diff --git a/Source/3rdParty/VDKComboBox/VDKComboBox.swift b/Source/3rdParty/VDKComboBox/VDKComboBox.swift new file mode 100644 index 00000000..2c14bc58 --- /dev/null +++ b/Source/3rdParty/VDKComboBox/VDKComboBox.swift @@ -0,0 +1,70 @@ +// +// Ref: https://stackoverflow.com/a/71058587/4162914 +// License: https://creativecommons.org/licenses/by-sa/4.0/ +// + +import SwiftUI + +// MARK: - NSComboBox +// Ref: https://stackoverflow.com/a/71058587/4162914 +@available(macOS 11.0, *) +struct ComboBox: NSViewRepresentable { + // The items that will show up in the pop-up menu: + var items: [String] + + // The property on our parent view that gets synced to the current + // stringValue of the NSComboBox, whether the user typed it in or + // selected it from the list: + @Binding var text: String + + func makeCoordinator() -> Coordinator { + return Coordinator(self) + } + + func makeNSView(context: Context) -> NSComboBox { + let comboBox = NSComboBox() + comboBox.usesDataSource = false + comboBox.completes = false + comboBox.delegate = context.coordinator + comboBox.intercellSpacing = NSSize(width: 0.0, height: 10.0) + return comboBox + } + + func updateNSView(_ nsView: NSComboBox, context: Context) { + nsView.removeAllItems() + nsView.addItems(withObjectValues: items) + + // ComboBox doesn't automatically select the item matching its text; + // we must do that manually. But we need the delegate to ignore that + // selection-change or we'll get a "state modified during view update; + // will cause undefined behavior" warning. + context.coordinator.ignoreSelectionChanges = true + nsView.stringValue = text + nsView.selectItem(withObjectValue: text) + context.coordinator.ignoreSelectionChanges = false + } + + class Coordinator: NSObject, NSComboBoxDelegate { + var parent: ComboBox + var ignoreSelectionChanges: Bool = false + + init(_ parent: ComboBox) { + self.parent = parent + } + + func comboBoxSelectionDidChange(_ notification: Notification) { + if !ignoreSelectionChanges, + let box: NSComboBox = notification.object as? NSComboBox, + let newStringValue: String = box.objectValueOfSelectedItem as? String + { + parent.text = newStringValue + } + } + + func controlTextDidEndEditing(_ obj: Notification) { + if let textField = obj.object as? NSTextField { + parent.text = textField.stringValue + } + } + } +} diff --git a/Source/Modules/IMEModules/ctlInputMethod_Menu.swift b/Source/Modules/IMEModules/ctlInputMethod_Menu.swift index a6a5aca2..bdd05ea4 100644 --- a/Source/Modules/IMEModules/ctlInputMethod_Menu.swift +++ b/Source/Modules/IMEModules/ctlInputMethod_Menu.swift @@ -123,10 +123,14 @@ extension ctlInputMethod { menu.addItem(NSMenuItem.separator()) // --------------------- - menu.addItem( - withTitle: NSLocalizedString("vChewing Preferences…", comment: ""), - action: #selector(showPreferences(_:)), keyEquivalent: "") - if !optionKeyPressed { + if optionKeyPressed { + menu.addItem( + withTitle: NSLocalizedString("vChewing Preferences…", comment: ""), + action: #selector(showLegacyPreferences(_:)), keyEquivalent: "") + } else { + menu.addItem( + withTitle: NSLocalizedString("vChewing Preferences…", comment: ""), + action: #selector(showPreferences(_:)), keyEquivalent: "") menu.addItem( withTitle: NSLocalizedString("Check for Updates…", comment: ""), action: #selector(checkForUpdate(_:)), keyEquivalent: "") @@ -152,6 +156,20 @@ extension ctlInputMethod { // MARK: - IME Menu Items @objc override func showPreferences(_ sender: Any?) { + if #available(macOS 11.0, *) { + NSApp.setActivationPolicy(.accessory) + ctlPrefUI.shared.controller.show(preferencePane: Preferences.PaneIdentifier(rawValue: "General")) + ctlPrefUI.shared.controller.window?.level = .floating + } else { + showPrefWindowTraditional() + } + } + + @objc func showLegacyPreferences(_ sender: Any?) { + showPrefWindowTraditional() + } + + private func showPrefWindowTraditional() { (NSApp.delegate as? AppDelegate)?.showPreferences() NSApp.activate(ignoringOtherApps: true) } diff --git a/Source/Resources/Base.lproj/Localizable.strings b/Source/Resources/Base.lproj/Localizable.strings index a1ce8b59..540c3ddc 100644 --- a/Source/Resources/Base.lproj/Localizable.strings +++ b/Source/Resources/Base.lproj/Localizable.strings @@ -73,3 +73,71 @@ "catDoubleTableLines" = "DoubleTableLines"; "catFillingBlocks" = "FillingBlocks"; "catLineSegments" = "LineSegments"; + +// SwiftUI Preferences +"(Shift+)Space:" = "(Shift+)Space:"; +"An accomodation for elder computer users." = "An accomodation for elder computer users."; +"Apple ABC (equivalent to English US)" = "Apple ABC (equivalent to English US)"; +"Apple Chewing - Dachen" = "Apple Chewing - Dachen"; +"Apple Chewing - Eten Traditional" = "Apple Chewing - Eten Traditional"; +"Apple Dynamic Bopomofo Basic Keyboard Layouts (Dachen & Eten Traditional) must match the Dachen parser in order to be functional." = "Apple Dynamic Bopomofo Basic Keyboard Layouts (Dachen & Eten Traditional) must match the Dachen parser in order to be functional."; +"Auto-convert traditional Chinese glyphs to JIS Shinjitai characters" = "Auto-convert traditional Chinese glyphs to JIS Shinjitai characters"; +"Auto-convert traditional Chinese glyphs to KangXi characters" = "Auto-convert traditional Chinese glyphs to KangXi characters"; +"Automatically reload user data files if changes detected" = "Automatically reload user data files if changes detected"; +"Basic Keyboard Layout:" = "Basic Keyboard Layout:"; +"Candidate Layout:" = "Candidate Layout:"; +"Candidate Size:" = "Candidate Size:"; +"Change user interface language (will reboot the IME)." = "Change user interface language (will reboot the IME)."; +"Check for updates automatically" = "Check for updates automatically"; +"Choose candidate font size for better visual clarity." = "Choose candidate font size for better visual clarity."; +"Choose or hit Enter to confim your prefered keys for selecting candidates." = "Choose or hit Enter to confim your prefered keys for selecting candidates."; +"Choose the behavior of (Shift+)Space key in the candidate window." = "Choose the behavior of (Shift+)Space key in the candidate window."; +"Choose the behavior of (Shift+)Tab key in the candidate window." = "Choose the behavior of (Shift+)Tab key in the candidate window."; +"Choose the cursor position where you want to list possible candidates." = "Choose the cursor position where you want to list possible candidates."; +"Choose the macOS-level basic keyboard layout." = "Choose the macOS-level basic keyboard layout."; +"Choose the phonetic layout for Mandarin parser." = "Choose the phonetic layout for Mandarin parser."; +"Choose your desired user data folder path. Will be omitted if invalid." = "Choose your desired user data folder path. Will be omitted if invalid."; +"Choose your preferred layout of the candidate window." = "Choose your preferred layout of the candidate window."; +"Cursor Selection:" = "Cursor Selection:"; +"Dachen (Microsoft Standard / Wang / 01, etc.)" = "Dachen (Microsoft Standard / Wang / 01, etc.)"; +"Debug Mode" = "Debug Mode"; +"Dictionary" = "Dictionary"; +"Emulating select-candidate-per-character mode" = "Emulating select-candidate-per-character mode"; +"Enable CNS11643 Support (2022-01-27)" = "Enable CNS11643 Support (2022-01-27)"; +"Enable Space key for calling candidate window" = "Enable Space key for calling candidate window"; +"Enable symbol input support (incl. certain emoji symbols)" = "Enable symbol input support (incl. certain emoji symbols)"; +"English" = "English"; +"Eten 26" = "Eten 26"; +"Eten Traditional" = "Eten Traditional"; +"Experience" = "Experience"; +"Fake Seigyou" = "Fake Seigyou"; +"Follow OS settings" = "Follow OS settings"; +"for cycling candidates" = "for cycling candidates"; +"for cycling pages" = "for cycling pages"; +"General" = "General"; +"Hanyu Pinyin with Numeral Intonation" = "Hanyu Pinyin with Numeral Intonation"; +"Horizontal" = "Horizontal"; +"Hsu" = "Hsu"; +"IBM" = "IBM"; +"Japanese" = "Japanese"; +"Keyboard" = "Keyboard"; +"Misc Settings:" = "Misc Settings:"; +"MiTAC" = "MiTAC"; +"Non-QWERTY alphanumeral keyboard layouts are for Hanyu Pinyin parser only." = "Non-QWERTY alphanumeral keyboard layouts are for Hanyu Pinyin parser only."; +"Output Settings:" = "Output Settings:"; +"Phonetic Parser:" = "Phonetic Parser:"; +"Push the cursor to the front of the phrase after selection" = "Push the cursor to the front of the phrase after selection"; +"Selection Keys:" = "Selection Keys:"; +"Show page buttons in candidate window" = "Show page buttons in candidate window"; +"Simplified Chinese" = "Simplified Chinese"; +"Space & ESC Key:" = "Space & ESC Key:"; +"Space to +cycle candidates, Shift+Space to +cycle pages" = "Space to +cycle candidates, Shift+Space to +cycle pages"; +"Space to +cycle pages, Shift+Space to +cycle candidates" = "Space to +cycle pages, Shift+Space to +cycle candidates"; +"Stop farting (when typed phonetic combination is invalid, etc.)" = "Stop farting (when typed phonetic combination is invalid, etc.)"; +"to the front of the phrase (like Matsushita Hanin IME)" = "to the front of the phrase (like Matsushita Hanin IME)"; +"to the rear of the phrase (like MS New-Phonetic IME)" = "to the rear of the phrase (like MS New-Phonetic IME)"; +"Traditional Chinese" = "Traditional Chinese"; +"Typing Style:" = "Typing Style:"; +"UI Language:" = "UI Language:"; +"Use ESC key to clear the entire input buffer" = "Use ESC key to clear the entire input buffer"; +"Vertical" = "Vertical"; diff --git a/Source/Resources/en.lproj/Localizable.strings b/Source/Resources/en.lproj/Localizable.strings index a1ce8b59..540c3ddc 100644 --- a/Source/Resources/en.lproj/Localizable.strings +++ b/Source/Resources/en.lproj/Localizable.strings @@ -73,3 +73,71 @@ "catDoubleTableLines" = "DoubleTableLines"; "catFillingBlocks" = "FillingBlocks"; "catLineSegments" = "LineSegments"; + +// SwiftUI Preferences +"(Shift+)Space:" = "(Shift+)Space:"; +"An accomodation for elder computer users." = "An accomodation for elder computer users."; +"Apple ABC (equivalent to English US)" = "Apple ABC (equivalent to English US)"; +"Apple Chewing - Dachen" = "Apple Chewing - Dachen"; +"Apple Chewing - Eten Traditional" = "Apple Chewing - Eten Traditional"; +"Apple Dynamic Bopomofo Basic Keyboard Layouts (Dachen & Eten Traditional) must match the Dachen parser in order to be functional." = "Apple Dynamic Bopomofo Basic Keyboard Layouts (Dachen & Eten Traditional) must match the Dachen parser in order to be functional."; +"Auto-convert traditional Chinese glyphs to JIS Shinjitai characters" = "Auto-convert traditional Chinese glyphs to JIS Shinjitai characters"; +"Auto-convert traditional Chinese glyphs to KangXi characters" = "Auto-convert traditional Chinese glyphs to KangXi characters"; +"Automatically reload user data files if changes detected" = "Automatically reload user data files if changes detected"; +"Basic Keyboard Layout:" = "Basic Keyboard Layout:"; +"Candidate Layout:" = "Candidate Layout:"; +"Candidate Size:" = "Candidate Size:"; +"Change user interface language (will reboot the IME)." = "Change user interface language (will reboot the IME)."; +"Check for updates automatically" = "Check for updates automatically"; +"Choose candidate font size for better visual clarity." = "Choose candidate font size for better visual clarity."; +"Choose or hit Enter to confim your prefered keys for selecting candidates." = "Choose or hit Enter to confim your prefered keys for selecting candidates."; +"Choose the behavior of (Shift+)Space key in the candidate window." = "Choose the behavior of (Shift+)Space key in the candidate window."; +"Choose the behavior of (Shift+)Tab key in the candidate window." = "Choose the behavior of (Shift+)Tab key in the candidate window."; +"Choose the cursor position where you want to list possible candidates." = "Choose the cursor position where you want to list possible candidates."; +"Choose the macOS-level basic keyboard layout." = "Choose the macOS-level basic keyboard layout."; +"Choose the phonetic layout for Mandarin parser." = "Choose the phonetic layout for Mandarin parser."; +"Choose your desired user data folder path. Will be omitted if invalid." = "Choose your desired user data folder path. Will be omitted if invalid."; +"Choose your preferred layout of the candidate window." = "Choose your preferred layout of the candidate window."; +"Cursor Selection:" = "Cursor Selection:"; +"Dachen (Microsoft Standard / Wang / 01, etc.)" = "Dachen (Microsoft Standard / Wang / 01, etc.)"; +"Debug Mode" = "Debug Mode"; +"Dictionary" = "Dictionary"; +"Emulating select-candidate-per-character mode" = "Emulating select-candidate-per-character mode"; +"Enable CNS11643 Support (2022-01-27)" = "Enable CNS11643 Support (2022-01-27)"; +"Enable Space key for calling candidate window" = "Enable Space key for calling candidate window"; +"Enable symbol input support (incl. certain emoji symbols)" = "Enable symbol input support (incl. certain emoji symbols)"; +"English" = "English"; +"Eten 26" = "Eten 26"; +"Eten Traditional" = "Eten Traditional"; +"Experience" = "Experience"; +"Fake Seigyou" = "Fake Seigyou"; +"Follow OS settings" = "Follow OS settings"; +"for cycling candidates" = "for cycling candidates"; +"for cycling pages" = "for cycling pages"; +"General" = "General"; +"Hanyu Pinyin with Numeral Intonation" = "Hanyu Pinyin with Numeral Intonation"; +"Horizontal" = "Horizontal"; +"Hsu" = "Hsu"; +"IBM" = "IBM"; +"Japanese" = "Japanese"; +"Keyboard" = "Keyboard"; +"Misc Settings:" = "Misc Settings:"; +"MiTAC" = "MiTAC"; +"Non-QWERTY alphanumeral keyboard layouts are for Hanyu Pinyin parser only." = "Non-QWERTY alphanumeral keyboard layouts are for Hanyu Pinyin parser only."; +"Output Settings:" = "Output Settings:"; +"Phonetic Parser:" = "Phonetic Parser:"; +"Push the cursor to the front of the phrase after selection" = "Push the cursor to the front of the phrase after selection"; +"Selection Keys:" = "Selection Keys:"; +"Show page buttons in candidate window" = "Show page buttons in candidate window"; +"Simplified Chinese" = "Simplified Chinese"; +"Space & ESC Key:" = "Space & ESC Key:"; +"Space to +cycle candidates, Shift+Space to +cycle pages" = "Space to +cycle candidates, Shift+Space to +cycle pages"; +"Space to +cycle pages, Shift+Space to +cycle candidates" = "Space to +cycle pages, Shift+Space to +cycle candidates"; +"Stop farting (when typed phonetic combination is invalid, etc.)" = "Stop farting (when typed phonetic combination is invalid, etc.)"; +"to the front of the phrase (like Matsushita Hanin IME)" = "to the front of the phrase (like Matsushita Hanin IME)"; +"to the rear of the phrase (like MS New-Phonetic IME)" = "to the rear of the phrase (like MS New-Phonetic IME)"; +"Traditional Chinese" = "Traditional Chinese"; +"Typing Style:" = "Typing Style:"; +"UI Language:" = "UI Language:"; +"Use ESC key to clear the entire input buffer" = "Use ESC key to clear the entire input buffer"; +"Vertical" = "Vertical"; diff --git a/Source/Resources/ja.lproj/Localizable.strings b/Source/Resources/ja.lproj/Localizable.strings index c5f672a1..8129b74d 100644 --- a/Source/Resources/ja.lproj/Localizable.strings +++ b/Source/Resources/ja.lproj/Localizable.strings @@ -73,3 +73,71 @@ "catDoubleTableLines" = "双線"; "catFillingBlocks" = "ブロック"; "catLineSegments" = "線分"; + +// SwiftUI Preferences +"(Shift+)Space:" = "(Shift+)Space:"; +"An accomodation for elder computer users." = "年配なるユーザーのために提供した機能である。"; +"Apple ABC (equivalent to English US)" = "Apple ABC (Apple U.S. キーボードと同じ)"; +"Apple Chewing - Dachen" = "Apple 大千注音キーボード"; +"Apple Chewing - Eten Traditional" = "Apple 倚天傳統キーボード"; +"Apple Dynamic Bopomofo Basic Keyboard Layouts (Dachen & Eten Traditional) must match the Dachen parser in order to be functional." = "Apple 動態注音キーボード (大千と倚天伝統) を使うには、共通語分析器の配列を大千と設定すべきである。"; +"Auto-convert traditional Chinese glyphs to JIS Shinjitai characters" = "入力した繁体字を日文 JIS 新字体と自動変換"; +"Auto-convert traditional Chinese glyphs to KangXi characters" = "入力した繁体字を康熙字体と自動変換"; +"Automatically reload user data files if changes detected" = "ユーザー辞書データの変更を自動検出し、自動的に再読込"; +"Basic Keyboard Layout:" = "基礎キーボード:"; +"Candidate Layout:" = "入力候補陳列の仕様"; +"Candidate Size:" = "候補文字の字号:"; +"Change user interface language (will reboot the IME)." = "アプリ表示用言語をご指定下さい、そして入力アプリは自動的に再起動。"; +"Check for updates automatically" = "アプリの更新通知を受く"; +"Choose candidate font size for better visual clarity." = "入力候補陳列の候補文字の字号をご指定ください。"; +"Choose or hit Enter to confim your prefered keys for selecting candidates." = "お好きなる言選り用キー陣列をご指定ください。新しい組み合わせは Enter で効かす。"; +"Choose the behavior of (Shift+)Space key in the candidate window." = "入力候補陳列での (Shift+)Space キーの輪番切替対象をご指定ください。"; +"Choose the behavior of (Shift+)Tab key in the candidate window." = "入力候補陳列での (Shift+)Tab キーの輪番切替対象をご指定ください。"; +"Choose the cursor position where you want to list possible candidates." = "カーソルはどこで入力候補を呼び出すかとご指定ださい。"; +"Choose the macOS-level basic keyboard layout." = "macOS 基礎キーボード配置をご指定ください。"; +"Choose the phonetic layout for Mandarin parser." = "共通語分析器の注音配列をご指定ください。"; +"Choose your desired user data folder path. Will be omitted if invalid." = "欲しがるユーザー辞書保存先をご指定ください。無効なる保存先設定は省かれる。"; +"Choose your preferred layout of the candidate window." = "入力候補陳列の仕様をご指定ください。"; +"Cursor Selection:" = "カーソル候補呼出:"; +"Dachen (Microsoft Standard / Wang / 01, etc.)" = "大千配列 (Microsoft 標準・王安・零壹など)"; +"Debug Mode" = "欠陥辿着モード"; +"Dictionary" = "辞書設定"; +"Emulating select-candidate-per-character mode" = "漢字1つづつ全候補選択入力モード"; +"Enable CNS11643 Support (2022-01-27)" = "全字庫モード // 入力可能な漢字数を倍増す (2022-01-07)"; +"Enable Space key for calling candidate window" = "Space キーで入力候補を呼び出す"; +"Enable symbol input support (incl. certain emoji symbols)" = "僅かなる絵文字も含む符号入力サポートを起用"; +"English" = "英語"; +"Eten 26" = "倚天形忘れ配列 (26 キー)"; +"Eten Traditional" = "倚天伝統配列"; +"Experience" = "体験設定"; +"Fake Seigyou" = "偽精業配列"; +"Follow OS settings" = "システム設定に準ず"; +"for cycling candidates" = "候補文字そのもの"; +"for cycling pages" = "候補陳列ページ"; +"General" = "全般設定"; +"Hanyu Pinyin with Numeral Intonation" = "漢語弁音 (ローマ字+数字音調)"; +"Horizontal" = "横型陳列"; +"Hsu" = "許氏国音自然配列"; +"IBM" = "IBM 配列"; +"Japanese" = "和語"; +"Keyboard" = "配列設定"; +"Misc Settings:" = "他の設定:"; +"MiTAC" = "神通配列"; +"Non-QWERTY alphanumeral keyboard layouts are for Hanyu Pinyin parser only." = "QWERTY 以外の英数キーボードは漢語弁音以外の配列に不適用。"; +"Output Settings:" = "出力設定:"; +"Phonetic Parser:" = "注音配列:"; +"Push the cursor to the front of the phrase after selection" = "候補選択の直後、すぐカーソルを単語の向こうに推し進める"; +"Selection Keys:" = "言選り用キー:"; +"Show page buttons in candidate window" = "入力候補陳列の側にページボタンを表示"; +"Simplified Chinese" = "簡体中国語"; +"Space & ESC Key:" = "ESC と Space:"; +"Space to +cycle candidates, Shift+Space to +cycle pages" = "Shift+Space で次のページ、Space で次の候補文字を"; +"Space to +cycle pages, Shift+Space to +cycle candidates" = "Space で次のページ、Shift+Space で次の候補文字を"; +"Stop farting (when typed phonetic combination is invalid, etc.)" = "マナーモード // 外すと入力間違った時に変な声が出る"; +"to the front of the phrase (like Matsushita Hanin IME)" = "単語の前で // パナソニック漢音のやり方"; +"to the rear of the phrase (like MS New-Phonetic IME)" = "単語の後で // Microsoft 新注音のやり方"; +"Traditional Chinese" = "繁体中国語"; +"Typing Style:" = "入力習慣:"; +"UI Language:" = "表示用言語:"; +"Use ESC key to clear the entire input buffer" = "ESC キーで入力緩衝列を消す"; +"Vertical" = "縦型陳列"; diff --git a/Source/Resources/zh-Hans.lproj/Localizable.strings b/Source/Resources/zh-Hans.lproj/Localizable.strings index cc518504..a6dbdc3e 100644 --- a/Source/Resources/zh-Hans.lproj/Localizable.strings +++ b/Source/Resources/zh-Hans.lproj/Localizable.strings @@ -73,3 +73,71 @@ "catDoubleTableLines" = "双线"; "catFillingBlocks" = "填色"; "catLineSegments" = "线段"; + +// SwiftUI Preferences +"(Shift+)Space:" = "(Shift+)空格键:"; +"An accomodation for elder computer users." = "针对年长使用者的习惯而提供。"; +"Apple ABC (equivalent to English US)" = "Apple ABC (与 Apple 美规键盘等价)"; +"Apple Chewing - Dachen" = "Apple 大千注音键盘配列"; +"Apple Chewing - Eten Traditional" = "Apple 倚天传统键盘配列"; +"Apple Dynamic Bopomofo Basic Keyboard Layouts (Dachen & Eten Traditional) must match the Dachen parser in order to be functional." = "Apple 动态注音键盘布局(大千与倚天)要求普通话/国音分析器得配置为大千配列。"; +"Auto-convert traditional Chinese glyphs to JIS Shinjitai characters" = "自动将繁体中文字转为日文 JIS 新字体"; +"Auto-convert traditional Chinese glyphs to KangXi characters" = "自动将繁体中文字转为康熙字"; +"Automatically reload user data files if changes detected" = "自动检测并载入使用者语汇档案变更"; +"Basic Keyboard Layout:" = "基础键盘布局:"; +"Candidate Layout:" = "候选字窗布局:"; +"Candidate Size:" = "候选字窗字号:"; +"Change user interface language (will reboot the IME)." = "变更输入法介面语言,会自动重启输入法。"; +"Check for updates automatically" = "自动检查软体更新"; +"Choose candidate font size for better visual clarity." = "变更候选字窗的字型大小。"; +"Choose or hit Enter to confim your prefered keys for selecting candidates." = "请选择您所偏好的用来选字的按键组合。自订组合需敲 Enter 键生效。"; +"Choose the behavior of (Shift+)Space key in the candidate window." = "指定 (Shift+)空格键 在选字窗内的轮替操作对象。"; +"Choose the behavior of (Shift+)Tab key in the candidate window." = "指定 (Shift+)Tab 在选字窗内的轮替操作对象。"; +"Choose the cursor position where you want to list possible candidates." = "请选择用以触发选字的游标相对位置。"; +"Choose the macOS-level basic keyboard layout." = "请选择 macOS 基础键盘布局。"; +"Choose the phonetic layout for Mandarin parser." = "请指定普通话/国音分析器所使用的注音配列。"; +"Choose your desired user data folder path. Will be omitted if invalid." = "请在此指定您想指定的使用者语汇档案目录。无效值会被忽略。"; +"Choose your preferred layout of the candidate window." = "选择您所偏好的候选字窗布局。"; +"Cursor Selection:" = "选字游标:"; +"Dachen (Microsoft Standard / Wang / 01, etc.)" = "大千配列 (微软标准/王安/零壹/仲鼎/国乔)"; +"Debug Mode" = "侦错模式"; +"Dictionary" = "辞典"; +"Emulating select-candidate-per-character mode" = "模拟 90 年代前期注音逐字选字输入风格"; +"Enable CNS11643 Support (2022-01-27)" = "启用 CNS11643 全字库支援 (2022-01-07)"; +"Enable Space key for calling candidate window" = "敲空格键以呼出候选字窗"; +"Enable symbol input support (incl. certain emoji symbols)" = "启用包括少许绘文字在内的符号输入支援"; +"English" = "英语"; +"Eten 26" = "倚天忘形配列 (26 键)"; +"Eten Traditional" = "倚天传统配列"; +"Experience" = "体验"; +"Fake Seigyou" = "伪精业配列"; +"Follow OS settings" = "依系统设定"; +"for cycling candidates" = "轮替候选字"; +"for cycling pages" = "轮替页面"; +"General" = "通用"; +"Hanyu Pinyin with Numeral Intonation" = "汉语拼音+数字标调"; +"Horizontal" = "横向布局"; +"Hsu" = "许氏国音自然配列"; +"IBM" = "IBM 配列"; +"Japanese" = "和语"; +"Keyboard" = "键盘"; +"Misc Settings:" = "杂项:"; +"MiTAC" = "神通配列"; +"Non-QWERTY alphanumeral keyboard layouts are for Hanyu Pinyin parser only." = "QWERTY 以外的英数布局是为了汉语拼音配列使用者而准备的。"; +"Output Settings:" = "输出设定:"; +"Phonetic Parser:" = "注音配列:"; +"Push the cursor to the front of the phrase after selection" = "在选字后将游标置于该字词的前方"; +"Selection Keys:" = "选字键:"; +"Show page buttons in candidate window" = "在选字窗内显示翻页按钮"; +"Simplified Chinese" = "简体中文"; +"Space & ESC Key:" = "ESC 与空格键:"; +"Space to +cycle candidates, Shift+Space to +cycle pages" = "Shift+空格键 换下一页,空格键 换选下一个后选字"; +"Space to +cycle pages, Shift+Space to +cycle candidates" = "空格键 换下一页,Shift+空格键 换选下一个后选字"; +"Stop farting (when typed phonetic combination is invalid, etc.)" = "不要放屁 // 例:当输入的音韵有误时,等"; +"to the front of the phrase (like Matsushita Hanin IME)" = "将游标置于词语前方 // 松下汉音风格"; +"to the rear of the phrase (like MS New-Phonetic IME)" = "将游标置于词语后方 // 微软新注音风格"; +"Traditional Chinese" = "繁体中文"; +"Typing Style:" = "输入风格:"; +"UI Language:" = "介面语言:"; +"Use ESC key to clear the entire input buffer" = "敲 ESC 键以清空整个组字缓冲区"; +"Vertical" = "纵向布局"; diff --git a/Source/Resources/zh-Hant.lproj/Localizable.strings b/Source/Resources/zh-Hant.lproj/Localizable.strings index 6f789838..98ff5818 100644 --- a/Source/Resources/zh-Hant.lproj/Localizable.strings +++ b/Source/Resources/zh-Hant.lproj/Localizable.strings @@ -73,3 +73,71 @@ "catDoubleTableLines" = "雙線"; "catFillingBlocks" = "填色"; "catLineSegments" = "線段"; + +// SwiftUI Preferences +"(Shift+)Space:" = "(Shift+)空格鍵:"; +"An accomodation for elder computer users." = "針對年長使用者的習慣而提供。"; +"Apple ABC (equivalent to English US)" = "Apple ABC (與 Apple 美規鍵盤等價)"; +"Apple Chewing - Dachen" = "Apple 大千注音鍵盤佈局"; +"Apple Chewing - Eten Traditional" = "Apple 倚天傳統鍵盤佈局"; +"Apple Dynamic Bopomofo Basic Keyboard Layouts (Dachen & Eten Traditional) must match the Dachen parser in order to be functional." = "Apple 動態注音鍵盤佈局(大千與倚天)要求普通話/國音分析器得配置為大千配列。"; +"Auto-convert traditional Chinese glyphs to JIS Shinjitai characters" = "自動將繁體中文字轉為日文 JIS 新字體"; +"Auto-convert traditional Chinese glyphs to KangXi characters" = "自動將繁體中文字轉為康熙字"; +"Automatically reload user data files if changes detected" = "自動檢測並載入使用者語彙檔案變更"; +"Basic Keyboard Layout:" = "基礎鍵盤佈局:"; +"Candidate Layout:" = "候選字窗佈局:"; +"Candidate Size:" = "候選字窗字號:"; +"Change user interface language (will reboot the IME)." = "變更輸入法介面語言,會自動重啟輸入法。"; +"Check for updates automatically" = "自動檢查軟體更新"; +"Choose candidate font size for better visual clarity." = "變更候選字窗的字型大小。"; +"Choose or hit Enter to confim your prefered keys for selecting candidates." = "請選擇您所偏好的用來選字的按鍵組合。自訂組合需敲 Enter 鍵生效。"; +"Choose the behavior of (Shift+)Space key in the candidate window." = "指定 (Shift+)空格鍵 在選字窗內的輪替操作對象。"; +"Choose the behavior of (Shift+)Tab key in the candidate window." = "指定 (Shift+)Tab 在選字窗內的輪替操作對象。"; +"Choose the cursor position where you want to list possible candidates." = "請選擇用以觸發選字的游標相對位置。"; +"Choose the macOS-level basic keyboard layout." = "請選擇 macOS 基礎鍵盤佈局。"; +"Choose the phonetic layout for Mandarin parser." = "請指定普通話/國音分析器所使用的注音配列。"; +"Choose your desired user data folder path. Will be omitted if invalid." = "請在此指定您想指定的使用者語彙檔案目錄。無效值會被忽略。"; +"Choose your preferred layout of the candidate window." = "選擇您所偏好的候選字窗佈局。"; +"Cursor Selection:" = "選字游標:"; +"Dachen (Microsoft Standard / Wang / 01, etc.)" = "大千配列 (微軟標準/王安/零壹/仲鼎/國喬)"; +"Debug Mode" = "偵錯模式"; +"Dictionary" = "辭典"; +"Emulating select-candidate-per-character mode" = "模擬 90 年代前期注音逐字選字輸入風格"; +"Enable CNS11643 Support (2022-01-27)" = "啟用 CNS11643 全字庫支援 (2022-01-07)"; +"Enable Space key for calling candidate window" = "敲空格鍵以呼出候選字窗"; +"Enable symbol input support (incl. certain emoji symbols)" = "啟用包括少許繪文字在內的符號輸入支援"; +"English" = "英語"; +"Eten 26" = "倚天忘形配列 (26 鍵)"; +"Eten Traditional" = "倚天傳統配列"; +"Experience" = "體驗"; +"Fake Seigyou" = "偽精業配列"; +"Follow OS settings" = "依系統設定"; +"for cycling candidates" = "輪替候選字"; +"for cycling pages" = "輪替頁面"; +"General" = "通用"; +"Hanyu Pinyin with Numeral Intonation" = "漢語拼音+數字標調"; +"Horizontal" = "橫向佈局"; +"Hsu" = "許氏國音自然配列"; +"IBM" = "IBM 配列"; +"Japanese" = "和語"; +"Keyboard" = "鍵盤"; +"Misc Settings:" = "雜項:"; +"MiTAC" = "神通配列"; +"Non-QWERTY alphanumeral keyboard layouts are for Hanyu Pinyin parser only." = "QWERTY 以外的英數佈局是為了漢語拼音配列使用者而準備的。"; +"Output Settings:" = "輸出設定:"; +"Phonetic Parser:" = "注音配列:"; +"Push the cursor to the front of the phrase after selection" = "在選字後將游標置於該字詞的前方"; +"Selection Keys:" = "選字鍵:"; +"Show page buttons in candidate window" = "在選字窗內顯示翻頁按鈕"; +"Simplified Chinese" = "簡體中文"; +"Space & ESC Key:" = "ESC 與空格鍵:"; +"Space to +cycle candidates, Shift+Space to +cycle pages" = "Shift+空格鍵 換下一頁,空格鍵 換選下一個後選字"; +"Space to +cycle pages, Shift+Space to +cycle candidates" = "空格鍵 換下一頁,Shift+空格鍵 換選下一個後選字"; +"Stop farting (when typed phonetic combination is invalid, etc.)" = "不要放屁 // 例:當輸入的音韻有誤時,等"; +"to the front of the phrase (like Matsushita Hanin IME)" = "將游標置於詞語前方 // 松下漢音風格"; +"to the rear of the phrase (like MS New-Phonetic IME)" = "將游標置於詞語後方 // 微軟新注音風格"; +"Traditional Chinese" = "繁體中文"; +"Typing Style:" = "輸入風格:"; +"UI Language:" = "介面語言:"; +"Use ESC key to clear the entire input buffer" = "敲 ESC 鍵以清空整個組字緩衝區"; +"Vertical" = "縱向佈局"; diff --git a/Source/UI/CandidateUI/ctlCandidateHorizontal.swift b/Source/UI/CandidateUI/ctlCandidateHorizontal.swift index 027703e9..e2e78b23 100644 --- a/Source/UI/CandidateUI/ctlCandidateHorizontal.swift +++ b/Source/UI/CandidateUI/ctlCandidateHorizontal.swift @@ -435,10 +435,9 @@ extension ctlCandidateHorizontal { frameRect = window?.frame ?? NSRect.zero - let topLeftPoint = NSMakePoint( - frameRect.origin.x, frameRect.origin.y + frameRect.size.height) + let topLeftPoint = NSPoint(x: frameRect.origin.x, y: frameRect.origin.y + frameRect.size.height) frameRect.size = newSize - frameRect.origin = NSMakePoint(topLeftPoint.x, topLeftPoint.y - frameRect.size.height) + frameRect.origin = NSPoint(x: topLeftPoint.x, y: topLeftPoint.y - frameRect.size.height) self.window?.setFrame(frameRect, display: false) candidateView.setNeedsDisplay(candidateView.bounds) } diff --git a/Source/UI/CandidateUI/ctlCandidateVertical.swift b/Source/UI/CandidateUI/ctlCandidateVertical.swift index 8e5c4cd5..dfeb93f7 100644 --- a/Source/UI/CandidateUI/ctlCandidateVertical.swift +++ b/Source/UI/CandidateUI/ctlCandidateVertical.swift @@ -440,10 +440,9 @@ extension ctlCandidateVertical { frameRect = window?.frame ?? NSRect.zero - let topLeftPoint = NSMakePoint( - frameRect.origin.x, frameRect.origin.y + frameRect.size.height) + let topLeftPoint = NSPoint(x: frameRect.origin.x, y: frameRect.origin.y + frameRect.size.height) frameRect.size = newSize - frameRect.origin = NSMakePoint(topLeftPoint.x, topLeftPoint.y - frameRect.size.height) + frameRect.origin = NSPoint(x: topLeftPoint.x, y: topLeftPoint.y - frameRect.size.height) self.window?.setFrame(frameRect, display: false) candidateView.setNeedsDisplay(candidateView.bounds) } diff --git a/Source/UI/PrefUI/ctlPrefUI.swift b/Source/UI/PrefUI/ctlPrefUI.swift new file mode 100644 index 00000000..048f43f4 --- /dev/null +++ b/Source/UI/PrefUI/ctlPrefUI.swift @@ -0,0 +1,71 @@ +// Copyright (c) 2021 and onwards The vChewing Project (MIT-NTL License). +/* +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal in +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of +the Software, and to permit persons to whom the Software is furnished to do so, +subject to the following conditions: + +1. The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +2. 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 above. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +*/ + +import Cocoa + +@available(macOS 11.0, *) +class ctlPrefUI { + lazy var controller = PreferencesWindowController( + panes: [ + Preferences.Pane( + identifier: Preferences.PaneIdentifier(rawValue: "General"), + title: NSLocalizedString("General", comment: ""), + toolbarIcon: NSImage( + systemSymbolName: "wrench.and.screwdriver.fill", accessibilityDescription: "General Preferences") + ?? NSImage(named: NSImage.homeTemplateName)! + ) { + suiPrefPaneGeneral() + }, + Preferences.Pane( + identifier: Preferences.PaneIdentifier(rawValue: "Experiences"), + title: NSLocalizedString("Experience", comment: ""), + toolbarIcon: NSImage( + systemSymbolName: "person.fill.questionmark", accessibilityDescription: "Experiences Preferences") + ?? NSImage(named: NSImage.listViewTemplateName)! + ) { + suiPrefPaneExperience() + }, + Preferences.Pane( + identifier: Preferences.PaneIdentifier(rawValue: "Dictionary"), + title: NSLocalizedString("Dictionary", comment: ""), + toolbarIcon: NSImage( + systemSymbolName: "character.book.closed.fill", accessibilityDescription: "Dictionary Preferences") + ?? NSImage(named: NSImage.bookmarksTemplateName)! + ) { + suiPrefPaneDictionary() + }, + Preferences.Pane( + identifier: Preferences.PaneIdentifier(rawValue: "Keyboard"), + title: NSLocalizedString("Keyboard", comment: ""), + toolbarIcon: NSImage( + systemSymbolName: "keyboard.macwindow", accessibilityDescription: "Keyboard Preferences") + ?? NSImage(named: NSImage.actionTemplateName)! + ) { + suiPrefPaneKeyboard() + }, + ], + style: .toolbarItems + ) + static let shared = ctlPrefUI() +} diff --git a/Source/UI/PrefUI/suiPrefPaneDictionary.swift b/Source/UI/PrefUI/suiPrefPaneDictionary.swift new file mode 100644 index 00000000..c99cf168 --- /dev/null +++ b/Source/UI/PrefUI/suiPrefPaneDictionary.swift @@ -0,0 +1,126 @@ +// Copyright (c) 2021 and onwards The vChewing Project (MIT-NTL License). +/* +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal in +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of +the Software, and to permit persons to whom the Software is furnished to do so, +subject to the following conditions: + +1. The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +2. 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 above. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +*/ + +import SwiftUI + +@available(macOS 11.0, *) +struct suiPrefPaneDictionary: View { + private var fdrDefault = mgrLangModel.dataFolderPath(isDefaultFolder: true) + @State private var tbxUserDataPathSpecified: String = + UserDefaults.standard.string(forKey: UserDef.kUserDataFolderSpecified) + ?? mgrLangModel.dataFolderPath(isDefaultFolder: true) + @State private var selAutoReloadUserData: Bool = UserDefaults.standard.bool( + forKey: UserDef.kShouldAutoReloadUserDataFiles) + @State private var selEnableCNS11643: Bool = UserDefaults.standard.bool(forKey: UserDef.kCNS11643Enabled) + @State private var selEnableSymbolInputSupport: Bool = UserDefaults.standard.bool( + forKey: UserDef.kSymbolInputEnabled) + private let contentWidth: Double = 560.0 + + var body: some View { + Preferences.Container(contentWidth: contentWidth) { + Preferences.Section(title: "", bottomDivider: true) { + Text(LocalizedStringKey("Choose your desired user data folder path. Will be omitted if invalid.")) + HStack { + TextField(fdrDefault, text: $tbxUserDataPathSpecified).disabled(true) + .help(tbxUserDataPathSpecified) + Button { + IME.dlgOpenPath.title = NSLocalizedString( + "Choose your desired user data folder.", comment: "") + IME.dlgOpenPath.showsResizeIndicator = true + IME.dlgOpenPath.showsHiddenFiles = true + IME.dlgOpenPath.canChooseFiles = false + IME.dlgOpenPath.canChooseDirectories = true + + let bolPreviousFolderValidity = mgrLangModel.checkIfSpecifiedUserDataFolderValid( + NSString(string: mgrPrefs.userDataFolderSpecified).expandingTildeInPath) + + if let window = ctlPrefUI.shared.controller.window { + IME.dlgOpenPath.beginSheetModal(for: window) { result in + if result == NSApplication.ModalResponse.OK { + if IME.dlgOpenPath.url != nil { + // CommonDialog 讀入的路徑沒有結尾斜槓,這會導致檔案目錄合規性判定失準。 + // 所以要手動補回來。 + var newPath = IME.dlgOpenPath.url!.path + newPath.ensureTrailingSlash() + if mgrLangModel.checkIfSpecifiedUserDataFolderValid(newPath) { + mgrPrefs.userDataFolderSpecified = newPath + tbxUserDataPathSpecified = mgrPrefs.userDataFolderSpecified + IME.initLangModels(userOnly: true) + } else { + clsSFX.beep() + if !bolPreviousFolderValidity { + mgrPrefs.resetSpecifiedUserDataFolder() + } + return + } + } + } else { + if !bolPreviousFolderValidity { + mgrPrefs.resetSpecifiedUserDataFolder() + } + return + } + } + } // End If self.window != nil + } label: { + Text("...") + } + Button { + mgrPrefs.resetSpecifiedUserDataFolder() + tbxUserDataPathSpecified = "" + } label: { + Text("↻") + } + + } + Toggle( + LocalizedStringKey("Automatically reload user data files if changes detected"), + isOn: $selAutoReloadUserData + ).controlSize(.small).onChange(of: selAutoReloadUserData) { (value) in + mgrPrefs.shouldAutoReloadUserDataFiles = value + } + Divider() + Toggle(LocalizedStringKey("Enable CNS11643 Support (2022-01-27)"), isOn: $selEnableCNS11643) + .onChange(of: selEnableCNS11643) { (value) in + mgrPrefs.cns11643Enabled = value + } + Toggle( + LocalizedStringKey("Enable symbol input support (incl. certain emoji symbols)"), + isOn: $selEnableSymbolInputSupport + ) + .onChange(of: selEnableSymbolInputSupport) { (value) in + mgrPrefs.symbolInputEnabled = value + } + + } + } + } +} + +@available(macOS 11.0, *) +struct suiPrefPaneDictionary_Previews: PreviewProvider { + static var previews: some View { + suiPrefPaneDictionary() + } +} diff --git a/Source/UI/PrefUI/suiPrefPaneExperience.swift b/Source/UI/PrefUI/suiPrefPaneExperience.swift new file mode 100644 index 00000000..55c40fc8 --- /dev/null +++ b/Source/UI/PrefUI/suiPrefPaneExperience.swift @@ -0,0 +1,155 @@ +// Copyright (c) 2021 and onwards The vChewing Project (MIT-NTL License). +/* +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal in +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of +the Software, and to permit persons to whom the Software is furnished to do so, +subject to the following conditions: + +1. The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +2. 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 above. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +*/ + +import Cocoa +import SwiftUI + +@available(macOS 11.0, *) +struct suiPrefPaneExperience: View { + @State private var selSelectionKeysList = mgrPrefs.suggestedCandidateKeys + @State private var selSelectionKeys = + (UserDefaults.standard.string(forKey: UserDef.kCandidateKeys) ?? mgrPrefs.defaultCandidateKeys) as String + @State private var selCursorPosition = + UserDefaults.standard.bool( + forKey: UserDef.kSelectPhraseAfterCursorAsCandidate) ? 1 : 0 + @State private var selPushCursorAfterSelection = UserDefaults.standard.bool( + forKey: UserDef.kMoveCursorAfterSelectingCandidate) + @State private var selKeyBehaviorShiftTab = + UserDefaults.standard.bool(forKey: UserDef.kSpecifyShiftTabKeyBehavior) ? 1 : 0 + @State private var selKeyBehaviorShiftSpace = + UserDefaults.standard.bool( + forKey: UserDef.kSpecifyShiftSpaceKeyBehavior) ? 1 : 0 + @State private var selKeyBehaviorSpaceForCallingCandidate = UserDefaults.standard.bool( + forKey: UserDef.kChooseCandidateUsingSpace) + @State private var selKeyBehaviorESCForClearingTheBuffer = UserDefaults.standard.bool( + forKey: UserDef.kEscToCleanInputBuffer) + @State private var selEnableSCPCTypingMode = UserDefaults.standard.bool(forKey: UserDef.kUseSCPCTypingMode) + private let contentWidth: Double = 560.0 + + var body: some View { + Preferences.Container(contentWidth: contentWidth) { + Preferences.Section(bottomDivider: true, label: { Text(LocalizedStringKey("Selection Keys:")) }) { + ComboBox(items: mgrPrefs.suggestedCandidateKeys, text: $selSelectionKeys).frame(width: 180).onChange( + of: selSelectionKeys + ) { (value) in + let keys: String = (value.trimmingCharacters(in: .whitespacesAndNewlines) as String).charDeDuplicate + do { + try mgrPrefs.validate(candidateKeys: keys) + mgrPrefs.candidateKeys = keys + selSelectionKeys = mgrPrefs.candidateKeys + } catch mgrPrefs.CandidateKeyError.empty { + selSelectionKeys = mgrPrefs.candidateKeys + } catch { + if let window = ctlPrefUI.shared.controller.window { + let alert = NSAlert(error: error) + alert.beginSheetModal(for: window) { _ in + selSelectionKeys = mgrPrefs.candidateKeys + } + clsSFX.beep() + } + } + } + Text( + LocalizedStringKey( + "Choose or hit Enter to confim your prefered keys for selecting candidates." + ) + ) + .preferenceDescription() + } + Preferences.Section(bottomDivider: true, label: { Text(LocalizedStringKey("Cursor Selection:")) }) { + Picker("", selection: $selCursorPosition) { + Text(LocalizedStringKey("to the front of the phrase (like Matsushita Hanin IME)")).tag(0) + Text(LocalizedStringKey("to the rear of the phrase (like MS New-Phonetic IME)")).tag(1) + }.onChange(of: selCursorPosition) { (value) in + mgrPrefs.selectPhraseAfterCursorAsCandidate = (value == 1) ? true : false + } + .labelsHidden() + .pickerStyle(RadioGroupPickerStyle()) + Text(LocalizedStringKey("Choose the cursor position where you want to list possible candidates.")) + .preferenceDescription() + Toggle( + LocalizedStringKey("Push the cursor to the front of the phrase after selection"), + isOn: $selPushCursorAfterSelection + ).onChange(of: selPushCursorAfterSelection) { (value) in + mgrPrefs.moveCursorAfterSelectingCandidate = value + }.controlSize(.small) + } + Preferences.Section(title: "(Shift+)Tab:", bottomDivider: true) { + Picker("", selection: $selKeyBehaviorShiftTab) { + Text(LocalizedStringKey("for cycling candidates")).tag(0) + Text(LocalizedStringKey("for cycling pages")).tag(1) + }.onChange(of: selKeyBehaviorShiftTab) { (value) in + mgrPrefs.specifyShiftTabKeyBehavior = (value == 1) ? true : false + } + .labelsHidden() + .horizontalRadioGroupLayout() + .pickerStyle(RadioGroupPickerStyle()) + Text(LocalizedStringKey("Choose the behavior of (Shift+)Tab key in the candidate window.")) + .preferenceDescription() + } + Preferences.Section(bottomDivider: true, label: { Text(LocalizedStringKey("(Shift+)Space:")) }) { + Picker("", selection: $selKeyBehaviorShiftSpace) { + Text(LocalizedStringKey("Space to +cycle candidates, Shift+Space to +cycle pages")).tag(0) + Text(LocalizedStringKey("Space to +cycle pages, Shift+Space to +cycle candidates")).tag(1) + }.onChange(of: selKeyBehaviorShiftSpace) { (value) in + mgrPrefs.specifyShiftSpaceKeyBehavior = (value == 1) ? true : false + } + .labelsHidden() + .pickerStyle(RadioGroupPickerStyle()) + Text(LocalizedStringKey("Choose the behavior of (Shift+)Space key in the candidate window.")) + .preferenceDescription() + } + Preferences.Section(bottomDivider: true, label: { Text(LocalizedStringKey("Space & ESC Key:")) }) { + Toggle( + LocalizedStringKey("Enable Space key for calling candidate window"), + isOn: $selKeyBehaviorSpaceForCallingCandidate + ).onChange(of: selKeyBehaviorSpaceForCallingCandidate) { (value) in + mgrPrefs.chooseCandidateUsingSpace = value + } + Toggle( + LocalizedStringKey("Use ESC key to clear the entire input buffer"), + isOn: $selKeyBehaviorESCForClearingTheBuffer + ).onChange(of: selKeyBehaviorESCForClearingTheBuffer) { (value) in + mgrPrefs.escToCleanInputBuffer = value + } + } + Preferences.Section(label: { Text(LocalizedStringKey("Typing Style:")) }) { + Toggle( + LocalizedStringKey("Emulating select-candidate-per-character mode"), isOn: $selEnableSCPCTypingMode + ).onChange(of: selEnableSCPCTypingMode) { (value) in + mgrPrefs.useSCPCTypingMode = value + } + Text(LocalizedStringKey("An accomodation for elder computer users.")) + .preferenceDescription() + } + } + } +} + +@available(macOS 11.0, *) +struct suiPrefPaneExperience_Previews: PreviewProvider { + static var previews: some View { + suiPrefPaneExperience() + } +} diff --git a/Source/UI/PrefUI/suiPrefPaneGeneral.swift b/Source/UI/PrefUI/suiPrefPaneGeneral.swift new file mode 100644 index 00000000..d8b544bc --- /dev/null +++ b/Source/UI/PrefUI/suiPrefPaneGeneral.swift @@ -0,0 +1,158 @@ +// Copyright (c) 2021 and onwards The vChewing Project (MIT-NTL License). +/* +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal in +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of +the Software, and to permit persons to whom the Software is furnished to do so, +subject to the following conditions: + +1. The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +2. 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 above. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +*/ + +import Cocoa +import SwiftUI + +@available(macOS 11.0, *) +struct suiPrefPaneGeneral: View { + @State private var selCandidateUIFontSize = UserDefaults.standard.integer(forKey: UserDef.kCandidateListTextSize) + @State private var selUILanguage: [String] = + IME.arrSupportedLocales.contains( + ((UserDefaults.standard.object(forKey: UserDef.kAppleLanguages) == nil) + ? ["auto"] : UserDefaults.standard.array(forKey: UserDef.kAppleLanguages) as? [String] ?? ["auto"])[0]) + ? ((UserDefaults.standard.object(forKey: UserDef.kAppleLanguages) == nil) + ? ["auto"] : UserDefaults.standard.array(forKey: UserDef.kAppleLanguages) as? [String] ?? ["auto"]) + : ["auto"] + @State private var selEnableHorizontalCandidateLayout = UserDefaults.standard.bool( + forKey: UserDef.kUseHorizontalCandidateList) + @State private var selShowPageButtonsInCandidateUI = UserDefaults.standard.bool( + forKey: UserDef.kShowPageButtonsInCandidateWindow) + @State private var selEnableKanjiConvToKangXi = UserDefaults.standard.bool( + forKey: UserDef.kChineseConversionEnabled) + @State private var selEnableKanjiConvToJIS = UserDefaults.standard.bool( + forKey: UserDef.kShiftJISShinjitaiOutputEnabled) + @State private var selEnableFartSuppressor = UserDefaults.standard.bool(forKey: UserDef.kShouldNotFartInLieuOfBeep) + @State private var selEnableAutoUpdateCheck = UserDefaults.standard.bool(forKey: UserDef.kCheckUpdateAutomatically) + @State private var selEnableDebugMode = UserDefaults.standard.bool(forKey: UserDef.kIsDebugModeEnabled) + + private let contentWidth: Double = 560.0 + + var body: some View { + Preferences.Container(contentWidth: contentWidth) { + Preferences.Section(bottomDivider: false, label: { Text(LocalizedStringKey("Candidate Size:")) }) { + Picker("", selection: $selCandidateUIFontSize) { + Text("12").tag(12) + Text("14").tag(14) + Text("16").tag(16) + Text("18").tag(18) + Text("24").tag(24) + Text("32").tag(32) + Text("64").tag(64) + Text("96").tag(96) + }.onChange(of: selCandidateUIFontSize) { (value) in + mgrPrefs.candidateListTextSize = CGFloat(value) + } + .labelsHidden() + .frame(width: 120.0) + Text(LocalizedStringKey("Choose candidate font size for better visual clarity.")) + .preferenceDescription() + } + Preferences.Section(bottomDivider: false, label: { Text(LocalizedStringKey("UI Language:")) }) { + Picker(LocalizedStringKey("Follow OS settings"), selection: $selUILanguage) { + Text(LocalizedStringKey("Follow OS settings")).tag(["auto"]) + Text(LocalizedStringKey("Simplified Chinese")).tag(["zh-Hans"]) + Text(LocalizedStringKey("Traditional Chinese")).tag(["zh-Hant"]) + Text(LocalizedStringKey("Japanese")).tag(["ja"]) + Text(LocalizedStringKey("English")).tag(["en"]) + }.onChange(of: selUILanguage) { (value) in + IME.prtDebugIntel(value[0]) + if selUILanguage == mgrPrefs.appleLanguages + || (selUILanguage[0] == "auto" + && UserDefaults.standard.object(forKey: UserDef.kAppleLanguages) == nil) + { + return + } + if selUILanguage[0] != "auto" { + mgrPrefs.appleLanguages = value + } else { + UserDefaults.standard.removeObject(forKey: UserDef.kAppleLanguages) + } + NSLog("vChewing App self-terminated due to UI language change.") + NSApplication.shared.terminate(nil) + } + .labelsHidden() + .frame(width: 180.0) + + Text(LocalizedStringKey("Change user interface language (will reboot the IME).")) + .preferenceDescription() + } + Preferences.Section(bottomDivider: true, label: { Text(LocalizedStringKey("Candidate Layout:")) }) { + Picker("", selection: $selEnableHorizontalCandidateLayout) { + Text(LocalizedStringKey("Vertical")).tag(false) + Text(LocalizedStringKey("Horizontal")).tag(true) + }.onChange(of: selEnableHorizontalCandidateLayout) { (value) in + mgrPrefs.useHorizontalCandidateList = value + } + .labelsHidden() + .horizontalRadioGroupLayout() + .pickerStyle(RadioGroupPickerStyle()) + Text(LocalizedStringKey("Choose your preferred layout of the candidate window.")) + .preferenceDescription() + Toggle( + LocalizedStringKey("Show page buttons in candidate window"), isOn: $selShowPageButtonsInCandidateUI + ).controlSize(.small) + } + Preferences.Section(bottomDivider: true, label: { Text(LocalizedStringKey("Output Settings:")) }) { + Toggle( + LocalizedStringKey("Auto-convert traditional Chinese glyphs to KangXi characters"), + isOn: $selEnableKanjiConvToKangXi + ).onChange(of: selEnableKanjiConvToKangXi) { (value) in + mgrPrefs.chineseConversionEnabled = value + } + Toggle( + LocalizedStringKey("Auto-convert traditional Chinese glyphs to JIS Shinjitai characters"), + isOn: $selEnableKanjiConvToJIS + ).onChange(of: selEnableKanjiConvToJIS) { (value) in + mgrPrefs.shiftJISShinjitaiOutputEnabled = value + } + Toggle( + LocalizedStringKey("Stop farting (when typed phonetic combination is invalid, etc.)"), + isOn: $selEnableFartSuppressor + ).onChange(of: selEnableFartSuppressor) { (value) in + mgrPrefs.shouldNotFartInLieuOfBeep = value + clsSFX.beep() + } + } + Preferences.Section(label: { Text(LocalizedStringKey("Misc Settings:")).controlSize(.small) }) { + Toggle(LocalizedStringKey("Check for updates automatically"), isOn: $selEnableAutoUpdateCheck) + .onChange(of: selEnableAutoUpdateCheck) { (value) in + mgrPrefs.checkUpdateAutomatically = value + } + .controlSize(.small) + Toggle(LocalizedStringKey("Debug Mode"), isOn: $selEnableDebugMode).controlSize(.small) + .onChange(of: selEnableDebugMode) { (value) in + mgrPrefs.isDebugModeEnabled = value + } + } + } + } +} + +@available(macOS 11.0, *) +struct suiPrefPaneGeneral_Previews: PreviewProvider { + static var previews: some View { + suiPrefPaneGeneral() + } +} diff --git a/Source/UI/PrefUI/suiPrefPaneKeyboard.swift b/Source/UI/PrefUI/suiPrefPaneKeyboard.swift new file mode 100644 index 00000000..93772500 --- /dev/null +++ b/Source/UI/PrefUI/suiPrefPaneKeyboard.swift @@ -0,0 +1,98 @@ +// Copyright (c) 2021 and onwards The vChewing Project (MIT-NTL License). +/* +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal in +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of +the Software, and to permit persons to whom the Software is furnished to do so, +subject to the following conditions: + +1. The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +2. 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 above. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +*/ + +import SwiftUI + +@available(macOS 11.0, *) +struct suiPrefPaneKeyboard: View { + @State private var selMandarinParser = UserDefaults.standard.integer(forKey: UserDef.kMandarinParser) + @State private var selBasicKeyboardLayout: String = + UserDefaults.standard.string(forKey: UserDef.kBasicKeyboardLayout) ?? mgrPrefs.basicKeyboardLayout + private let contentWidth: Double = 560.0 + + var body: some View { + Preferences.Container(contentWidth: contentWidth) { + Preferences.Section(label: { Text(LocalizedStringKey("Phonetic Parser:")) }) { + Picker("", selection: $selMandarinParser) { + Text(LocalizedStringKey("Dachen (Microsoft Standard / Wang / 01, etc.)")).tag(0) + Text(LocalizedStringKey("Eten Traditional")).tag(1) + Text(LocalizedStringKey("Eten 26")).tag(3) + Text(LocalizedStringKey("IBM")).tag(4) + Text(LocalizedStringKey("Hsu")).tag(2) + Text(LocalizedStringKey("MiTAC")).tag(5) + Text(LocalizedStringKey("Fake Seigyou")).tag(6) + Text(LocalizedStringKey("Hanyu Pinyin with Numeral Intonation")).tag(10) + }.onChange(of: selMandarinParser) { (value) in + mgrPrefs.mandarinParser = value + } + .labelsHidden() + .frame(width: 320.0) + Text(LocalizedStringKey("Choose the phonetic layout for Mandarin parser.")) + .preferenceDescription() + } + Preferences.Section(bottomDivider: true, label: { Text(LocalizedStringKey("Basic Keyboard Layout:")) }) { + HStack { + Picker("", selection: $selBasicKeyboardLayout) { + ForEach(0...(IME.arrEnumerateSystemKeyboardLayouts.count - 1), id: \.self) { id in + Text(IME.arrEnumerateSystemKeyboardLayouts[id].strName).tag( + IME.arrEnumerateSystemKeyboardLayouts[id].strValue) + }.id(UUID()) + }.onChange(of: selBasicKeyboardLayout) { (value) in + mgrPrefs.basicKeyboardLayout = value + } + .labelsHidden() + .frame(width: 240.0) + } + Text(LocalizedStringKey("Choose the macOS-level basic keyboard layout.")) + .preferenceDescription() + } + } + Divider() + Preferences.Container(contentWidth: contentWidth) { + Preferences.Section(title: "") { + VStack(alignment: .leading, spacing: 10) { + Text( + LocalizedStringKey( + "Non-QWERTY alphanumeral keyboard layouts are for Hanyu Pinyin parser only." + ) + ) + .preferenceDescription() + Text( + LocalizedStringKey( + "Apple Dynamic Bopomofo Basic Keyboard Layouts (Dachen & Eten Traditional) must match the Dachen parser in order to be functional." + ) + ) + .preferenceDescription() + } + } + } + } +} + +@available(macOS 11.0, *) +struct suiPrefPaneKeyboard_Previews: PreviewProvider { + static var previews: some View { + suiPrefPaneKeyboard() + } +} diff --git a/vChewing.xcodeproj/project.pbxproj b/vChewing.xcodeproj/project.pbxproj index ce3b8e7d..43f06194 100644 --- a/vChewing.xcodeproj/project.pbxproj +++ b/vChewing.xcodeproj/project.pbxproj @@ -30,19 +30,25 @@ 5B707CEC27D9F4870099EF99 /* OpenCC in Frameworks */ = {isa = PBXBuildFile; productRef = 5B707CEB27D9F4870099EF99 /* OpenCC */; }; 5B73FB5E27B2BE1300E9BF49 /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = 5B73FB6027B2BE1300E9BF49 /* InfoPlist.strings */; }; 5B7BC4B027AFFBE800F66C24 /* frmPrefWindow.xib in Resources */ = {isa = PBXBuildFile; fileRef = 5B7BC4AE27AFFBE800F66C24 /* frmPrefWindow.xib */; }; - 5BA9FD2327FEF39C002DE248 /* Utilities.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5BA9FD1627FEF39C002DE248 /* Utilities.swift */; }; - 5BA9FD2427FEF39C002DE248 /* Pane.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5BA9FD1727FEF39C002DE248 /* Pane.swift */; }; - 5BA9FD2527FEF39C002DE248 /* Localization.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5BA9FD1827FEF39C002DE248 /* Localization.swift */; }; - 5BA9FD2627FEF39C002DE248 /* PreferencesStyle.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5BA9FD1927FEF39C002DE248 /* PreferencesStyle.swift */; }; - 5BA9FD2727FEF39C002DE248 /* PreferencePane.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5BA9FD1A27FEF39C002DE248 /* PreferencePane.swift */; }; - 5BA9FD2827FEF39C002DE248 /* Preferences.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5BA9FD1B27FEF39C002DE248 /* Preferences.swift */; }; - 5BA9FD2927FEF39C002DE248 /* SegmentedControlStyleViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5BA9FD1C27FEF39C002DE248 /* SegmentedControlStyleViewController.swift */; }; - 5BA9FD2A27FEF39C002DE248 /* ToolbarItemStyleViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5BA9FD1D27FEF39C002DE248 /* ToolbarItemStyleViewController.swift */; }; - 5BA9FD2B27FEF39C002DE248 /* Container.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5BA9FD1E27FEF39C002DE248 /* Container.swift */; }; - 5BA9FD2C27FEF39C002DE248 /* PreferencesStyleController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5BA9FD1F27FEF39C002DE248 /* PreferencesStyleController.swift */; }; - 5BA9FD2D27FEF39C002DE248 /* PreferencesWindowController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5BA9FD2027FEF39C002DE248 /* PreferencesWindowController.swift */; }; - 5BA9FD2E27FEF39C002DE248 /* Section.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5BA9FD2127FEF39C002DE248 /* Section.swift */; }; - 5BA9FD2F27FEF39C002DE248 /* PreferencesTabViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5BA9FD2227FEF39C002DE248 /* PreferencesTabViewController.swift */; }; + 5BA9FD0F27FEDB6B002DE248 /* suiPrefPaneGeneral.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5BA9FD0A27FEDB6B002DE248 /* suiPrefPaneGeneral.swift */; }; + 5BA9FD1027FEDB6B002DE248 /* suiPrefPaneKeyboard.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5BA9FD0B27FEDB6B002DE248 /* suiPrefPaneKeyboard.swift */; }; + 5BA9FD1127FEDB6B002DE248 /* ctlPrefUI.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5BA9FD0C27FEDB6B002DE248 /* ctlPrefUI.swift */; }; + 5BA9FD1227FEDB6B002DE248 /* suiPrefPaneExperience.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5BA9FD0D27FEDB6B002DE248 /* suiPrefPaneExperience.swift */; }; + 5BA9FD1327FEDB6B002DE248 /* suiPrefPaneDictionary.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5BA9FD0E27FEDB6B002DE248 /* suiPrefPaneDictionary.swift */; }; + 5BA9FD3E27FEF3C8002DE248 /* Utilities.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5BA9FD3127FEF3C8002DE248 /* Utilities.swift */; }; + 5BA9FD3F27FEF3C8002DE248 /* Pane.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5BA9FD3227FEF3C8002DE248 /* Pane.swift */; }; + 5BA9FD4027FEF3C8002DE248 /* Localization.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5BA9FD3327FEF3C8002DE248 /* Localization.swift */; }; + 5BA9FD4127FEF3C8002DE248 /* PreferencesStyle.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5BA9FD3427FEF3C8002DE248 /* PreferencesStyle.swift */; }; + 5BA9FD4227FEF3C8002DE248 /* PreferencePane.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5BA9FD3527FEF3C8002DE248 /* PreferencePane.swift */; }; + 5BA9FD4327FEF3C8002DE248 /* Preferences.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5BA9FD3627FEF3C8002DE248 /* Preferences.swift */; }; + 5BA9FD4427FEF3C8002DE248 /* SegmentedControlStyleViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5BA9FD3727FEF3C8002DE248 /* SegmentedControlStyleViewController.swift */; }; + 5BA9FD4527FEF3C9002DE248 /* ToolbarItemStyleViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5BA9FD3827FEF3C8002DE248 /* ToolbarItemStyleViewController.swift */; }; + 5BA9FD4627FEF3C9002DE248 /* Container.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5BA9FD3927FEF3C8002DE248 /* Container.swift */; }; + 5BA9FD4727FEF3C9002DE248 /* PreferencesStyleController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5BA9FD3A27FEF3C8002DE248 /* PreferencesStyleController.swift */; }; + 5BA9FD4827FEF3C9002DE248 /* PreferencesWindowController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5BA9FD3B27FEF3C8002DE248 /* PreferencesWindowController.swift */; }; + 5BA9FD4927FEF3C9002DE248 /* Section.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5BA9FD3C27FEF3C8002DE248 /* Section.swift */; }; + 5BA9FD4A27FEF3C9002DE248 /* PreferencesTabViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5BA9FD3D27FEF3C8002DE248 /* PreferencesTabViewController.swift */; }; + 5BA9FD8B28006B41002DE248 /* VDKComboBox.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5BA9FD8A28006B41002DE248 /* VDKComboBox.swift */; }; 5BAD0CD527D701F6003D127F /* vChewingKeyLayout.bundle in Resources */ = {isa = PBXBuildFile; fileRef = 5B30F11227BA568800484E24 /* vChewingKeyLayout.bundle */; }; 5BB802DA27FABA8300CF1C19 /* ctlInputMethod_Menu.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5BB802D927FABA8300CF1C19 /* ctlInputMethod_Menu.swift */; }; 5BBBB75F27AED54C0023B93A /* Beep.m4a in Resources */ = {isa = PBXBuildFile; fileRef = 5BBBB75D27AED54C0023B93A /* Beep.m4a */; }; @@ -202,19 +208,25 @@ 5B7BC4AF27AFFBE800F66C24 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = Base; path = Base.lproj/frmPrefWindow.xib; sourceTree = ""; }; 5B7BC4B227AFFC0B00F66C24 /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/frmPrefWindow.strings; sourceTree = ""; }; 5B8F43ED27C9BC220069AC27 /* SymbolLM.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = SymbolLM.h; sourceTree = ""; }; - 5BA9FD1627FEF39C002DE248 /* Utilities.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Utilities.swift; sourceTree = ""; }; - 5BA9FD1727FEF39C002DE248 /* Pane.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Pane.swift; sourceTree = ""; }; - 5BA9FD1827FEF39C002DE248 /* Localization.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Localization.swift; sourceTree = ""; }; - 5BA9FD1927FEF39C002DE248 /* PreferencesStyle.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PreferencesStyle.swift; sourceTree = ""; }; - 5BA9FD1A27FEF39C002DE248 /* PreferencePane.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PreferencePane.swift; sourceTree = ""; }; - 5BA9FD1B27FEF39C002DE248 /* Preferences.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Preferences.swift; sourceTree = ""; }; - 5BA9FD1C27FEF39C002DE248 /* SegmentedControlStyleViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SegmentedControlStyleViewController.swift; sourceTree = ""; }; - 5BA9FD1D27FEF39C002DE248 /* ToolbarItemStyleViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ToolbarItemStyleViewController.swift; sourceTree = ""; }; - 5BA9FD1E27FEF39C002DE248 /* Container.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Container.swift; sourceTree = ""; }; - 5BA9FD1F27FEF39C002DE248 /* PreferencesStyleController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PreferencesStyleController.swift; sourceTree = ""; }; - 5BA9FD2027FEF39C002DE248 /* PreferencesWindowController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PreferencesWindowController.swift; sourceTree = ""; }; - 5BA9FD2127FEF39C002DE248 /* Section.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Section.swift; sourceTree = ""; }; - 5BA9FD2227FEF39C002DE248 /* PreferencesTabViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PreferencesTabViewController.swift; sourceTree = ""; }; + 5BA9FD0A27FEDB6B002DE248 /* suiPrefPaneGeneral.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = suiPrefPaneGeneral.swift; sourceTree = ""; }; + 5BA9FD0B27FEDB6B002DE248 /* suiPrefPaneKeyboard.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = suiPrefPaneKeyboard.swift; sourceTree = ""; }; + 5BA9FD0C27FEDB6B002DE248 /* ctlPrefUI.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ctlPrefUI.swift; sourceTree = ""; }; + 5BA9FD0D27FEDB6B002DE248 /* suiPrefPaneExperience.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = suiPrefPaneExperience.swift; sourceTree = ""; }; + 5BA9FD0E27FEDB6B002DE248 /* suiPrefPaneDictionary.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = suiPrefPaneDictionary.swift; sourceTree = ""; }; + 5BA9FD3127FEF3C8002DE248 /* Utilities.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Utilities.swift; sourceTree = ""; }; + 5BA9FD3227FEF3C8002DE248 /* Pane.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Pane.swift; sourceTree = ""; }; + 5BA9FD3327FEF3C8002DE248 /* Localization.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Localization.swift; sourceTree = ""; }; + 5BA9FD3427FEF3C8002DE248 /* PreferencesStyle.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PreferencesStyle.swift; sourceTree = ""; }; + 5BA9FD3527FEF3C8002DE248 /* PreferencePane.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PreferencePane.swift; sourceTree = ""; }; + 5BA9FD3627FEF3C8002DE248 /* Preferences.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Preferences.swift; sourceTree = ""; }; + 5BA9FD3727FEF3C8002DE248 /* SegmentedControlStyleViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SegmentedControlStyleViewController.swift; sourceTree = ""; }; + 5BA9FD3827FEF3C8002DE248 /* ToolbarItemStyleViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ToolbarItemStyleViewController.swift; sourceTree = ""; }; + 5BA9FD3927FEF3C8002DE248 /* Container.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Container.swift; sourceTree = ""; }; + 5BA9FD3A27FEF3C8002DE248 /* PreferencesStyleController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PreferencesStyleController.swift; sourceTree = ""; }; + 5BA9FD3B27FEF3C8002DE248 /* PreferencesWindowController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PreferencesWindowController.swift; sourceTree = ""; }; + 5BA9FD3C27FEF3C8002DE248 /* Section.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Section.swift; sourceTree = ""; }; + 5BA9FD3D27FEF3C8002DE248 /* PreferencesTabViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PreferencesTabViewController.swift; sourceTree = ""; }; + 5BA9FD8A28006B41002DE248 /* VDKComboBox.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VDKComboBox.swift; sourceTree = ""; }; 5BB802D927FABA8300CF1C19 /* ctlInputMethod_Menu.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ctlInputMethod_Menu.swift; sourceTree = ""; }; 5BBBB75D27AED54C0023B93A /* Beep.m4a */ = {isa = PBXFileReference; lastKnownFileType = file; path = Beep.m4a; sourceTree = ""; }; 5BBBB75E27AED54C0023B93A /* Fart.m4a */ = {isa = PBXFileReference; lastKnownFileType = file; path = Fart.m4a; sourceTree = ""; }; @@ -377,6 +389,7 @@ 5B62A30127AE732800A19448 /* 3rdParty */ = { isa = PBXGroup; children = ( + 5BA9FD8C28006BA7002DE248 /* VDKComboBox */, 5B707CE627D9F43E0099EF99 /* OpenCCBridge */, 5B62A30227AE733500A19448 /* OVMandarin */, 5BA9FCEA27FED652002DE248 /* SindreSorhus */, @@ -509,6 +522,7 @@ isa = PBXGroup; children = ( 5B62A33E27AE7CD900A19448 /* CandidateUI */, + 5BA9FD0927FED9F3002DE248 /* PrefUI */, 5B62A34227AE7CD900A19448 /* TooltipUI */, 5B62A34427AE7CD900A19448 /* NotifierUI */, ); @@ -594,32 +608,52 @@ 5BA9FCEA27FED652002DE248 /* SindreSorhus */ = { isa = PBXGroup; children = ( - 5BA9FD1527FEF39C002DE248 /* Preferences */, + 5BA9FD3027FEF3C8002DE248 /* Preferences */, ); name = SindreSorhus; path = Source/3rdParty/SindreSorhus; sourceTree = SOURCE_ROOT; }; - 5BA9FD1527FEF39C002DE248 /* Preferences */ = { + 5BA9FD0927FED9F3002DE248 /* PrefUI */ = { isa = PBXGroup; children = ( - 5BA9FD1E27FEF39C002DE248 /* Container.swift */, - 5BA9FD1827FEF39C002DE248 /* Localization.swift */, - 5BA9FD1727FEF39C002DE248 /* Pane.swift */, - 5BA9FD1A27FEF39C002DE248 /* PreferencePane.swift */, - 5BA9FD1B27FEF39C002DE248 /* Preferences.swift */, - 5BA9FD1927FEF39C002DE248 /* PreferencesStyle.swift */, - 5BA9FD1F27FEF39C002DE248 /* PreferencesStyleController.swift */, - 5BA9FD2227FEF39C002DE248 /* PreferencesTabViewController.swift */, - 5BA9FD2027FEF39C002DE248 /* PreferencesWindowController.swift */, - 5BA9FD2127FEF39C002DE248 /* Section.swift */, - 5BA9FD1C27FEF39C002DE248 /* SegmentedControlStyleViewController.swift */, - 5BA9FD1D27FEF39C002DE248 /* ToolbarItemStyleViewController.swift */, - 5BA9FD1627FEF39C002DE248 /* Utilities.swift */, + 5BA9FD0C27FEDB6B002DE248 /* ctlPrefUI.swift */, + 5BA9FD0E27FEDB6B002DE248 /* suiPrefPaneDictionary.swift */, + 5BA9FD0D27FEDB6B002DE248 /* suiPrefPaneExperience.swift */, + 5BA9FD0A27FEDB6B002DE248 /* suiPrefPaneGeneral.swift */, + 5BA9FD0B27FEDB6B002DE248 /* suiPrefPaneKeyboard.swift */, + ); + path = PrefUI; + sourceTree = ""; + }; + 5BA9FD3027FEF3C8002DE248 /* Preferences */ = { + isa = PBXGroup; + children = ( + 5BA9FD3927FEF3C8002DE248 /* Container.swift */, + 5BA9FD3327FEF3C8002DE248 /* Localization.swift */, + 5BA9FD3227FEF3C8002DE248 /* Pane.swift */, + 5BA9FD3527FEF3C8002DE248 /* PreferencePane.swift */, + 5BA9FD3627FEF3C8002DE248 /* Preferences.swift */, + 5BA9FD3427FEF3C8002DE248 /* PreferencesStyle.swift */, + 5BA9FD3A27FEF3C8002DE248 /* PreferencesStyleController.swift */, + 5BA9FD3D27FEF3C8002DE248 /* PreferencesTabViewController.swift */, + 5BA9FD3B27FEF3C8002DE248 /* PreferencesWindowController.swift */, + 5BA9FD3C27FEF3C8002DE248 /* Section.swift */, + 5BA9FD3727FEF3C8002DE248 /* SegmentedControlStyleViewController.swift */, + 5BA9FD3827FEF3C8002DE248 /* ToolbarItemStyleViewController.swift */, + 5BA9FD3127FEF3C8002DE248 /* Utilities.swift */, ); path = Preferences; sourceTree = ""; }; + 5BA9FD8C28006BA7002DE248 /* VDKComboBox */ = { + isa = PBXGroup; + children = ( + 5BA9FD8A28006B41002DE248 /* VDKComboBox.swift */, + ); + path = VDKComboBox; + sourceTree = ""; + }; 5BBBB75C27AED54C0023B93A /* SoundFiles */ = { isa = PBXGroup; children = ( @@ -1022,52 +1056,58 @@ files = ( 5B707CE827D9F4590099EF99 /* OpenCCBridge.swift in Sources */, D427F76C278CA2B0004A2160 /* AppDelegate.swift in Sources */, + 5BA9FD4527FEF3C9002DE248 /* ToolbarItemStyleViewController.swift in Sources */, + 5BA9FD4127FEF3C8002DE248 /* PreferencesStyle.swift in Sources */, + 5BA9FD1227FEDB6B002DE248 /* suiPrefPaneExperience.swift in Sources */, 6ACC3D442793701600F1B140 /* ParselessPhraseDB.cpp in Sources */, D461B792279DAC010070E734 /* InputState.swift in Sources */, 5B62A33D27AE7CC100A19448 /* ctlAboutWindow.swift in Sources */, D47B92C027972AD100458394 /* main.swift in Sources */, - 5BA9FD2527FEF39C002DE248 /* Localization.swift in Sources */, D44FB74D2792189A003C80A6 /* PhraseReplacementMap.mm in Sources */, - 5BA9FD2E27FEF39C002DE248 /* Section.swift in Sources */, D4A13D5A27A59F0B003BE359 /* ctlInputMethod.swift in Sources */, + 5BA9FD4827FEF3C9002DE248 /* PreferencesWindowController.swift in Sources */, D4E569DC27A34D0E00AC2CEF /* KeyHandler.mm in Sources */, + 5BA9FD4627FEF3C9002DE248 /* Container.swift in Sources */, D47F7DD0278C0897002F9DD7 /* ctlNonModalAlertWindow.swift in Sources */, 5B62A32F27AE78B000A19448 /* CoreLM.mm in Sources */, 5BE78BE027B38804005EA1BE /* LMConsolidator.mm in Sources */, D456576E279E4F7B00DF6BC9 /* KeyParser.swift in Sources */, + 5BA9FD1027FEDB6B002DE248 /* suiPrefPaneKeyboard.swift in Sources */, + 5BA9FD4327FEF3C8002DE248 /* Preferences.swift in Sources */, + 5BA9FD4427FEF3C8002DE248 /* SegmentedControlStyleViewController.swift in Sources */, D47F7DCE278BFB57002F9DD7 /* ctlPrefWindow.swift in Sources */, - 5BA9FD2927FEF39C002DE248 /* SegmentedControlStyleViewController.swift in Sources */, + 5BA9FD4227FEF3C8002DE248 /* PreferencePane.swift in Sources */, + 5BA9FD8B28006B41002DE248 /* VDKComboBox.swift in Sources */, D47D73AC27A6CAE600255A50 /* AssociatedPhrases.mm in Sources */, + 5BA9FD4A27FEF3C9002DE248 /* PreferencesTabViewController.swift in Sources */, 5B62A34A27AE7CD900A19448 /* NotifierController.swift in Sources */, - 5BA9FD2827FEF39C002DE248 /* Preferences.swift in Sources */, - 5BA9FD2D27FEF39C002DE248 /* PreferencesWindowController.swift in Sources */, - 5BA9FD2B27FEF39C002DE248 /* Container.swift in Sources */, - 5BA9FD2427FEF39C002DE248 /* Pane.swift in Sources */, 5B11328927B94CFB00E58451 /* AppleKeyboardConverter.swift in Sources */, D41355DB278E6D17005E5CBD /* LMInstantiator.mm in Sources */, 5B62A32927AE77D100A19448 /* FSEventStreamHelper.swift in Sources */, D47F7DD3278C1263002F9DD7 /* UserOverrideModel.cpp in Sources */, 5B62A33627AE795800A19448 /* mgrPrefs.swift in Sources */, 5B62A33827AE79CD00A19448 /* NSStringUtils.swift in Sources */, - 5BA9FD2327FEF39C002DE248 /* Utilities.swift in Sources */, + 5BA9FD0F27FEDB6B002DE248 /* suiPrefPaneGeneral.swift in Sources */, + 5BA9FD4927FEF3C9002DE248 /* Section.swift in Sources */, + 5BA9FD3E27FEF3C8002DE248 /* Utilities.swift in Sources */, + 5BA9FD1127FEDB6B002DE248 /* ctlPrefUI.swift in Sources */, 5B62A33227AE792F00A19448 /* InputSourceHelper.swift in Sources */, - 5BA9FD2C27FEF39C002DE248 /* PreferencesStyleController.swift in Sources */, - 5BA9FD2A27FEF39C002DE248 /* ToolbarItemStyleViewController.swift in Sources */, - 5BA9FD2F27FEF39C002DE248 /* PreferencesTabViewController.swift in Sources */, 5B5E535227EF261400C6AA1E /* IME.swift in Sources */, - 5BA9FD2627FEF39C002DE248 /* PreferencesStyle.swift in Sources */, 5B62A34927AE7CD900A19448 /* TooltipController.swift in Sources */, 6A0D4F4515FC0EB100ABF4B3 /* Mandarin.cpp in Sources */, 5B62A34827AE7CD900A19448 /* ctlCandidateVertical.swift in Sources */, + 5BA9FD4027FEF3C8002DE248 /* Localization.swift in Sources */, + 5BA9FD1327FEDB6B002DE248 /* suiPrefPaneDictionary.swift in Sources */, 6ACC3D452793701600F1B140 /* ParselessLM.cpp in Sources */, 5BBBB77A27AEDC690023B93A /* clsSFX.swift in Sources */, + 5BA9FD4727FEF3C9002DE248 /* PreferencesStyleController.swift in Sources */, 5BF8423127BAA942008E7E4C /* vChewingKanjiConverter.swift in Sources */, 5B62A34627AE7CD900A19448 /* ctlCandidateHorizontal.swift in Sources */, 5B62A34727AE7CD900A19448 /* ctlCandidate.swift in Sources */, + 5BA9FD3F27FEF3C8002DE248 /* Pane.swift in Sources */, 5BB802DA27FABA8300CF1C19 /* ctlInputMethod_Menu.swift in Sources */, D41355DE278EA3ED005E5CBD /* UserPhrasesLM.mm in Sources */, 6ACC3D3F27914F2400F1B140 /* KeyValueBlobReader.cpp in Sources */, - 5BA9FD2727FEF39C002DE248 /* PreferencePane.swift in Sources */, D41355D8278D74B5005E5CBD /* mgrLangModel.mm in Sources */, 5BDC1CFA27FDF1310052C2B9 /* apiUpdate.swift in Sources */, );