PrefWindow & PrefUI // Maintenance.
This commit is contained in:
parent
25cf9bfbf8
commit
d758ce5cd1
|
@ -209,16 +209,20 @@ extension SessionCtl {
|
||||||
|
|
||||||
public extension SessionCtl {
|
public extension SessionCtl {
|
||||||
@objc override func showPreferences(_: Any? = nil) {
|
@objc override func showPreferences(_: Any? = nil) {
|
||||||
if #unavailable(macOS 10.15) {
|
osCheck: if #available(macOS 10.15, *) {
|
||||||
CtlPrefWindow.show()
|
switch NSEvent.modifierFlags {
|
||||||
} else if NSEvent.modifierFlags.contains(.option) {
|
case .option: break osCheck
|
||||||
CtlPrefWindow.show()
|
// case .shift:
|
||||||
} else {
|
// CtlPrefUIShared.shared.controller.show(preferencePane: PrefUITabs.tabGeneral.ssPaneIdentifier)
|
||||||
CtlPrefUI.shared.controller.show(preferencePane: SSPreferences.PaneIdentifier(rawValue: "General"))
|
// CtlPrefUIShared.shared.controller.window?.level = .statusBar
|
||||||
CtlPrefUI.shared.controller.window?.level = .statusBar
|
// CtlPrefUIShared.shared.controller.window?.setPosition(vertical: .top, horizontal: .right, padding: 20)
|
||||||
CtlPrefUI.shared.controller.window?.setPosition(vertical: .top, horizontal: .right, padding: 20)
|
default: CtlPrefUI.show()
|
||||||
}
|
}
|
||||||
NSApp.activate(ignoringOtherApps: true)
|
NSApp.activate(ignoringOtherApps: true)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
CtlPrefWindow.show()
|
||||||
|
NSApp.activate(ignoringOtherApps: true)
|
||||||
}
|
}
|
||||||
|
|
||||||
@objc func showCheatSheet(_: Any? = nil) {
|
@objc func showCheatSheet(_: Any? = nil) {
|
||||||
|
|
|
@ -6,21 +6,31 @@
|
||||||
// marks, or product names of Contributor, except as required to fulfill notice
|
// marks, or product names of Contributor, except as required to fulfill notice
|
||||||
// requirements defined in MIT License.
|
// requirements defined in MIT License.
|
||||||
|
|
||||||
import SSPreferences
|
import BookmarkManager
|
||||||
import SwiftExtension
|
import IMKUtils
|
||||||
|
import Shared
|
||||||
import SwiftUI
|
import SwiftUI
|
||||||
|
|
||||||
@available(macOS 10.15, *)
|
private let kWindowTitleHeight: Double = 78
|
||||||
extension PrefUITabs {
|
|
||||||
var ssPaneIdentifier: SSPreferences.PaneIdentifier { .init(rawValue: rawValue) }
|
// InputMethodServerPreferencesWindowControllerClass 非必需。
|
||||||
}
|
|
||||||
|
|
||||||
@available(macOS 10.15, *)
|
@available(macOS 10.15, *)
|
||||||
struct VwrPrefPage: View {
|
class CtlPrefUI: NSWindowController, NSWindowDelegate {
|
||||||
@State var tabType: PrefUITabs
|
static var vwrGeneral: NSView = generateView(tab: .tabGeneral)
|
||||||
|
static var vwrCandidates: NSView = generateView(tab: .tabCandidates)
|
||||||
|
static var vwrBehavior: NSView = generateView(tab: .tabBehavior)
|
||||||
|
static var vwrOutput: NSView = generateView(tab: .tabOutput)
|
||||||
|
static var vwrDictionary: NSView = generateView(tab: .tabDictionary)
|
||||||
|
static var vwrPhrases: NSView = generateView(tab: .tabPhrases)
|
||||||
|
static var vwrCassette: NSView = generateView(tab: .tabCassette)
|
||||||
|
static var vwrKeyboard: NSView = generateView(tab: .tabKeyboard)
|
||||||
|
static var vwrDevZone: NSView = generateView(tab: .tabDevZone)
|
||||||
|
|
||||||
|
static func generateView(tab: PrefUITabs) -> NSView {
|
||||||
var body: some View {
|
var body: some View {
|
||||||
Group {
|
Group {
|
||||||
switch tabType {
|
switch tab {
|
||||||
case .tabGeneral: VwrPrefPaneGeneral()
|
case .tabGeneral: VwrPrefPaneGeneral()
|
||||||
case .tabCandidates: VwrPrefPaneCandidates()
|
case .tabCandidates: VwrPrefPaneCandidates()
|
||||||
case .tabBehavior: VwrPrefPaneBehavior()
|
case .tabBehavior: VwrPrefPaneBehavior()
|
||||||
|
@ -29,63 +39,125 @@ struct VwrPrefPage: View {
|
||||||
case .tabPhrases: VwrPrefPanePhrases()
|
case .tabPhrases: VwrPrefPanePhrases()
|
||||||
case .tabCassette: VwrPrefPaneCassette()
|
case .tabCassette: VwrPrefPaneCassette()
|
||||||
case .tabKeyboard: VwrPrefPaneKeyboard()
|
case .tabKeyboard: VwrPrefPaneKeyboard()
|
||||||
case .tabDevZone, .tabExperience: VwrPrefPaneDevZone()
|
case .tabDevZone: VwrPrefPaneDevZone()
|
||||||
}
|
}
|
||||||
}.fixedSize()
|
}.fixedSize()
|
||||||
}
|
}
|
||||||
|
return NSHostingView(rootView: body.edgesIgnoringSafeArea(.top))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static var shared: CtlPrefUI?
|
||||||
|
|
||||||
|
static func show() {
|
||||||
|
if shared == nil {
|
||||||
|
let newWindow = NSWindow(
|
||||||
|
contentRect: CGRect(x: 401, y: 295, width: 577, height: 568),
|
||||||
|
styleMask: [.titled, .closable, .miniaturizable],
|
||||||
|
backing: .buffered, defer: true
|
||||||
|
)
|
||||||
|
let newInstance = CtlPrefUI(window: newWindow)
|
||||||
|
shared = newInstance
|
||||||
|
}
|
||||||
|
guard let shared = shared, let sharedWindow = shared.window else { return }
|
||||||
|
sharedWindow.delegate = shared
|
||||||
|
if !sharedWindow.isVisible {
|
||||||
|
shared.windowDidLoad()
|
||||||
|
}
|
||||||
|
sharedWindow.setPosition(vertical: .top, horizontal: .right, padding: 20)
|
||||||
|
sharedWindow.orderFrontRegardless() // 逼著視窗往最前方顯示
|
||||||
|
sharedWindow.level = .statusBar
|
||||||
|
shared.showWindow(shared)
|
||||||
|
NSApp.activate(ignoringOtherApps: true)
|
||||||
|
}
|
||||||
|
|
||||||
|
private var currentLanguageSelectItem: NSMenuItem?
|
||||||
|
|
||||||
|
override func windowDidLoad() {
|
||||||
|
super.windowDidLoad()
|
||||||
|
window?.setPosition(vertical: .top, horizontal: .right, padding: 20)
|
||||||
|
|
||||||
|
var preferencesTitleName = NSLocalizedString("vChewing Preferences…", comment: "")
|
||||||
|
preferencesTitleName.removeLast()
|
||||||
|
|
||||||
|
let toolbar = NSToolbar(identifier: "preference toolbar")
|
||||||
|
toolbar.allowsUserCustomization = false
|
||||||
|
toolbar.autosavesConfiguration = false
|
||||||
|
toolbar.sizeMode = .default
|
||||||
|
toolbar.delegate = self
|
||||||
|
toolbar.selectedItemIdentifier = PrefUITabs.tabGeneral.toolbarIdentifier
|
||||||
|
toolbar.showsBaselineSeparator = true
|
||||||
|
if #available(macOS 11.0, *) {
|
||||||
|
window?.toolbarStyle = .preference
|
||||||
|
}
|
||||||
|
window?.toolbar = toolbar
|
||||||
|
window?.title = preferencesTitleName
|
||||||
|
window?.titlebarAppearsTransparent = false
|
||||||
|
use(view: Self.vwrGeneral, animate: false)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// MARK: - NSToolbarDelegate Methods
|
||||||
|
|
||||||
@available(macOS 10.15, *)
|
@available(macOS 10.15, *)
|
||||||
class CtlPrefUI {
|
extension CtlPrefUI: NSToolbarDelegate {
|
||||||
var controller = PreferencesWindowController(
|
func use(view newView: NSView, animate: Bool = true) {
|
||||||
panes: {
|
// 強制重置語彙編輯器畫面。
|
||||||
var result = [PreferencePaneConvertible]()
|
if window?.contentView == Self.vwrPhrases || newView == Self.vwrPhrases {
|
||||||
PrefUITabs.allCases.forEach { neta in
|
Self.vwrPhrases = Self.generateView(tab: .tabPhrases)
|
||||||
if [.tabExperience].contains(neta) { return }
|
|
||||||
let item: PreferencePaneConvertible = SSPreferences.Pane(
|
|
||||||
identifier: SSPreferences.PaneIdentifier(rawValue: neta.rawValue),
|
|
||||||
title: neta.i18nTitle, toolbarIcon: neta.icon,
|
|
||||||
contentView: { VwrPrefPage(tabType: neta) }
|
|
||||||
)
|
|
||||||
result.append(item)
|
|
||||||
}
|
}
|
||||||
return result
|
guard let window = window, let existingContentView = window.contentView else { return }
|
||||||
}(),
|
let temporaryViewOld = NSView(frame: existingContentView.frame)
|
||||||
style: .toolbarItems
|
window.contentView = temporaryViewOld
|
||||||
)
|
var newWindowRect = NSRect(origin: window.frame.origin, size: newView.fittingSize)
|
||||||
|
newWindowRect.size.height += kWindowTitleHeight
|
||||||
static let shared = CtlPrefUI()
|
newWindowRect.origin.y = window.frame.maxY - newWindowRect.height
|
||||||
static let sentenceSeparator: String = {
|
window.setFrame(newWindowRect, display: true, animate: animate)
|
||||||
switch PrefMgr.shared.appleLanguages[0] {
|
window.contentView = newView
|
||||||
case "ja":
|
|
||||||
return ""
|
|
||||||
default:
|
|
||||||
if PrefMgr.shared.appleLanguages[0].contains("zh-Han") {
|
|
||||||
return ""
|
|
||||||
} else {
|
|
||||||
return " "
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}()
|
|
||||||
|
|
||||||
static let contentMaxHeight: Double = 490
|
|
||||||
static let contentWidth: Double = {
|
|
||||||
switch PrefMgr.shared.appleLanguages[0] {
|
|
||||||
case "ja":
|
|
||||||
return 520
|
|
||||||
default:
|
|
||||||
if PrefMgr.shared.appleLanguages[0].contains("zh-Han") {
|
|
||||||
return 500
|
|
||||||
} else {
|
|
||||||
return 580
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@available(macOS 10.15, *)
|
var toolbarIdentifiers: [NSToolbarItem.Identifier] {
|
||||||
public extension View {
|
PrefUITabs.allCases.map(\.toolbarIdentifier)
|
||||||
func prefDescriptionWidthLimited() -> some View {
|
}
|
||||||
frame(maxWidth: CtlPrefUI.contentWidth * 0.8, alignment: .leading)
|
|
||||||
|
func toolbarDefaultItemIdentifiers(_: NSToolbar) -> [NSToolbarItem.Identifier] {
|
||||||
|
toolbarIdentifiers
|
||||||
|
}
|
||||||
|
|
||||||
|
func toolbarAllowedItemIdentifiers(_: NSToolbar) -> [NSToolbarItem.Identifier] {
|
||||||
|
toolbarIdentifiers
|
||||||
|
}
|
||||||
|
|
||||||
|
func toolbarSelectableItemIdentifiers(_: NSToolbar) -> [NSToolbarItem.Identifier] {
|
||||||
|
toolbarIdentifiers
|
||||||
|
}
|
||||||
|
|
||||||
|
@objc func updateTab(_ target: NSToolbarItem) {
|
||||||
|
guard let tab = PrefUITabs.fromInt(target.tag) else { return }
|
||||||
|
switch tab {
|
||||||
|
case .tabGeneral: use(view: Self.vwrGeneral)
|
||||||
|
case .tabCandidates: use(view: Self.vwrCandidates)
|
||||||
|
case .tabBehavior: use(view: Self.vwrBehavior)
|
||||||
|
case .tabOutput: use(view: Self.vwrOutput)
|
||||||
|
case .tabDictionary: use(view: Self.vwrDictionary)
|
||||||
|
case .tabPhrases: use(view: Self.vwrPhrases)
|
||||||
|
case .tabCassette: use(view: Self.vwrCassette)
|
||||||
|
case .tabKeyboard: use(view: Self.vwrKeyboard)
|
||||||
|
case .tabDevZone: use(view: Self.vwrDevZone)
|
||||||
|
}
|
||||||
|
window?.toolbar?.selectedItemIdentifier = tab.toolbarIdentifier
|
||||||
|
}
|
||||||
|
|
||||||
|
func toolbar(
|
||||||
|
_: NSToolbar, itemForItemIdentifier itemIdentifier: NSToolbarItem.Identifier,
|
||||||
|
willBeInsertedIntoToolbar _: Bool
|
||||||
|
) -> NSToolbarItem? {
|
||||||
|
guard let tab = PrefUITabs(rawValue: itemIdentifier.rawValue) else { return nil }
|
||||||
|
let item = NSToolbarItem(itemIdentifier: itemIdentifier)
|
||||||
|
item.target = self
|
||||||
|
item.image = tab.icon
|
||||||
|
item.label = tab.i18nTitle
|
||||||
|
item.tag = tab.cocoaTag
|
||||||
|
item.action = #selector(updateTab(_:))
|
||||||
|
return item
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,87 @@
|
||||||
|
// (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.
|
||||||
|
|
||||||
|
import SSPreferences
|
||||||
|
import SwiftExtension
|
||||||
|
import SwiftUI
|
||||||
|
|
||||||
|
@available(macOS 10.15, *)
|
||||||
|
extension PrefUITabs {
|
||||||
|
var ssPaneIdentifier: SSPreferences.PaneIdentifier { .init(rawValue: rawValue) }
|
||||||
|
}
|
||||||
|
|
||||||
|
@available(macOS 10.15, *)
|
||||||
|
struct VwrPrefPage: View {
|
||||||
|
@State var tabType: PrefUITabs
|
||||||
|
var body: some View {
|
||||||
|
Group {
|
||||||
|
switch tabType {
|
||||||
|
case .tabGeneral: VwrPrefPaneGeneral()
|
||||||
|
case .tabCandidates: VwrPrefPaneCandidates()
|
||||||
|
case .tabBehavior: VwrPrefPaneBehavior()
|
||||||
|
case .tabOutput: VwrPrefPaneOutput()
|
||||||
|
case .tabDictionary: VwrPrefPaneDictionary()
|
||||||
|
case .tabPhrases: VwrPrefPanePhrases()
|
||||||
|
case .tabCassette: VwrPrefPaneCassette()
|
||||||
|
case .tabKeyboard: VwrPrefPaneKeyboard()
|
||||||
|
case .tabDevZone: VwrPrefPaneDevZone()
|
||||||
|
}
|
||||||
|
}.fixedSize()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@available(macOS 10.15, *)
|
||||||
|
class CtlPrefUIShared {
|
||||||
|
var controller = PreferencesWindowController(
|
||||||
|
panes: {
|
||||||
|
var result = [PreferencePaneConvertible]()
|
||||||
|
PrefUITabs.allCases.forEach { neta in
|
||||||
|
let item: PreferencePaneConvertible = SSPreferences.Pane(
|
||||||
|
identifier: SSPreferences.PaneIdentifier(rawValue: neta.rawValue),
|
||||||
|
title: neta.i18nTitle, toolbarIcon: neta.icon,
|
||||||
|
contentView: { VwrPrefPage(tabType: neta) }
|
||||||
|
)
|
||||||
|
result.append(item)
|
||||||
|
}
|
||||||
|
return result
|
||||||
|
}(),
|
||||||
|
style: .toolbarItems
|
||||||
|
)
|
||||||
|
|
||||||
|
static var sharedWindow: NSWindow? {
|
||||||
|
CtlPrefUI.shared?.window ?? CtlPrefUIShared.shared.controller.window
|
||||||
|
}
|
||||||
|
|
||||||
|
static let shared = CtlPrefUIShared()
|
||||||
|
static let sentenceSeparator: String = {
|
||||||
|
switch PrefMgr.shared.appleLanguages[0] {
|
||||||
|
case "ja":
|
||||||
|
return ""
|
||||||
|
default:
|
||||||
|
if PrefMgr.shared.appleLanguages[0].contains("zh-Han") {
|
||||||
|
return ""
|
||||||
|
} else {
|
||||||
|
return " "
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
|
||||||
|
static let contentMaxHeight: Double = 490
|
||||||
|
static let contentWidth: Double = {
|
||||||
|
switch PrefMgr.shared.appleLanguages[0] {
|
||||||
|
case "ja":
|
||||||
|
return 520
|
||||||
|
default:
|
||||||
|
if PrefMgr.shared.appleLanguages[0].contains("zh-Han") {
|
||||||
|
return 500
|
||||||
|
} else {
|
||||||
|
return 580
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
}
|
|
@ -50,7 +50,7 @@ struct VwrPrefPaneBehavior: View {
|
||||||
|
|
||||||
var body: some View {
|
var body: some View {
|
||||||
ScrollView {
|
ScrollView {
|
||||||
SSPreferences.Container(contentWidth: CtlPrefUI.contentWidth) {
|
SSPreferences.Container(contentWidth: CtlPrefUIShared.contentWidth) {
|
||||||
SSPreferences.Section(title: "Space:".localized, bottomDivider: true) {
|
SSPreferences.Section(title: "Space:".localized, bottomDivider: true) {
|
||||||
Toggle(
|
Toggle(
|
||||||
LocalizedStringKey("Enable Space key for calling candidate window"),
|
LocalizedStringKey("Enable Space key for calling candidate window"),
|
||||||
|
@ -63,7 +63,7 @@ struct VwrPrefPaneBehavior: View {
|
||||||
"If disabled, this will insert space instead."
|
"If disabled, this will insert space instead."
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
.preferenceDescription().prefDescriptionWidthLimited()
|
.preferenceDescription()
|
||||||
}
|
}
|
||||||
SSPreferences.Section(title: "ESC:".localized, bottomDivider: true) {
|
SSPreferences.Section(title: "ESC:".localized, bottomDivider: true) {
|
||||||
Toggle(
|
Toggle(
|
||||||
|
@ -77,7 +77,7 @@ struct VwrPrefPaneBehavior: View {
|
||||||
"If unchecked, the ESC key will try cleaning the unfinished readings / strokes first, and will commit the current composition buffer if there's no unfinished readings / strkes."
|
"If unchecked, the ESC key will try cleaning the unfinished readings / strokes first, and will commit the current composition buffer if there's no unfinished readings / strkes."
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
.preferenceDescription().prefDescriptionWidthLimited()
|
.preferenceDescription()
|
||||||
}
|
}
|
||||||
SSPreferences.Section(title: "Enter:".localized, bottomDivider: true) {
|
SSPreferences.Section(title: "Enter:".localized, bottomDivider: true) {
|
||||||
Toggle(
|
Toggle(
|
||||||
|
@ -91,7 +91,7 @@ struct VwrPrefPaneBehavior: View {
|
||||||
"Otherwise, only the candidate keys are allowed to confirm associates."
|
"Otherwise, only the candidate keys are allowed to confirm associates."
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
.preferenceDescription().prefDescriptionWidthLimited()
|
.preferenceDescription()
|
||||||
}
|
}
|
||||||
SSPreferences.Section(title: "Shift+BackSpace:".localized, bottomDivider: true) {
|
SSPreferences.Section(title: "Shift+BackSpace:".localized, bottomDivider: true) {
|
||||||
Picker(
|
Picker(
|
||||||
|
@ -107,7 +107,7 @@ struct VwrPrefPaneBehavior: View {
|
||||||
.labelsHidden()
|
.labelsHidden()
|
||||||
.pickerStyle(RadioGroupPickerStyle())
|
.pickerStyle(RadioGroupPickerStyle())
|
||||||
Text(LocalizedStringKey("Disassembling process does not work with non-phonetic reading keys."))
|
Text(LocalizedStringKey("Disassembling process does not work with non-phonetic reading keys."))
|
||||||
.preferenceDescription().prefDescriptionWidthLimited()
|
.preferenceDescription()
|
||||||
}
|
}
|
||||||
SSPreferences.Section(title: "(Shift+)Tab:", bottomDivider: true) {
|
SSPreferences.Section(title: "(Shift+)Tab:", bottomDivider: true) {
|
||||||
Picker(
|
Picker(
|
||||||
|
@ -123,7 +123,7 @@ struct VwrPrefPaneBehavior: View {
|
||||||
.horizontalRadioGroupLayout()
|
.horizontalRadioGroupLayout()
|
||||||
.pickerStyle(RadioGroupPickerStyle())
|
.pickerStyle(RadioGroupPickerStyle())
|
||||||
Text(LocalizedStringKey("Choose the behavior of (Shift+)Tab key in the candidate window."))
|
Text(LocalizedStringKey("Choose the behavior of (Shift+)Tab key in the candidate window."))
|
||||||
.preferenceDescription().prefDescriptionWidthLimited()
|
.preferenceDescription()
|
||||||
}
|
}
|
||||||
SSPreferences.Section(title: "(Shift+)Space:".localized, bottomDivider: true) {
|
SSPreferences.Section(title: "(Shift+)Space:".localized, bottomDivider: true) {
|
||||||
Picker(
|
Picker(
|
||||||
|
@ -138,7 +138,7 @@ struct VwrPrefPaneBehavior: View {
|
||||||
.labelsHidden()
|
.labelsHidden()
|
||||||
.pickerStyle(RadioGroupPickerStyle())
|
.pickerStyle(RadioGroupPickerStyle())
|
||||||
Text(LocalizedStringKey("Choose the behavior of (Shift+)Space key with candidates."))
|
Text(LocalizedStringKey("Choose the behavior of (Shift+)Space key with candidates."))
|
||||||
.preferenceDescription().prefDescriptionWidthLimited()
|
.preferenceDescription()
|
||||||
}
|
}
|
||||||
SSPreferences.Section(title: "Shift+Letter:".localized, bottomDivider: true) {
|
SSPreferences.Section(title: "Shift+Letter:".localized, bottomDivider: true) {
|
||||||
Picker(
|
Picker(
|
||||||
|
@ -154,7 +154,7 @@ struct VwrPrefPaneBehavior: View {
|
||||||
.labelsHidden()
|
.labelsHidden()
|
||||||
.pickerStyle(RadioGroupPickerStyle())
|
.pickerStyle(RadioGroupPickerStyle())
|
||||||
Text(LocalizedStringKey("Choose the behavior of Shift+Letter key with letter inputs."))
|
Text(LocalizedStringKey("Choose the behavior of Shift+Letter key with letter inputs."))
|
||||||
.preferenceDescription().prefDescriptionWidthLimited()
|
.preferenceDescription()
|
||||||
}
|
}
|
||||||
SSPreferences.Section(title: "Intonation Key:".localized, bottomDivider: true) {
|
SSPreferences.Section(title: "Intonation Key:".localized, bottomDivider: true) {
|
||||||
Picker(
|
Picker(
|
||||||
|
@ -170,7 +170,7 @@ struct VwrPrefPaneBehavior: View {
|
||||||
.labelsHidden()
|
.labelsHidden()
|
||||||
.pickerStyle(RadioGroupPickerStyle())
|
.pickerStyle(RadioGroupPickerStyle())
|
||||||
Text(LocalizedStringKey("Specify the behavior of intonation key when syllable composer is empty."))
|
Text(LocalizedStringKey("Specify the behavior of intonation key when syllable composer is empty."))
|
||||||
.preferenceDescription().prefDescriptionWidthLimited()
|
.preferenceDescription()
|
||||||
}
|
}
|
||||||
SSPreferences.Section(title: "Shift:", bottomDivider: true) {
|
SSPreferences.Section(title: "Shift:", bottomDivider: true) {
|
||||||
Toggle(
|
Toggle(
|
||||||
|
@ -194,9 +194,9 @@ struct VwrPrefPaneBehavior: View {
|
||||||
!PrefMgr.shared.togglingAlphanumericalModeWithRShift && !PrefMgr.shared.togglingAlphanumericalModeWithLShift
|
!PrefMgr.shared.togglingAlphanumericalModeWithRShift && !PrefMgr.shared.togglingAlphanumericalModeWithLShift
|
||||||
)
|
)
|
||||||
Text(
|
Text(
|
||||||
"This feature requires macOS 10.15 and above.".localized + CtlPrefUI.sentenceSeparator
|
"This feature requires macOS 10.15 and above.".localized + CtlPrefUIShared.sentenceSeparator
|
||||||
+ "It only needs to parse consecutive NSEvents passed by macOS built-in InputMethodKit framework, hence no necessity of asking end-users for extra privileges of monitoring global keyboard inputs. You are free to investigate our codebase or reverse-engineer this input method to see whether the above statement is trustable.".localized
|
+ "It only needs to parse consecutive NSEvents passed by macOS built-in InputMethodKit framework, hence no necessity of asking end-users for extra privileges of monitoring global keyboard inputs. You are free to investigate our codebase or reverse-engineer this input method to see whether the above statement is trustable.".localized
|
||||||
).preferenceDescription().prefDescriptionWidthLimited()
|
).preferenceDescription()
|
||||||
}
|
}
|
||||||
SSPreferences.Section(title: "Caps Lock:", bottomDivider: true) {
|
SSPreferences.Section(title: "Caps Lock:", bottomDivider: true) {
|
||||||
Toggle(
|
Toggle(
|
||||||
|
@ -207,7 +207,7 @@ struct VwrPrefPaneBehavior: View {
|
||||||
).disabled(!macOSMontereyOrLaterDetected)
|
).disabled(!macOSMontereyOrLaterDetected)
|
||||||
Text(
|
Text(
|
||||||
"This feature requires macOS 10.15 and above.".localized
|
"This feature requires macOS 10.15 and above.".localized
|
||||||
).preferenceDescription().prefDescriptionWidthLimited()
|
).preferenceDescription()
|
||||||
}
|
}
|
||||||
SSPreferences.Section(title: "Misc Settings:".localized) {
|
SSPreferences.Section(title: "Misc Settings:".localized) {
|
||||||
Toggle(
|
Toggle(
|
||||||
|
@ -220,11 +220,11 @@ struct VwrPrefPaneBehavior: View {
|
||||||
LocalizedStringKey(
|
LocalizedStringKey(
|
||||||
"Key names in tooltip will be shown as symbols when the tooltip is vertical. However, this option will be ignored since tooltip will always be horizontal if the UI language is English."
|
"Key names in tooltip will be shown as symbols when the tooltip is vertical. However, this option will be ignored since tooltip will always be horizontal if the UI language is English."
|
||||||
)
|
)
|
||||||
).preferenceDescription().prefDescriptionWidthLimited()
|
).preferenceDescription()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.frame(maxHeight: CtlPrefUI.contentMaxHeight).fixedSize(horizontal: false, vertical: true)
|
.frame(maxHeight: CtlPrefUIShared.contentMaxHeight).fixedSize(horizontal: false, vertical: true)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -48,7 +48,7 @@ struct VwrPrefPaneCandidates: View {
|
||||||
|
|
||||||
var body: some View {
|
var body: some View {
|
||||||
ScrollView {
|
ScrollView {
|
||||||
SSPreferences.Container(contentWidth: CtlPrefUI.contentWidth) {
|
SSPreferences.Container(contentWidth: CtlPrefUIShared.contentWidth) {
|
||||||
SSPreferences.Section(title: "Selection Keys:".localized, bottomDivider: true) {
|
SSPreferences.Section(title: "Selection Keys:".localized, bottomDivider: true) {
|
||||||
VwrPrefPaneCandidates_SelectionKeys()
|
VwrPrefPaneCandidates_SelectionKeys()
|
||||||
}
|
}
|
||||||
|
@ -66,7 +66,7 @@ struct VwrPrefPaneCandidates: View {
|
||||||
.horizontalRadioGroupLayout()
|
.horizontalRadioGroupLayout()
|
||||||
.pickerStyle(RadioGroupPickerStyle())
|
.pickerStyle(RadioGroupPickerStyle())
|
||||||
Text(LocalizedStringKey("Choose your preferred layout of the candidate window."))
|
Text(LocalizedStringKey("Choose your preferred layout of the candidate window."))
|
||||||
.preferenceDescription().prefDescriptionWidthLimited()
|
.preferenceDescription()
|
||||||
Toggle(
|
Toggle(
|
||||||
LocalizedStringKey("Use only one row / column in candidate window."),
|
LocalizedStringKey("Use only one row / column in candidate window."),
|
||||||
isOn: $selCandidateWindowShowOnlyOneLine.onChange {
|
isOn: $selCandidateWindowShowOnlyOneLine.onChange {
|
||||||
|
@ -78,10 +78,10 @@ struct VwrPrefPaneCandidates: View {
|
||||||
.disabled(PrefMgr.shared.useIMKCandidateWindow)
|
.disabled(PrefMgr.shared.useIMKCandidateWindow)
|
||||||
Text(
|
Text(
|
||||||
"This only works with Tadokoro candidate window.".localized
|
"This only works with Tadokoro candidate window.".localized
|
||||||
+ CtlPrefUI.sentenceSeparator
|
+ CtlPrefUIShared.sentenceSeparator
|
||||||
+ "Tadokoro candidate window shows 4 rows / columns by default, providing similar experiences from Microsoft New Phonetic IME and macOS bult-in Chinese IME (since macOS 10.9). However, for some users who have presbyopia, they prefer giant candidate font sizes, resulting a concern that multiple rows / columns of candidates can make the candidate window looks too big, hence this option. Note that this option will be dismissed if the typing context is vertical, forcing the candidates to be shown in only one row / column. Only one reverse-lookup result can be made available in single row / column mode due to reduced candidate window size.".localized
|
+ "Tadokoro candidate window shows 4 rows / columns by default, providing similar experiences from Microsoft New Phonetic IME and macOS bult-in Chinese IME (since macOS 10.9). However, for some users who have presbyopia, they prefer giant candidate font sizes, resulting a concern that multiple rows / columns of candidates can make the candidate window looks too big, hence this option. Note that this option will be dismissed if the typing context is vertical, forcing the candidates to be shown in only one row / column. Only one reverse-lookup result can be made available in single row / column mode due to reduced candidate window size.".localized
|
||||||
)
|
)
|
||||||
.preferenceDescription().prefDescriptionWidthLimited()
|
.preferenceDescription()
|
||||||
}
|
}
|
||||||
SSPreferences.Section(title: "Candidate Size:".localized, bottomDivider: true) {
|
SSPreferences.Section(title: "Candidate Size:".localized, bottomDivider: true) {
|
||||||
Picker(
|
Picker(
|
||||||
|
@ -109,7 +109,7 @@ struct VwrPrefPaneCandidates: View {
|
||||||
.labelsHidden()
|
.labelsHidden()
|
||||||
.frame(width: 120.0)
|
.frame(width: 120.0)
|
||||||
Text(LocalizedStringKey("Choose candidate font size for better visual clarity."))
|
Text(LocalizedStringKey("Choose candidate font size for better visual clarity."))
|
||||||
.preferenceDescription().prefDescriptionWidthLimited()
|
.preferenceDescription()
|
||||||
}
|
}
|
||||||
SSPreferences.Section(title: "Cursor Selection:".localized, bottomDivider: true) {
|
SSPreferences.Section(title: "Cursor Selection:".localized, bottomDivider: true) {
|
||||||
Picker(
|
Picker(
|
||||||
|
@ -142,10 +142,10 @@ struct VwrPrefPaneCandidates: View {
|
||||||
.disabled(PrefMgr.shared.useIMKCandidateWindow)
|
.disabled(PrefMgr.shared.useIMKCandidateWindow)
|
||||||
Text(
|
Text(
|
||||||
"This only works with Tadokoro candidate window.".localized
|
"This only works with Tadokoro candidate window.".localized
|
||||||
+ CtlPrefUI.sentenceSeparator
|
+ CtlPrefUIShared.sentenceSeparator
|
||||||
+ "The lookup results are supplied by the CIN cassette module.".localized
|
+ "The lookup results are supplied by the CIN cassette module.".localized
|
||||||
)
|
)
|
||||||
.preferenceDescription().prefDescriptionWidthLimited()
|
.preferenceDescription()
|
||||||
Toggle(
|
Toggle(
|
||||||
LocalizedStringKey("Always use fixed listing order in candidate window"),
|
LocalizedStringKey("Always use fixed listing order in candidate window"),
|
||||||
isOn: $selUseFixecCandidateOrderOnSelection.onChange {
|
isOn: $selUseFixecCandidateOrderOnSelection.onChange {
|
||||||
|
@ -157,7 +157,7 @@ struct VwrPrefPaneCandidates: View {
|
||||||
"This will stop user override model from affecting how candidates get sorted."
|
"This will stop user override model from affecting how candidates get sorted."
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
.preferenceDescription().prefDescriptionWidthLimited()
|
.preferenceDescription()
|
||||||
Toggle(
|
Toggle(
|
||||||
LocalizedStringKey("Consolidate the context on confirming candidate selection"),
|
LocalizedStringKey("Consolidate the context on confirming candidate selection"),
|
||||||
isOn: $selConsolidateContextOnCandidateSelection.onChange {
|
isOn: $selConsolidateContextOnCandidateSelection.onChange {
|
||||||
|
@ -165,11 +165,9 @@ struct VwrPrefPaneCandidates: View {
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
Text(
|
Text(
|
||||||
LocalizedStringKey(
|
"For example: When typing “章太炎” and you want to override the “太” with “泰”, and the raw operation index range [1,2) which bounds are cutting the current node “章太炎” in range [0,3). If having lack of the pre-consolidation process, this word will become something like “張泰言” after the candidate selection. Only if we enable this consolidation, this word will become “章泰炎” which is the expected result that the context is kept as-is.".localized
|
||||||
"For example: When typing “章太炎” and you want to override the “太” with “泰”, and the raw operation index range [1,2) which bounds are cutting the current node “章太炎” in range [0,3). If having lack of the pre-consolidation process, this word will become something like “張泰言” after the candidate selection. Only if we enable this consolidation, this word will become “章泰炎” which is the expected result that the context is kept as-is."
|
|
||||||
)
|
)
|
||||||
)
|
.preferenceDescription()
|
||||||
.preferenceDescription().prefDescriptionWidthLimited()
|
|
||||||
}
|
}
|
||||||
SSPreferences.Section(title: "Experimental:".localized) {
|
SSPreferences.Section(title: "Experimental:".localized) {
|
||||||
Toggle(
|
Toggle(
|
||||||
|
@ -183,13 +181,11 @@ struct VwrPrefPaneCandidates: View {
|
||||||
Text(
|
Text(
|
||||||
LocalizedStringKey("⚠︎ This will reboot the vChewing IME.")
|
LocalizedStringKey("⚠︎ This will reboot the vChewing IME.")
|
||||||
)
|
)
|
||||||
.preferenceDescription().prefDescriptionWidthLimited()
|
.preferenceDescription()
|
||||||
Text(
|
Text(
|
||||||
LocalizedStringKey(
|
"IMK candidate window relies on certain Apple private APIs which are force-exposed by using bridging headers. Its usability, at this moment, is only guaranteed from macOS 10.14 Mojave to macOS 13 Ventura. Further tests are required in the future in order to tell whether it is usable in newer macOS releases.".localized
|
||||||
"IMK candidate window relies on certain Apple private APIs which are force-exposed by using bridging headers. Its usability, at this moment, is only guaranteed from macOS 10.14 Mojave to macOS 13 Ventura. Further tests are required in the future in order to tell whether it is usable in newer macOS releases."
|
|
||||||
)
|
)
|
||||||
)
|
.preferenceDescription()
|
||||||
.preferenceDescription().prefDescriptionWidthLimited()
|
|
||||||
Toggle(
|
Toggle(
|
||||||
LocalizedStringKey("Enable mouse wheel support for Tadokoro Candidate Window"),
|
LocalizedStringKey("Enable mouse wheel support for Tadokoro Candidate Window"),
|
||||||
isOn: $selEnableMouseScrollingForTDKCandidatesCocoa.onChange {
|
isOn: $selEnableMouseScrollingForTDKCandidatesCocoa.onChange {
|
||||||
|
@ -209,11 +205,9 @@ struct VwrPrefPaneCandidates: View {
|
||||||
)
|
)
|
||||||
.disabled(PrefMgr.shared.useIMKCandidateWindow)
|
.disabled(PrefMgr.shared.useIMKCandidateWindow)
|
||||||
Text(
|
Text(
|
||||||
LocalizedStringKey(
|
"By checking this, Tadokoro Candidate Window will use SwiftUI. SwiftUI was being used in vChewing 3.3.8 and before. However, SwiftUI has unacceptable responsiveness & latency & efficiency problems in rendering the candidate panel UI. That's why a refactored version has been introduced since vChewing 3.3.9 using Cocoa, providing an optimized user experience with blasing-fast operation responsiveness, plus experimental mouse-wheel support.".localized
|
||||||
"By checking this, Tadokoro Candidate Window will use SwiftUI. SwiftUI was being used in vChewing 3.3.8 and before. However, SwiftUI has unacceptable responsiveness & latency & efficiency problems in rendering the candidate panel UI. That's why a refactored version has been introduced since vChewing 3.3.9 using Cocoa, providing an optimized user experience with blasing-fast operation responsiveness, plus experimental mouse-wheel support."
|
|
||||||
)
|
)
|
||||||
)
|
.preferenceDescription()
|
||||||
.preferenceDescription().prefDescriptionWidthLimited()
|
|
||||||
Toggle(
|
Toggle(
|
||||||
LocalizedStringKey("Allow boosting / excluding a candidate of single kanji"),
|
LocalizedStringKey("Allow boosting / excluding a candidate of single kanji"),
|
||||||
isOn: $selAllowBoostingSingleKanjiAsUserPhrase.onChange {
|
isOn: $selAllowBoostingSingleKanjiAsUserPhrase.onChange {
|
||||||
|
@ -225,11 +219,11 @@ struct VwrPrefPaneCandidates: View {
|
||||||
"⚠︎ This may hinder the walking algorithm from giving appropriate results."
|
"⚠︎ This may hinder the walking algorithm from giving appropriate results."
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
.preferenceDescription().prefDescriptionWidthLimited()
|
.preferenceDescription()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.frame(maxHeight: CtlPrefUI.contentMaxHeight)
|
.frame(maxHeight: CtlPrefUIShared.contentMaxHeight)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -261,7 +255,7 @@ private struct VwrPrefPaneCandidates_SelectionKeys: View {
|
||||||
// Start Error Handling.
|
// Start Error Handling.
|
||||||
if let errorResult = CandidateKey.validate(keys: keys) {
|
if let errorResult = CandidateKey.validate(keys: keys) {
|
||||||
IMEApp.buzz()
|
IMEApp.buzz()
|
||||||
if let window = CtlPrefUI.shared.controller.window {
|
if let window = CtlPrefUIShared.sharedWindow {
|
||||||
let alert = NSAlert(error: NSLocalizedString("Invalid Selection Keys.", comment: ""))
|
let alert = NSAlert(error: NSLocalizedString("Invalid Selection Keys.", comment: ""))
|
||||||
alert.informativeText = errorResult
|
alert.informativeText = errorResult
|
||||||
alert.beginSheetModal(for: window) { _ in
|
alert.beginSheetModal(for: window) { _ in
|
||||||
|
@ -283,14 +277,14 @@ private struct VwrPrefPaneCandidates_SelectionKeys: View {
|
||||||
"⚠︎ This feature in IMK Candidate Window defects. Please consult\nApple Developer Relations with Radar ID: #FB11300759."
|
"⚠︎ This feature in IMK Candidate Window defects. Please consult\nApple Developer Relations with Radar ID: #FB11300759."
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
.preferenceDescription().prefDescriptionWidthLimited()
|
.preferenceDescription()
|
||||||
} else {
|
} else {
|
||||||
Text(
|
Text(
|
||||||
"Choose or hit Enter to confim your prefered keys for selecting candidates.".localized
|
"Choose or hit Enter to confim your prefered keys for selecting candidates.".localized
|
||||||
+ "\n"
|
+ "\n"
|
||||||
+ "This will also affect the row / column capacity of the candidate window.".localized
|
+ "This will also affect the row / column capacity of the candidate window.".localized
|
||||||
)
|
)
|
||||||
.preferenceDescription().prefDescriptionWidthLimited()
|
.preferenceDescription()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -31,10 +31,10 @@ struct VwrPrefPaneCassette: View {
|
||||||
|
|
||||||
var body: some View {
|
var body: some View {
|
||||||
ScrollView {
|
ScrollView {
|
||||||
SSPreferences.Container(contentWidth: CtlPrefUI.contentWidth) {
|
SSPreferences.Container(contentWidth: CtlPrefUIShared.contentWidth) {
|
||||||
// MARK: - Cassette Data Path Management
|
// MARK: - Cassette Data Path Management
|
||||||
|
|
||||||
SSPreferences.Section(title: "", bottomDivider: true) {
|
SSPreferences.Section(bottomDivider: true) {
|
||||||
Text(LocalizedStringKey("Choose your desired cassette file path. Will be omitted if invalid."))
|
Text(LocalizedStringKey("Choose your desired cassette file path. Will be omitted if invalid."))
|
||||||
HStack {
|
HStack {
|
||||||
TextField(fdrCassetteDataDefault, text: $tbxCassettePath).disabled(true)
|
TextField(fdrCassetteDataDefault, text: $tbxCassettePath).disabled(true)
|
||||||
|
@ -54,7 +54,7 @@ struct VwrPrefPaneCassette: View {
|
||||||
let bolPreviousPathValidity = LMMgr.checkCassettePathValidity(
|
let bolPreviousPathValidity = LMMgr.checkCassettePathValidity(
|
||||||
PrefMgr.shared.cassettePath.expandingTildeInPath)
|
PrefMgr.shared.cassettePath.expandingTildeInPath)
|
||||||
|
|
||||||
if let window = CtlPrefUI.shared.controller.window {
|
if let window = CtlPrefUIShared.sharedWindow {
|
||||||
Self.dlgOpenFile.beginSheetModal(for: window) { result in
|
Self.dlgOpenFile.beginSheetModal(for: window) { result in
|
||||||
if result == NSApplication.ModalResponse.OK {
|
if result == NSApplication.ModalResponse.OK {
|
||||||
guard let url = Self.dlgOpenFile.url else { return }
|
guard let url = Self.dlgOpenFile.url else { return }
|
||||||
|
@ -92,7 +92,7 @@ struct VwrPrefPaneCassette: View {
|
||||||
LocalizedStringKey("Enable cassette mode, suppressing phonabet input"),
|
LocalizedStringKey("Enable cassette mode, suppressing phonabet input"),
|
||||||
isOn: $selCassetteEnabled.onChange {
|
isOn: $selCassetteEnabled.onChange {
|
||||||
if selCassetteEnabled, !LMMgr.checkCassettePathValidity(PrefMgr.shared.cassettePath) {
|
if selCassetteEnabled, !LMMgr.checkCassettePathValidity(PrefMgr.shared.cassettePath) {
|
||||||
if let window = CtlPrefUI.shared.controller.window {
|
if let window = CtlPrefUIShared.sharedWindow {
|
||||||
IMEApp.buzz()
|
IMEApp.buzz()
|
||||||
let alert = NSAlert(error: NSLocalizedString("Path invalid or file access error.", comment: ""))
|
let alert = NSAlert(error: NSLocalizedString("Path invalid or file access error.", comment: ""))
|
||||||
alert.informativeText = NSLocalizedString(
|
alert.informativeText = NSLocalizedString(
|
||||||
|
@ -115,12 +115,12 @@ struct VwrPrefPaneCassette: View {
|
||||||
"Cassette mode is similar to the CIN support of the Yahoo Kimo IME, allowing users to use their own CIN tables to implement their stroked-based input schema (e.g. Wubi, Cangjie, Boshiamy, etc.) as a plan-B in vChewing IME. However, since vChewing won't compromise its phonabet input mode experience for this cassette mode, users might not feel comfortable enough comparing to their experiences with RIME (recommended) or OpenVanilla (deprecated)."
|
"Cassette mode is similar to the CIN support of the Yahoo Kimo IME, allowing users to use their own CIN tables to implement their stroked-based input schema (e.g. Wubi, Cangjie, Boshiamy, etc.) as a plan-B in vChewing IME. However, since vChewing won't compromise its phonabet input mode experience for this cassette mode, users might not feel comfortable enough comparing to their experiences with RIME (recommended) or OpenVanilla (deprecated)."
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
.preferenceDescription().fixedSize(horizontal: false, vertical: true)
|
.preferenceDescription()
|
||||||
}
|
}
|
||||||
|
|
||||||
// MARK: - Something Else
|
// MARK: - Something Else
|
||||||
|
|
||||||
SSPreferences.Section(title: "") {
|
SSPreferences.Section {
|
||||||
Toggle(
|
Toggle(
|
||||||
LocalizedStringKey("Auto-composite when the longest possible key is formed"),
|
LocalizedStringKey("Auto-composite when the longest possible key is formed"),
|
||||||
isOn: $selAutoCompositeWithLongestPossibleCassetteKey.onChange {
|
isOn: $selAutoCompositeWithLongestPossibleCassetteKey.onChange {
|
||||||
|
@ -139,7 +139,7 @@ struct VwrPrefPaneCassette: View {
|
||||||
"All strokes in the composition buffer will be shown as ASCII keyboard characters unless this option is enabled. Stroke is definable in the “%keyname” section of the CIN file."
|
"All strokes in the composition buffer will be shown as ASCII keyboard characters unless this option is enabled. Stroke is definable in the “%keyname” section of the CIN file."
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
.preferenceDescription().fixedSize(horizontal: false, vertical: true)
|
.preferenceDescription()
|
||||||
Picker(
|
Picker(
|
||||||
"",
|
"",
|
||||||
selection: $selForceCassetteChineseConversion.onChange {
|
selection: $selForceCassetteChineseConversion.onChange {
|
||||||
|
@ -158,11 +158,11 @@ struct VwrPrefPaneCassette: View {
|
||||||
"This conversion only affects the cassette module, converting typed contents to either Simplified Chinese or Traditional Chinese in accordance with this setting and your current input mode."
|
"This conversion only affects the cassette module, converting typed contents to either Simplified Chinese or Traditional Chinese in accordance with this setting and your current input mode."
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
.preferenceDescription().fixedSize(horizontal: false, vertical: true)
|
.preferenceDescription()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.frame(maxHeight: CtlPrefUI.contentMaxHeight).fixedSize(horizontal: false, vertical: true)
|
.frame(maxHeight: CtlPrefUIShared.contentMaxHeight).fixedSize(horizontal: false, vertical: true)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -27,8 +27,8 @@ struct VwrPrefPaneDevZone: View {
|
||||||
|
|
||||||
var body: some View {
|
var body: some View {
|
||||||
ScrollView {
|
ScrollView {
|
||||||
SSPreferences.Container(contentWidth: CtlPrefUI.contentWidth) {
|
SSPreferences.Container(contentWidth: CtlPrefUIShared.contentWidth) {
|
||||||
SSPreferences.Section(title: "", bottomDivider: true) {
|
SSPreferences.Section(bottomDivider: true) {
|
||||||
Text(
|
Text(
|
||||||
LocalizedStringKey(
|
LocalizedStringKey(
|
||||||
"Warning: This page is for testing future features. \nFeatures listed here may not work as expected.")
|
"Warning: This page is for testing future features. \nFeatures listed here may not work as expected.")
|
||||||
|
@ -37,7 +37,7 @@ struct VwrPrefPaneDevZone: View {
|
||||||
Divider()
|
Divider()
|
||||||
HStack {
|
HStack {
|
||||||
Text("Some previous options are moved to other tabs.".localized)
|
Text("Some previous options are moved to other tabs.".localized)
|
||||||
.preferenceDescription().fixedSize(horizontal: false, vertical: true)
|
.preferenceDescription()
|
||||||
}
|
}
|
||||||
Toggle(
|
Toggle(
|
||||||
"Disable segmented thick underline in marking mode for managed clients".localized,
|
"Disable segmented thick underline in marking mode for managed clients".localized,
|
||||||
|
@ -48,11 +48,11 @@ struct VwrPrefPaneDevZone: View {
|
||||||
Text(
|
Text(
|
||||||
"Some clients with web-based front UI may have issues rendering segmented thick underlines drawn by their implemented “setMarkedText()”. This option stops the input method from delivering segmented thick underlines to “client().setMarkedText()”. Note that segmented thick underlines are only used in marking mode, unless the client itself misimplements the IMKTextInput method “setMarkedText()”. This option only affects the inline composition buffer.".localized
|
"Some clients with web-based front UI may have issues rendering segmented thick underlines drawn by their implemented “setMarkedText()”. This option stops the input method from delivering segmented thick underlines to “client().setMarkedText()”. Note that segmented thick underlines are only used in marking mode, unless the client itself misimplements the IMKTextInput method “setMarkedText()”. This option only affects the inline composition buffer.".localized
|
||||||
)
|
)
|
||||||
.preferenceDescription().fixedSize(horizontal: false, vertical: true)
|
.preferenceDescription()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.frame(maxHeight: CtlPrefUI.contentMaxHeight).fixedSize(horizontal: false, vertical: true)
|
.frame(maxHeight: CtlPrefUIShared.contentMaxHeight).fixedSize(horizontal: false, vertical: true)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -38,10 +38,10 @@ struct VwrPrefPaneDictionary: View {
|
||||||
|
|
||||||
var body: some View {
|
var body: some View {
|
||||||
ScrollView {
|
ScrollView {
|
||||||
SSPreferences.Container(contentWidth: CtlPrefUI.contentWidth) {
|
SSPreferences.Container(contentWidth: CtlPrefUIShared.contentWidth) {
|
||||||
// MARK: - User Data Folder Path Management
|
// MARK: - User Data Folder Path Management
|
||||||
|
|
||||||
SSPreferences.Section(title: "", bottomDivider: true) {
|
SSPreferences.Section(bottomDivider: true) {
|
||||||
Group {
|
Group {
|
||||||
Text(LocalizedStringKey("Choose your desired user data folder path. Will be omitted if invalid."))
|
Text(LocalizedStringKey("Choose your desired user data folder path. Will be omitted if invalid."))
|
||||||
HStack {
|
HStack {
|
||||||
|
@ -60,7 +60,7 @@ struct VwrPrefPaneDictionary: View {
|
||||||
let bolPreviousFolderValidity = LMMgr.checkIfSpecifiedUserDataFolderValid(
|
let bolPreviousFolderValidity = LMMgr.checkIfSpecifiedUserDataFolderValid(
|
||||||
PrefMgr.shared.userDataFolderSpecified.expandingTildeInPath)
|
PrefMgr.shared.userDataFolderSpecified.expandingTildeInPath)
|
||||||
|
|
||||||
if let window = CtlPrefUI.shared.controller.window {
|
if let window = CtlPrefUIShared.sharedWindow {
|
||||||
Self.dlgOpenPath.beginSheetModal(for: window) { result in
|
Self.dlgOpenPath.beginSheetModal(for: window) { result in
|
||||||
if result == NSApplication.ModalResponse.OK {
|
if result == NSApplication.ModalResponse.OK {
|
||||||
guard let url = Self.dlgOpenPath.url else { return }
|
guard let url = Self.dlgOpenPath.url else { return }
|
||||||
|
@ -170,7 +170,7 @@ struct VwrPrefPaneDictionary: View {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.frame(maxHeight: CtlPrefUI.contentMaxHeight).fixedSize(horizontal: false, vertical: true)
|
.frame(maxHeight: CtlPrefUIShared.contentMaxHeight).fixedSize(horizontal: false, vertical: true)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -37,8 +37,8 @@ struct VwrPrefPaneGeneral: View {
|
||||||
|
|
||||||
var body: some View {
|
var body: some View {
|
||||||
ScrollView {
|
ScrollView {
|
||||||
SSPreferences.Container(contentWidth: CtlPrefUI.contentWidth) {
|
SSPreferences.Container(contentWidth: CtlPrefUIShared.contentWidth) {
|
||||||
SSPreferences.Section(title: "") {
|
SSPreferences.Section {
|
||||||
Text(
|
Text(
|
||||||
"\u{2022} "
|
"\u{2022} "
|
||||||
+ NSLocalizedString(
|
+ NSLocalizedString(
|
||||||
|
@ -50,9 +50,10 @@ struct VwrPrefPaneGeneral: View {
|
||||||
comment: ""
|
comment: ""
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
.preferenceDescription().prefDescriptionWidthLimited()
|
.preferenceDescription().padding(.bottom, NSFont.systemFontSize)
|
||||||
}
|
}
|
||||||
SSPreferences.Section(label: { Text(LocalizedStringKey("UI Language:")) }) {
|
SSPreferences.Section(title: "UI Language:".localized) {
|
||||||
|
HStack {
|
||||||
Picker(
|
Picker(
|
||||||
LocalizedStringKey("Follow OS settings"),
|
LocalizedStringKey("Follow OS settings"),
|
||||||
selection: $selUILanguage.onChange {
|
selection: $selUILanguage.onChange {
|
||||||
|
@ -80,8 +81,10 @@ struct VwrPrefPaneGeneral: View {
|
||||||
}
|
}
|
||||||
.labelsHidden()
|
.labelsHidden()
|
||||||
.frame(width: 180.0)
|
.frame(width: 180.0)
|
||||||
|
Spacer()
|
||||||
|
}
|
||||||
Text(LocalizedStringKey("Change user interface language (will reboot the IME)."))
|
Text(LocalizedStringKey("Change user interface language (will reboot the IME)."))
|
||||||
.preferenceDescription().prefDescriptionWidthLimited()
|
.preferenceDescription()
|
||||||
}
|
}
|
||||||
SSPreferences.Section(label: { Text(LocalizedStringKey("Typing Settings:")) }) {
|
SSPreferences.Section(label: { Text(LocalizedStringKey("Typing Settings:")) }) {
|
||||||
Toggle(
|
Toggle(
|
||||||
|
@ -135,7 +138,7 @@ struct VwrPrefPaneGeneral: View {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
alert.addButton(withTitle: NSLocalizedString("Leave it checked", comment: ""))
|
alert.addButton(withTitle: NSLocalizedString("Leave it checked", comment: ""))
|
||||||
if let window = CtlPrefUI.shared.controller.window, !selEnableFartSuppressor {
|
if let window = CtlPrefUIShared.sharedWindow, !selEnableFartSuppressor {
|
||||||
PrefMgr.shared.shouldNotFartInLieuOfBeep = true
|
PrefMgr.shared.shouldNotFartInLieuOfBeep = true
|
||||||
alert.beginSheetModal(for: window) { result in
|
alert.beginSheetModal(for: window) { result in
|
||||||
switch result {
|
switch result {
|
||||||
|
@ -174,7 +177,7 @@ struct VwrPrefPaneGeneral: View {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.frame(maxHeight: CtlPrefUI.contentMaxHeight).fixedSize(horizontal: false, vertical: true)
|
.frame(maxHeight: CtlPrefUIShared.contentMaxHeight).fixedSize(horizontal: false, vertical: true)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -23,7 +23,7 @@ struct VwrPrefPaneKeyboard: View {
|
||||||
|
|
||||||
var body: some View {
|
var body: some View {
|
||||||
ScrollView {
|
ScrollView {
|
||||||
SSPreferences.Container(contentWidth: CtlPrefUI.contentWidth) {
|
SSPreferences.Container(contentWidth: CtlPrefUIShared.contentWidth) {
|
||||||
SSPreferences.Section(title: "Quick Setup:".localized) {
|
SSPreferences.Section(title: "Quick Setup:".localized) {
|
||||||
HStack(alignment: .top) {
|
HStack(alignment: .top) {
|
||||||
Button {
|
Button {
|
||||||
|
@ -52,7 +52,7 @@ struct VwrPrefPaneKeyboard: View {
|
||||||
}
|
}
|
||||||
}.controlSize(.small)
|
}.controlSize(.small)
|
||||||
}
|
}
|
||||||
SSPreferences.Section(label: { Text(LocalizedStringKey("Phonetic Parser:")) }) {
|
SSPreferences.Section(title: "Phonetic Parser:".localized) {
|
||||||
HStack {
|
HStack {
|
||||||
Picker(
|
Picker(
|
||||||
"",
|
"",
|
||||||
|
@ -68,13 +68,12 @@ struct VwrPrefPaneKeyboard: View {
|
||||||
}
|
}
|
||||||
.fixedSize()
|
.fixedSize()
|
||||||
.labelsHidden()
|
.labelsHidden()
|
||||||
Spacer()
|
Spacer(minLength: NSFont.systemFontSize)
|
||||||
}
|
}
|
||||||
.frame(width: 380.0)
|
|
||||||
Text(NSLocalizedString("Choose the phonetic layout for Mandarin parser.", comment: ""))
|
Text(NSLocalizedString("Choose the phonetic layout for Mandarin parser.", comment: ""))
|
||||||
.preferenceDescription()
|
.preferenceDescription()
|
||||||
}
|
}
|
||||||
SSPreferences.Section(label: { Text(LocalizedStringKey("Basic Keyboard Layout:")) }) {
|
SSPreferences.Section(title: "Basic Keyboard Layout:".localized) {
|
||||||
HStack {
|
HStack {
|
||||||
Picker(
|
Picker(
|
||||||
"",
|
"",
|
||||||
|
@ -92,8 +91,8 @@ struct VwrPrefPaneKeyboard: View {
|
||||||
}
|
}
|
||||||
}.id(UUID())
|
}.id(UUID())
|
||||||
}
|
}
|
||||||
.labelsHidden()
|
.labelsHidden().frame(width: 290)
|
||||||
.frame(width: 240.0)
|
Spacer(minLength: NSFont.systemFontSize)
|
||||||
}
|
}
|
||||||
Text(
|
Text(
|
||||||
NSLocalizedString(
|
NSLocalizedString(
|
||||||
|
@ -103,7 +102,7 @@ struct VwrPrefPaneKeyboard: View {
|
||||||
)
|
)
|
||||||
.preferenceDescription()
|
.preferenceDescription()
|
||||||
}
|
}
|
||||||
SSPreferences.Section(label: { Text(LocalizedStringKey("Alphanumerical Layout:")) }) {
|
SSPreferences.Section(title: "Alphanumerical Layout:".localized) {
|
||||||
HStack {
|
HStack {
|
||||||
Picker(
|
Picker(
|
||||||
"",
|
"",
|
||||||
|
@ -117,26 +116,23 @@ struct VwrPrefPaneKeyboard: View {
|
||||||
}
|
}
|
||||||
}.id(UUID())
|
}.id(UUID())
|
||||||
}
|
}
|
||||||
.labelsHidden()
|
.labelsHidden().frame(width: 290)
|
||||||
.frame(width: 240.0)
|
Spacer(minLength: NSFont.systemFontSize)
|
||||||
}
|
}
|
||||||
HStack {
|
|
||||||
Text(
|
Text(
|
||||||
NSLocalizedString(
|
NSLocalizedString(
|
||||||
"Choose the macOS-level alphanumerical keyboard layout. This setting is for Shift-toggled alphanumerical mode only.",
|
"Choose the macOS-level alphanumerical keyboard layout. This setting is for Shift-toggled alphanumerical mode only.",
|
||||||
comment: ""
|
comment: ""
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
.preferenceDescription().fixedSize(horizontal: false, vertical: true)
|
.preferenceDescription()
|
||||||
Spacer().frame(width: 30)
|
|
||||||
}
|
}
|
||||||
}
|
SSPreferences.Section(title: "Keyboard Shortcuts:".localized) {
|
||||||
SSPreferences.Section(label: { Text(LocalizedStringKey("Keyboard Shortcuts:")) }) {
|
|
||||||
VwrPrefPaneKeyboard_KeyboardShortcuts()
|
VwrPrefPaneKeyboard_KeyboardShortcuts()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.frame(maxHeight: CtlPrefUI.contentMaxHeight).fixedSize(horizontal: false, vertical: true)
|
.frame(maxHeight: CtlPrefUIShared.contentMaxHeight).fixedSize(horizontal: false, vertical: true)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -33,8 +33,8 @@ struct VwrPrefPaneOutput: View {
|
||||||
|
|
||||||
var body: some View {
|
var body: some View {
|
||||||
ScrollView {
|
ScrollView {
|
||||||
SSPreferences.Container(contentWidth: CtlPrefUI.contentWidth) {
|
SSPreferences.Container(contentWidth: CtlPrefUIShared.contentWidth) {
|
||||||
SSPreferences.Section(title: "Output Settings:".localized) {
|
SSPreferences.Section(title: "Output Settings:".localized, bottomDivider: true) {
|
||||||
Toggle(
|
Toggle(
|
||||||
LocalizedStringKey("Auto-convert traditional Chinese glyphs to KangXi characters"),
|
LocalizedStringKey("Auto-convert traditional Chinese glyphs to KangXi characters"),
|
||||||
isOn: $selEnableKanjiConvToKangXi.onChange {
|
isOn: $selEnableKanjiConvToKangXi.onChange {
|
||||||
|
@ -61,6 +61,8 @@ struct VwrPrefPaneOutput: View {
|
||||||
PrefMgr.shared.trimUnfinishedReadingsOnCommit = selTrimUnfinishedReadingsOnCommit
|
PrefMgr.shared.trimUnfinishedReadingsOnCommit = selTrimUnfinishedReadingsOnCommit
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
}
|
||||||
|
SSPreferences.Section(title: "Experimental:".localized) {
|
||||||
Toggle(
|
Toggle(
|
||||||
LocalizedStringKey("Harden vertical punctuations during vertical typing (not recommended)"),
|
LocalizedStringKey("Harden vertical punctuations during vertical typing (not recommended)"),
|
||||||
isOn: $selHardenVerticalPunctuations.onChange {
|
isOn: $selHardenVerticalPunctuations.onChange {
|
||||||
|
@ -72,11 +74,11 @@ struct VwrPrefPaneOutput: View {
|
||||||
"⚠︎ This feature is useful ONLY WHEN the font you are using doesn't support dynamic vertical punctuations. However, typed vertical punctuations will always shown as vertical punctuations EVEN IF your editor has changed the typing direction to horizontal."
|
"⚠︎ This feature is useful ONLY WHEN the font you are using doesn't support dynamic vertical punctuations. However, typed vertical punctuations will always shown as vertical punctuations EVEN IF your editor has changed the typing direction to horizontal."
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
.preferenceDescription().prefDescriptionWidthLimited()
|
.preferenceDescription()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.frame(maxHeight: CtlPrefUI.contentMaxHeight).fixedSize(horizontal: false, vertical: true)
|
.frame(maxHeight: CtlPrefUIShared.contentMaxHeight).fixedSize(horizontal: false, vertical: true)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -24,13 +24,13 @@ struct VwrPrefPanePhrases: View {
|
||||||
var body: some View {
|
var body: some View {
|
||||||
ScrollView {
|
ScrollView {
|
||||||
VStack {
|
VStack {
|
||||||
VwrPhraseEditorUI(delegate: LMMgr.shared, window: CtlPrefUI.shared.controller.window)
|
VwrPhraseEditorUI(delegate: LMMgr.shared, window: CtlPrefUIShared.sharedWindow)
|
||||||
.frame(width: CtlPrefUI.contentWidth + 28, height: 445)
|
.frame(width: CtlPrefUIShared.contentWidth + 28, height: 445)
|
||||||
Spacer()
|
Spacer()
|
||||||
}
|
}
|
||||||
.padding()
|
.padding()
|
||||||
}
|
}
|
||||||
.frame(maxHeight: CtlPrefUI.contentMaxHeight).fixedSize(horizontal: false, vertical: true)
|
.frame(maxHeight: CtlPrefUIShared.contentMaxHeight).fixedSize(horizontal: false, vertical: true)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -19,7 +19,6 @@ enum PrefUITabs: String, CaseIterable {
|
||||||
case tabCassette = "Cassette"
|
case tabCassette = "Cassette"
|
||||||
case tabKeyboard = "Keyboard"
|
case tabKeyboard = "Keyboard"
|
||||||
case tabDevZone = "DevZone"
|
case tabDevZone = "DevZone"
|
||||||
case tabExperience = "Experience"
|
|
||||||
}
|
}
|
||||||
|
|
||||||
extension PrefUITabs {
|
extension PrefUITabs {
|
||||||
|
@ -33,9 +32,37 @@ extension PrefUITabs {
|
||||||
"Cassette": (Hans: "磁带设定", Hant: "磁帶設定", Ja: "カセ設定"),
|
"Cassette": (Hans: "磁带设定", Hant: "磁帶設定", Ja: "カセ設定"),
|
||||||
"Keyboard": (Hans: "键盘设定", Hant: "鍵盤設定", Ja: "配列設定"),
|
"Keyboard": (Hans: "键盘设定", Hant: "鍵盤設定", Ja: "配列設定"),
|
||||||
"DevZone": (Hans: "开发道场", Hant: "開發道場", Ja: "開発道場"),
|
"DevZone": (Hans: "开发道场", Hant: "開發道場", Ja: "開発道場"),
|
||||||
"Experience": (Hans: "体验设定", Hant: "體驗設定", Ja: "体験設定"),
|
|
||||||
]
|
]
|
||||||
|
|
||||||
|
var cocoaTag: Int {
|
||||||
|
switch self {
|
||||||
|
case .tabGeneral: return 10
|
||||||
|
case .tabCandidates: return 20
|
||||||
|
case .tabBehavior: return 30
|
||||||
|
case .tabOutput: return 40
|
||||||
|
case .tabDictionary: return 50
|
||||||
|
case .tabPhrases: return 60
|
||||||
|
case .tabCassette: return 70
|
||||||
|
case .tabKeyboard: return 80
|
||||||
|
case .tabDevZone: return 90
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static func fromInt(_ int: Int) -> Self? {
|
||||||
|
switch int {
|
||||||
|
case 10: return .tabGeneral
|
||||||
|
case 20: return .tabCandidates
|
||||||
|
case 30: return .tabBehavior
|
||||||
|
case 40: return .tabOutput
|
||||||
|
case 50: return .tabDictionary
|
||||||
|
case 60: return .tabPhrases
|
||||||
|
case 70: return .tabCassette
|
||||||
|
case 80: return .tabKeyboard
|
||||||
|
case 90: return .tabDevZone
|
||||||
|
default: return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
var toolbarIdentifier: NSToolbarItem.Identifier { .init(rawValue: rawValue) }
|
var toolbarIdentifier: NSToolbarItem.Identifier { .init(rawValue: rawValue) }
|
||||||
|
|
||||||
var i18nTitle: String {
|
var i18nTitle: String {
|
||||||
|
@ -73,8 +100,6 @@ extension PrefUITabs {
|
||||||
return "keyboard.macwindow"
|
return "keyboard.macwindow"
|
||||||
case .tabDevZone:
|
case .tabDevZone:
|
||||||
return "pc"
|
return "pc"
|
||||||
case .tabExperience:
|
|
||||||
return "person.fill.questionmark"
|
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
let note = "\(self.rawValue) Preferences"
|
let note = "\(self.rawValue) Preferences"
|
||||||
|
|
|
@ -14,10 +14,8 @@ import Shared
|
||||||
|
|
||||||
private let kWindowTitleHeight: Double = 78
|
private let kWindowTitleHeight: Double = 78
|
||||||
|
|
||||||
// Note: The "InputMethodServerPreferencesWindowControllerClass" in Info.plist
|
// InputMethodServerPreferencesWindowControllerClass 非必需。
|
||||||
// only works with macOS System Preference pane (like macOS built-in input methods).
|
|
||||||
// It should be set as "Preferences" which correspondes to the "Preference" pref pane
|
|
||||||
// of this build target.
|
|
||||||
class CtlPrefWindow: NSWindowController, NSWindowDelegate {
|
class CtlPrefWindow: NSWindowController, NSWindowDelegate {
|
||||||
@IBOutlet var uiLanguageButton: NSPopUpButton!
|
@IBOutlet var uiLanguageButton: NSPopUpButton!
|
||||||
@IBOutlet var basicKeyboardLayoutButton: NSPopUpButton!
|
@IBOutlet var basicKeyboardLayoutButton: NSPopUpButton!
|
||||||
|
@ -30,6 +28,10 @@ class CtlPrefWindow: NSWindowController, NSWindowDelegate {
|
||||||
@IBOutlet var chkFartSuppressor: NSButton!
|
@IBOutlet var chkFartSuppressor: NSButton!
|
||||||
|
|
||||||
@IBOutlet var chkRevLookupInCandidateWindow: NSButton!
|
@IBOutlet var chkRevLookupInCandidateWindow: NSButton!
|
||||||
|
@IBOutlet var btnBrowseFolderForUserPhrases: NSButton!
|
||||||
|
@IBOutlet var txtUserPhrasesFolderPath: NSTextField!
|
||||||
|
@IBOutlet var lblUserPhraseFolderChangeDescription: NSTextField!
|
||||||
|
|
||||||
@IBOutlet var cmbPEInputModeMenu: NSPopUpButton!
|
@IBOutlet var cmbPEInputModeMenu: NSPopUpButton!
|
||||||
@IBOutlet var cmbPEDataTypeMenu: NSPopUpButton!
|
@IBOutlet var cmbPEDataTypeMenu: NSPopUpButton!
|
||||||
@IBOutlet var btnPEReload: NSButton!
|
@IBOutlet var btnPEReload: NSButton!
|
||||||
|
@ -62,10 +64,12 @@ class CtlPrefWindow: NSWindowController, NSWindowDelegate {
|
||||||
if shared == nil { shared = CtlPrefWindow(windowNibName: "frmPrefWindow") }
|
if shared == nil { shared = CtlPrefWindow(windowNibName: "frmPrefWindow") }
|
||||||
guard let shared = shared, let sharedWindow = shared.window else { return }
|
guard let shared = shared, let sharedWindow = shared.window else { return }
|
||||||
sharedWindow.delegate = shared
|
sharedWindow.delegate = shared
|
||||||
|
if !sharedWindow.isVisible {
|
||||||
|
shared.windowDidLoad()
|
||||||
|
}
|
||||||
sharedWindow.setPosition(vertical: .top, horizontal: .right, padding: 20)
|
sharedWindow.setPosition(vertical: .top, horizontal: .right, padding: 20)
|
||||||
sharedWindow.orderFrontRegardless() // 逼著視窗往最前方顯示
|
sharedWindow.orderFrontRegardless() // 逼著視窗往最前方顯示
|
||||||
sharedWindow.level = .statusBar
|
sharedWindow.level = .statusBar
|
||||||
sharedWindow.titlebarAppearsTransparent = true
|
|
||||||
shared.showWindow(shared)
|
shared.showWindow(shared)
|
||||||
if resetPhraseEditor { shared.initPhraseEditor() }
|
if resetPhraseEditor { shared.initPhraseEditor() }
|
||||||
NSApp.activate(ignoringOtherApps: true)
|
NSApp.activate(ignoringOtherApps: true)
|
||||||
|
@ -98,13 +102,13 @@ class CtlPrefWindow: NSWindowController, NSWindowDelegate {
|
||||||
toolbar.delegate = self
|
toolbar.delegate = self
|
||||||
toolbar.selectedItemIdentifier = PrefUITabs.tabGeneral.toolbarIdentifier
|
toolbar.selectedItemIdentifier = PrefUITabs.tabGeneral.toolbarIdentifier
|
||||||
toolbar.showsBaselineSeparator = true
|
toolbar.showsBaselineSeparator = true
|
||||||
window?.titlebarAppearsTransparent = false
|
|
||||||
if #available(macOS 11.0, *) {
|
if #available(macOS 11.0, *) {
|
||||||
window?.toolbarStyle = .preference
|
window?.toolbarStyle = .preference
|
||||||
}
|
}
|
||||||
window?.toolbar = toolbar
|
window?.toolbar = toolbar
|
||||||
window?.title = preferencesTitleName
|
window?.title = preferencesTitleName
|
||||||
use(view: vwrGeneral)
|
window?.titlebarAppearsTransparent = false
|
||||||
|
use(view: vwrGeneral, animate: false)
|
||||||
|
|
||||||
lblCurrentlySpecifiedUserDataFolder.placeholderString = LMMgr.dataFolderPath(
|
lblCurrentlySpecifiedUserDataFolder.placeholderString = LMMgr.dataFolderPath(
|
||||||
isDefaultFolder: true)
|
isDefaultFolder: true)
|
||||||
|
@ -406,28 +410,21 @@ class CtlPrefWindow: NSWindowController, NSWindowDelegate {
|
||||||
// MARK: - NSToolbarDelegate Methods
|
// MARK: - NSToolbarDelegate Methods
|
||||||
|
|
||||||
extension CtlPrefWindow: NSToolbarDelegate {
|
extension CtlPrefWindow: NSToolbarDelegate {
|
||||||
func use(view: NSView) {
|
func use(view newView: NSView, animate: Bool = true) {
|
||||||
guard let window = window else {
|
guard let window = window, let existingContentView = window.contentView else { return }
|
||||||
return
|
let temporaryViewOld = NSView(frame: existingContentView.frame)
|
||||||
}
|
window.contentView = temporaryViewOld
|
||||||
window.contentView?.subviews.first?.removeFromSuperview()
|
var newWindowRect = NSRect(origin: window.frame.origin, size: newView.bounds.size)
|
||||||
let viewFrame = view.frame
|
newWindowRect.size.height += kWindowTitleHeight
|
||||||
var windowRect = window.frame
|
newWindowRect.origin.y = window.frame.maxY - newWindowRect.height
|
||||||
windowRect.size.height = kWindowTitleHeight + viewFrame.height
|
window.setFrame(newWindowRect, display: true, animate: animate)
|
||||||
windowRect.size.width = viewFrame.width
|
window.contentView = newView
|
||||||
windowRect.origin.y = window.frame.maxY - (viewFrame.height + kWindowTitleHeight)
|
|
||||||
window.setFrame(windowRect, display: true, animate: true)
|
|
||||||
window.contentView?.frame = view.bounds
|
|
||||||
window.contentView?.addSubview(view)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
var toolbarIdentifiers: [NSToolbarItem.Identifier] {
|
var toolbarIdentifiers: [NSToolbarItem.Identifier] {
|
||||||
var result = [NSToolbarItem.Identifier]()
|
PrefUITabs.allCases.filter {
|
||||||
PrefUITabs.allCases.forEach { neta in
|
$0 != .tabOutput
|
||||||
if [.tabOutput, .tabExperience].contains(neta) { return }
|
}.map(\.toolbarIdentifier)
|
||||||
result.append(neta.toolbarIdentifier)
|
|
||||||
}
|
|
||||||
return result
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func toolbarDefaultItemIdentifiers(_: NSToolbar) -> [NSToolbarItem.Identifier] {
|
func toolbarDefaultItemIdentifiers(_: NSToolbar) -> [NSToolbarItem.Identifier] {
|
||||||
|
@ -442,44 +439,20 @@ extension CtlPrefWindow: NSToolbarDelegate {
|
||||||
toolbarIdentifiers
|
toolbarIdentifiers
|
||||||
}
|
}
|
||||||
|
|
||||||
@objc func showGeneralView(_: Any?) {
|
@objc func updateTab(_ target: NSToolbarItem) {
|
||||||
use(view: vwrGeneral)
|
guard let tab = PrefUITabs.fromInt(target.tag) else { return }
|
||||||
window?.toolbar?.selectedItemIdentifier = PrefUITabs.tabGeneral.toolbarIdentifier
|
switch tab {
|
||||||
|
case .tabGeneral: use(view: vwrGeneral)
|
||||||
|
case .tabCandidates: use(view: vwrCandidates)
|
||||||
|
case .tabBehavior: use(view: vwrBehavior)
|
||||||
|
case .tabOutput: return
|
||||||
|
case .tabDictionary: use(view: vwrDictionary)
|
||||||
|
case .tabPhrases: use(view: vwrPhrases)
|
||||||
|
case .tabCassette: use(view: vwrCassette)
|
||||||
|
case .tabKeyboard: use(view: vwrKeyboard)
|
||||||
|
case .tabDevZone: use(view: vwrDevZone)
|
||||||
}
|
}
|
||||||
|
window?.toolbar?.selectedItemIdentifier = tab.toolbarIdentifier
|
||||||
@objc func showCandidatesView(_: Any?) {
|
|
||||||
use(view: vwrCandidates)
|
|
||||||
window?.toolbar?.selectedItemIdentifier = PrefUITabs.tabCandidates.toolbarIdentifier
|
|
||||||
}
|
|
||||||
|
|
||||||
@objc func showBehaviorView(_: Any?) {
|
|
||||||
use(view: vwrBehavior)
|
|
||||||
window?.toolbar?.selectedItemIdentifier = PrefUITabs.tabBehavior.toolbarIdentifier
|
|
||||||
}
|
|
||||||
|
|
||||||
@objc func showDictionaryView(_: Any?) {
|
|
||||||
use(view: vwrDictionary)
|
|
||||||
window?.toolbar?.selectedItemIdentifier = PrefUITabs.tabDictionary.toolbarIdentifier
|
|
||||||
}
|
|
||||||
|
|
||||||
@objc func showPhrasesView(_: Any?) {
|
|
||||||
use(view: vwrPhrases)
|
|
||||||
window?.toolbar?.selectedItemIdentifier = PrefUITabs.tabPhrases.toolbarIdentifier
|
|
||||||
}
|
|
||||||
|
|
||||||
@objc func showCassetteView(_: Any?) {
|
|
||||||
use(view: vwrCassette)
|
|
||||||
window?.toolbar?.selectedItemIdentifier = PrefUITabs.tabCassette.toolbarIdentifier
|
|
||||||
}
|
|
||||||
|
|
||||||
@objc func showKeyboardView(_: Any?) {
|
|
||||||
use(view: vwrKeyboard)
|
|
||||||
window?.toolbar?.selectedItemIdentifier = PrefUITabs.tabKeyboard.toolbarIdentifier
|
|
||||||
}
|
|
||||||
|
|
||||||
@objc func showDevZoneView(_: Any?) {
|
|
||||||
use(view: vwrDevZone)
|
|
||||||
window?.toolbar?.selectedItemIdentifier = PrefUITabs.tabDevZone.toolbarIdentifier
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func toolbar(
|
func toolbar(
|
||||||
|
@ -491,18 +464,8 @@ extension CtlPrefWindow: NSToolbarDelegate {
|
||||||
item.target = self
|
item.target = self
|
||||||
item.image = tab.icon
|
item.image = tab.icon
|
||||||
item.label = tab.i18nTitle
|
item.label = tab.i18nTitle
|
||||||
switch tab {
|
item.tag = tab.cocoaTag
|
||||||
case .tabGeneral: item.action = #selector(showGeneralView(_:))
|
item.action = #selector(updateTab(_:))
|
||||||
case .tabCandidates: item.action = #selector(showCandidatesView(_:))
|
|
||||||
case .tabBehavior: item.action = #selector(showBehaviorView(_:))
|
|
||||||
case .tabOutput: return nil
|
|
||||||
case .tabDictionary: item.action = #selector(showDictionaryView(_:))
|
|
||||||
case .tabPhrases: item.action = #selector(showPhrasesView(_:))
|
|
||||||
case .tabCassette: item.action = #selector(showCassetteView(_:))
|
|
||||||
case .tabKeyboard: item.action = #selector(showKeyboardView(_:))
|
|
||||||
case .tabDevZone: item.action = #selector(showDevZoneView(_:))
|
|
||||||
case .tabExperience: return nil
|
|
||||||
}
|
|
||||||
return item
|
return item
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -54,7 +54,7 @@
|
||||||
5BA8C30328DF0360004C5CC4 /* CandidateWindow in Frameworks */ = {isa = PBXBuildFile; productRef = 5BA8C30228DF0360004C5CC4 /* CandidateWindow */; };
|
5BA8C30328DF0360004C5CC4 /* CandidateWindow in Frameworks */ = {isa = PBXBuildFile; productRef = 5BA8C30228DF0360004C5CC4 /* CandidateWindow */; };
|
||||||
5BA9FD0F27FEDB6B002DE248 /* VwrPrefPaneGeneral.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5BA9FD0A27FEDB6B002DE248 /* VwrPrefPaneGeneral.swift */; };
|
5BA9FD0F27FEDB6B002DE248 /* VwrPrefPaneGeneral.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5BA9FD0A27FEDB6B002DE248 /* VwrPrefPaneGeneral.swift */; };
|
||||||
5BA9FD1027FEDB6B002DE248 /* VwrPrefPaneKeyboard.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5BA9FD0B27FEDB6B002DE248 /* VwrPrefPaneKeyboard.swift */; };
|
5BA9FD1027FEDB6B002DE248 /* VwrPrefPaneKeyboard.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5BA9FD0B27FEDB6B002DE248 /* VwrPrefPaneKeyboard.swift */; };
|
||||||
5BA9FD1127FEDB6B002DE248 /* CtlPrefUI.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5BA9FD0C27FEDB6B002DE248 /* CtlPrefUI.swift */; };
|
5BA9FD1127FEDB6B002DE248 /* CtlPrefUIShared.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5BA9FD0C27FEDB6B002DE248 /* CtlPrefUIShared.swift */; };
|
||||||
5BA9FD1327FEDB6B002DE248 /* VwrPrefPaneDictionary.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5BA9FD0E27FEDB6B002DE248 /* VwrPrefPaneDictionary.swift */; };
|
5BA9FD1327FEDB6B002DE248 /* VwrPrefPaneDictionary.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5BA9FD0E27FEDB6B002DE248 /* VwrPrefPaneDictionary.swift */; };
|
||||||
5BAD0CD527D701F6003D127F /* vChewingKeyLayout.bundle in Resources */ = {isa = PBXBuildFile; fileRef = 5B30F11227BA568800484E24 /* vChewingKeyLayout.bundle */; };
|
5BAD0CD527D701F6003D127F /* vChewingKeyLayout.bundle in Resources */ = {isa = PBXBuildFile; fileRef = 5B30F11227BA568800484E24 /* vChewingKeyLayout.bundle */; };
|
||||||
5BAEFAD028012565001F42C9 /* LMMgr.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5BAEFACF28012565001F42C9 /* LMMgr.swift */; };
|
5BAEFAD028012565001F42C9 /* LMMgr.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5BAEFACF28012565001F42C9 /* LMMgr.swift */; };
|
||||||
|
@ -103,6 +103,7 @@
|
||||||
5BF018FD299923C200248CDD /* VwrPrefPaneCandidates.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5BF018FC299923C100248CDD /* VwrPrefPaneCandidates.swift */; };
|
5BF018FD299923C200248CDD /* VwrPrefPaneCandidates.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5BF018FC299923C100248CDD /* VwrPrefPaneCandidates.swift */; };
|
||||||
5BF56F9828C39A2700DD6839 /* IMEState.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5BF56F9728C39A2700DD6839 /* IMEState.swift */; };
|
5BF56F9828C39A2700DD6839 /* IMEState.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5BF56F9728C39A2700DD6839 /* IMEState.swift */; };
|
||||||
5BF56F9A28C39D1800DD6839 /* IMEStateData.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5BF56F9928C39D1800DD6839 /* IMEStateData.swift */; };
|
5BF56F9A28C39D1800DD6839 /* IMEStateData.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5BF56F9928C39D1800DD6839 /* IMEStateData.swift */; };
|
||||||
|
5BF7548929B2F04F00FA50DA /* CtlPrefUI.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5BF7548829B2F04F00FA50DA /* CtlPrefUI.swift */; };
|
||||||
5BF9DA2728840E6200DBD48E /* template-usersymbolphrases.txt in Resources */ = {isa = PBXBuildFile; fileRef = 5BF9DA2228840E6200DBD48E /* template-usersymbolphrases.txt */; };
|
5BF9DA2728840E6200DBD48E /* template-usersymbolphrases.txt in Resources */ = {isa = PBXBuildFile; fileRef = 5BF9DA2228840E6200DBD48E /* template-usersymbolphrases.txt */; };
|
||||||
5BF9DA2828840E6200DBD48E /* template-exclusions.txt in Resources */ = {isa = PBXBuildFile; fileRef = 5BF9DA2328840E6200DBD48E /* template-exclusions.txt */; };
|
5BF9DA2828840E6200DBD48E /* template-exclusions.txt in Resources */ = {isa = PBXBuildFile; fileRef = 5BF9DA2328840E6200DBD48E /* template-exclusions.txt */; };
|
||||||
5BF9DA2928840E6200DBD48E /* template-associatedPhrases-chs.txt in Resources */ = {isa = PBXBuildFile; fileRef = 5BF9DA2428840E6200DBD48E /* template-associatedPhrases-chs.txt */; };
|
5BF9DA2928840E6200DBD48E /* template-associatedPhrases-chs.txt in Resources */ = {isa = PBXBuildFile; fileRef = 5BF9DA2428840E6200DBD48E /* template-associatedPhrases-chs.txt */; };
|
||||||
|
@ -248,7 +249,7 @@
|
||||||
5BA8C30128DEFE4F004C5CC4 /* vChewing_CandidateWindow */ = {isa = PBXFileReference; lastKnownFileType = wrapper; name = vChewing_CandidateWindow; path = Packages/vChewing_CandidateWindow; sourceTree = "<group>"; };
|
5BA8C30128DEFE4F004C5CC4 /* vChewing_CandidateWindow */ = {isa = PBXFileReference; lastKnownFileType = wrapper; name = vChewing_CandidateWindow; path = Packages/vChewing_CandidateWindow; sourceTree = "<group>"; };
|
||||||
5BA9FD0A27FEDB6B002DE248 /* VwrPrefPaneGeneral.swift */ = {isa = PBXFileReference; explicitFileType = sourcecode.swift; fileEncoding = 4; indentWidth = 2; lineEnding = 0; path = VwrPrefPaneGeneral.swift; sourceTree = "<group>"; tabWidth = 2; usesTabs = 0; };
|
5BA9FD0A27FEDB6B002DE248 /* VwrPrefPaneGeneral.swift */ = {isa = PBXFileReference; explicitFileType = sourcecode.swift; fileEncoding = 4; indentWidth = 2; lineEnding = 0; path = VwrPrefPaneGeneral.swift; sourceTree = "<group>"; tabWidth = 2; usesTabs = 0; };
|
||||||
5BA9FD0B27FEDB6B002DE248 /* VwrPrefPaneKeyboard.swift */ = {isa = PBXFileReference; explicitFileType = sourcecode.swift; fileEncoding = 4; indentWidth = 2; lineEnding = 0; path = VwrPrefPaneKeyboard.swift; sourceTree = "<group>"; tabWidth = 2; usesTabs = 0; };
|
5BA9FD0B27FEDB6B002DE248 /* VwrPrefPaneKeyboard.swift */ = {isa = PBXFileReference; explicitFileType = sourcecode.swift; fileEncoding = 4; indentWidth = 2; lineEnding = 0; path = VwrPrefPaneKeyboard.swift; sourceTree = "<group>"; tabWidth = 2; usesTabs = 0; };
|
||||||
5BA9FD0C27FEDB6B002DE248 /* CtlPrefUI.swift */ = {isa = PBXFileReference; explicitFileType = sourcecode.swift; fileEncoding = 4; indentWidth = 2; lineEnding = 0; path = CtlPrefUI.swift; sourceTree = "<group>"; tabWidth = 2; usesTabs = 0; };
|
5BA9FD0C27FEDB6B002DE248 /* CtlPrefUIShared.swift */ = {isa = PBXFileReference; explicitFileType = sourcecode.swift; fileEncoding = 4; indentWidth = 2; lineEnding = 0; path = CtlPrefUIShared.swift; sourceTree = "<group>"; tabWidth = 2; usesTabs = 0; };
|
||||||
5BA9FD0E27FEDB6B002DE248 /* VwrPrefPaneDictionary.swift */ = {isa = PBXFileReference; explicitFileType = sourcecode.swift; fileEncoding = 4; indentWidth = 2; lineEnding = 0; path = VwrPrefPaneDictionary.swift; sourceTree = "<group>"; tabWidth = 2; usesTabs = 0; };
|
5BA9FD0E27FEDB6B002DE248 /* VwrPrefPaneDictionary.swift */ = {isa = PBXFileReference; explicitFileType = sourcecode.swift; fileEncoding = 4; indentWidth = 2; lineEnding = 0; path = VwrPrefPaneDictionary.swift; sourceTree = "<group>"; tabWidth = 2; usesTabs = 0; };
|
||||||
5BAEFACF28012565001F42C9 /* LMMgr.swift */ = {isa = PBXFileReference; explicitFileType = sourcecode.swift; fileEncoding = 4; indentWidth = 2; lineEnding = 0; path = LMMgr.swift; sourceTree = "<group>"; tabWidth = 2; usesTabs = 0; };
|
5BAEFACF28012565001F42C9 /* LMMgr.swift */ = {isa = PBXFileReference; explicitFileType = sourcecode.swift; fileEncoding = 4; indentWidth = 2; lineEnding = 0; path = LMMgr.swift; sourceTree = "<group>"; tabWidth = 2; usesTabs = 0; };
|
||||||
5BB1D7F32999027200EA8D2C /* PrefUITabs.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PrefUITabs.swift; sourceTree = "<group>"; };
|
5BB1D7F32999027200EA8D2C /* PrefUITabs.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PrefUITabs.swift; sourceTree = "<group>"; };
|
||||||
|
@ -302,6 +303,7 @@
|
||||||
5BF4A44628E5820C002AF9C5 /* vChewingInstaller.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = vChewingInstaller.entitlements; sourceTree = "<group>"; };
|
5BF4A44628E5820C002AF9C5 /* vChewingInstaller.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = vChewingInstaller.entitlements; sourceTree = "<group>"; };
|
||||||
5BF56F9728C39A2700DD6839 /* IMEState.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = IMEState.swift; sourceTree = "<group>"; };
|
5BF56F9728C39A2700DD6839 /* IMEState.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = IMEState.swift; sourceTree = "<group>"; };
|
||||||
5BF56F9928C39D1800DD6839 /* IMEStateData.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = IMEStateData.swift; sourceTree = "<group>"; };
|
5BF56F9928C39D1800DD6839 /* IMEStateData.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = IMEStateData.swift; sourceTree = "<group>"; };
|
||||||
|
5BF7548829B2F04F00FA50DA /* CtlPrefUI.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CtlPrefUI.swift; sourceTree = "<group>"; };
|
||||||
5BF9DA2228840E6200DBD48E /* template-usersymbolphrases.txt */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; lineEnding = 0; path = "template-usersymbolphrases.txt"; sourceTree = "<group>"; usesTabs = 0; };
|
5BF9DA2228840E6200DBD48E /* template-usersymbolphrases.txt */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; lineEnding = 0; path = "template-usersymbolphrases.txt"; sourceTree = "<group>"; usesTabs = 0; };
|
||||||
5BF9DA2328840E6200DBD48E /* template-exclusions.txt */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; lineEnding = 0; path = "template-exclusions.txt"; sourceTree = "<group>"; usesTabs = 0; };
|
5BF9DA2328840E6200DBD48E /* template-exclusions.txt */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; lineEnding = 0; path = "template-exclusions.txt"; sourceTree = "<group>"; usesTabs = 0; };
|
||||||
5BF9DA2428840E6200DBD48E /* template-associatedPhrases-chs.txt */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; lineEnding = 0; name = "template-associatedPhrases-chs.txt"; path = "../Data/components/chs/template-associatedPhrases-chs.txt"; sourceTree = "<group>"; usesTabs = 0; };
|
5BF9DA2428840E6200DBD48E /* template-associatedPhrases-chs.txt */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; lineEnding = 0; name = "template-associatedPhrases-chs.txt"; path = "../Data/components/chs/template-associatedPhrases-chs.txt"; sourceTree = "<group>"; usesTabs = 0; };
|
||||||
|
@ -526,7 +528,8 @@
|
||||||
5BA9FD0927FED9F3002DE248 /* PrefUI */ = {
|
5BA9FD0927FED9F3002DE248 /* PrefUI */ = {
|
||||||
isa = PBXGroup;
|
isa = PBXGroup;
|
||||||
children = (
|
children = (
|
||||||
5BA9FD0C27FEDB6B002DE248 /* CtlPrefUI.swift */,
|
5BA9FD0C27FEDB6B002DE248 /* CtlPrefUIShared.swift */,
|
||||||
|
5BF7548829B2F04F00FA50DA /* CtlPrefUI.swift */,
|
||||||
5BA9FD0A27FEDB6B002DE248 /* VwrPrefPaneGeneral.swift */,
|
5BA9FD0A27FEDB6B002DE248 /* VwrPrefPaneGeneral.swift */,
|
||||||
5BF018FC299923C100248CDD /* VwrPrefPaneCandidates.swift */,
|
5BF018FC299923C100248CDD /* VwrPrefPaneCandidates.swift */,
|
||||||
5BF018F8299923BD00248CDD /* VwrPrefPaneBehavior.swift */,
|
5BF018F8299923BD00248CDD /* VwrPrefPaneBehavior.swift */,
|
||||||
|
@ -1112,9 +1115,10 @@
|
||||||
5B782EC4280C243C007276DE /* InputHandler_HandleCandidate.swift in Sources */,
|
5B782EC4280C243C007276DE /* InputHandler_HandleCandidate.swift in Sources */,
|
||||||
5BA9FD0F27FEDB6B002DE248 /* VwrPrefPaneGeneral.swift in Sources */,
|
5BA9FD0F27FEDB6B002DE248 /* VwrPrefPaneGeneral.swift in Sources */,
|
||||||
5BCCAFF828DB19A300AB1B27 /* PrefMgr_Extension.swift in Sources */,
|
5BCCAFF828DB19A300AB1B27 /* PrefMgr_Extension.swift in Sources */,
|
||||||
5BA9FD1127FEDB6B002DE248 /* CtlPrefUI.swift in Sources */,
|
5BA9FD1127FEDB6B002DE248 /* CtlPrefUIShared.swift in Sources */,
|
||||||
5B8457A12871ADBE00C93B01 /* ChineseConverterBridge.swift in Sources */,
|
5B8457A12871ADBE00C93B01 /* ChineseConverterBridge.swift in Sources */,
|
||||||
5BA9FD1327FEDB6B002DE248 /* VwrPrefPaneDictionary.swift in Sources */,
|
5BA9FD1327FEDB6B002DE248 /* VwrPrefPaneDictionary.swift in Sources */,
|
||||||
|
5BF7548929B2F04F00FA50DA /* CtlPrefUI.swift in Sources */,
|
||||||
5BF018F9299923BD00248CDD /* VwrPrefPaneBehavior.swift in Sources */,
|
5BF018F9299923BD00248CDD /* VwrPrefPaneBehavior.swift in Sources */,
|
||||||
5BFDF011289635C100417BBC /* IMKCandidatesImpl.swift in Sources */,
|
5BFDF011289635C100417BBC /* IMKCandidatesImpl.swift in Sources */,
|
||||||
5BB802DA27FABA8300CF1C19 /* SessionCtl_Menu.swift in Sources */,
|
5BB802DA27FABA8300CF1C19 /* SessionCtl_Menu.swift in Sources */,
|
||||||
|
|
Loading…
Reference in New Issue