2.7.5 // Further renovation. Merge PR#147 from upd/2.7.5

This commit is contained in:
ShikiSuen 2022-09-25 21:28:00 +08:00 committed by GitHub
commit 50ab1184ec
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
112 changed files with 1747 additions and 1398 deletions

View File

@ -17,13 +17,9 @@ $ Contributors and volunteers of the upstream repo, having no responsibility in
- Zonble Yang: - Zonble Yang:
- McBopomofo for macOS 2.x architect. - McBopomofo for macOS 2.x architect.
- Voltaire candidate window MK2 (massively modified as MK3 in vChewing by Shiki Suen). - Voltaire candidate window MK2 (massively modified as MK3 in vChewing by Shiki Suen).
- Notifier window.
- App-style installer (only preserved for developer purposes). - App-style installer (only preserved for developer purposes).
- PrefMgr (userdefaults manager).
- Mengjuei Hsieh: - Mengjuei Hsieh:
- McBopomofo for macOS 1.x main developer and architect. - McBopomofo for macOS 1.x main developer and architect.
- The original C++ version of the User Override Module.
- Shiki Suen is trying to rewrite this module in Swift (and CSharp) with further development.
Although there is no Lukhnos's codes left in the current repository, we still credit him for his previous work: Although there is no Lukhnos's codes left in the current repository, we still credit him for his previous work:
@ -32,6 +28,8 @@ Although there is no Lukhnos's codes left in the current repository, we still cr
- Shiki Suen's Megrez engine (MIT License) is basically a Swift-rewritten version of Gramambular 2 with further development. - Shiki Suen's Megrez engine (MIT License) is basically a Swift-rewritten version of Gramambular 2 with further development.
- Developer of Mandarin syllable composer (removed since vChewing 1.5.7). - Developer of Mandarin syllable composer (removed since vChewing 1.5.7).
- Shiki Suen's Tekkon engine is made from scratch and has no relationship to Mandarin syllable composer. - Shiki Suen's Tekkon engine is made from scratch and has no relationship to Mandarin syllable composer.
- Developer of the original C++ version of the User Override Module MK2.
- Shiki Suen is trying to rewrite this module in Swift (and CSharp) with further development.
$ Special thanks to: $ Special thanks to:

Binary file not shown.

Before

Width:  |  Height:  |  Size: 22 KiB

After

Width:  |  Height:  |  Size: 21 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 76 KiB

After

Width:  |  Height:  |  Size: 75 KiB

View File

@ -48,7 +48,7 @@ public class NSAttributedTextView: NSView {
} }
public var direction: writingDirection = .horizontal public var direction: writingDirection = .horizontal
public var fontSize: CGFloat = NSFont.systemFontSize { public var fontSize: Double = NSFont.systemFontSize {
didSet { didSet {
attributes[.font] = NSFont.systemFont(ofSize: fontSize) attributes[.font] = NSFont.systemFont(ofSize: fontSize)
} }

View File

@ -0,0 +1,9 @@
.DS_Store
/.build
/Packages
/*.xcodeproj
xcuserdata/
DerivedData/
.swiftpm/config/registries.json
.swiftpm/xcode/package.xcworkspace/contents.xcworkspacedata
.netrc

View File

@ -0,0 +1,28 @@
// swift-tools-version:5.3
import PackageDescription
let package = Package(
name: "Voltaire",
platforms: [
.macOS(.v10_11)
],
products: [
.library(
name: "Voltaire",
targets: ["Voltaire"]
)
],
dependencies: [
.package(path: "../vChewing_CandidateWindow"),
.package(path: "../vChewing_Shared"),
],
targets: [
.target(
name: "Voltaire",
dependencies: [
.product(name: "Shared", package: "vChewing_Shared"),
.product(name: "CandidateWindow", package: "vChewing_CandidateWindow"),
]
)
]
)

View File

@ -0,0 +1,48 @@
# Voltaire
Voltaire is a UI component replacement for Apple's InputMethodKit (IMK). The
built-in candidate UI has a limited interaction model and is not very
extensible nor customizable.
The project also comes with a test app that demonstrates the features of the
UI component.
Voltaire MK3 provides following new features comparing to MK1 and MK2:
1. A brand-new candidate window design conforming to the latest macOS UI design style, plus a floating label indicating the current page number of candidates (a frequently-asked feature by vChewing users).
2. One class for both vertical and horizontal display purposes. This can be specified as a parameter on init().
3. Can specify whether default candidate fonts conform to MOE glyphs standard or continental glyphs standard, requiring macOS 12 Monterey or later.
4. Can specify whether page buttons are shown.
Regarding the horizontal and vertical layout:
1. It is recommended to use init() in lieu of directly changing the layout variable since the latter doesn't redraw page buttons correctly.
2. Vertical candidate mode doesn't support scrolling. This is a deliberated design.
---
Copyrights:
```
- (c) 2022 Shiki Suen for all modifications introduced to Voltaire MK3.
- (c) 2021 Zonble Yang for rewriting Voltaire MK2 in Swift.
- (c) 2012 Lukhnos Liu for Voltaire MK1 development in Objective-C.
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:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
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.
```

View File

@ -10,6 +10,10 @@
// Zonble Voltaire // Zonble Voltaire
import CandidateWindow
import Cocoa
import Shared
private class vwrCandidateUniversal: NSView { private class vwrCandidateUniversal: NSView {
var highlightedIndex: Int = 0 { var highlightedIndex: Int = 0 {
didSet { highlightedIndex = min(max(highlightedIndex, 0), dispCandidatesWithLabels.count - 1) } didSet { highlightedIndex = min(max(highlightedIndex, 0), dispCandidatesWithLabels.count - 1) }
@ -17,22 +21,23 @@ private class vwrCandidateUniversal: NSView {
var action: Selector? var action: Selector?
weak var target: AnyObject? weak var target: AnyObject?
weak var controller: AnyObject?
var isVerticalLayout = false var isVerticalLayout = false
var fractionFontSize: CGFloat = 12.0 var fractionFontSize: Double = 12.0
private var keyLabels: [String] = [] private var keyLabels: [String] = []
private var displayedCandidates: [String] = [] private var displayedCandidates: [String] = []
private var dispCandidatesWithLabels: [String] = [] private var dispCandidatesWithLabels: [String] = []
private var keyLabelHeight: CGFloat = 0 private var keyLabelHeight: Double = 0
private var keyLabelWidth: CGFloat = 0 private var keyLabelWidth: Double = 0
private var candidateTextHeight: CGFloat = 0 private var candidateTextHeight: Double = 0
private var cellPadding: CGFloat = 0 private var cellPadding: Double = 0
private var keyLabelAttrDict: [NSAttributedString.Key: AnyObject] = [:] private var keyLabelAttrDict: [NSAttributedString.Key: AnyObject] = [:]
private var candidateAttrDict: [NSAttributedString.Key: AnyObject] = [:] private var candidateAttrDict: [NSAttributedString.Key: AnyObject] = [:]
private var candidateWithLabelAttrDict: [NSAttributedString.Key: AnyObject] = [:] private var candidateWithLabelAttrDict: [NSAttributedString.Key: AnyObject] = [:]
private var windowWidth: CGFloat = 0 // private var windowWidth: Double = 0 //
private var elementWidths: [CGFloat] = [] private var elementWidths: [Double] = []
private var elementHeights: [CGFloat] = [] // private var elementHeights: [Double] = [] //
private var trackingHighlightedIndex: Int = .max { private var trackingHighlightedIndex: Int = .max {
didSet { trackingHighlightedIndex = max(trackingHighlightedIndex, 0) } didSet { trackingHighlightedIndex = max(trackingHighlightedIndex, 0) }
} }
@ -50,17 +55,17 @@ private class vwrCandidateUniversal: NSView {
result.width = windowWidth result.width = windowWidth
result.height = elementHeights.reduce(0, +) result.height = elementHeights.reduce(0, +)
case false: case false:
result.width = elementWidths.reduce(0, +) + CGFloat(elementWidths.count) result.width = elementWidths.reduce(0, +) + Double(elementWidths.count)
result.height = candidateTextHeight + cellPadding result.height = candidateTextHeight + cellPadding
} }
} }
return result return result
} }
@objc(setKeyLabels:displayedCandidates:)
func set(keyLabels labels: [String], displayedCandidates candidates: [String]) { func set(keyLabels labels: [String], displayedCandidates candidates: [String]) {
guard let delegate = (controller as? CtlCandidateUniversal)?.delegate else { return }
let candidates = candidates.map { theCandidate -> String in let candidates = candidates.map { theCandidate -> String in
let theConverted = ChineseConverter.kanjiConversionIfRequired(theCandidate) let theConverted = delegate.kanjiConversionIfRequired(theCandidate)
return (theCandidate == theConverted) ? theCandidate : "\(theConverted)(\(theCandidate))" return (theCandidate == theConverted) ? theCandidate : "\(theConverted)(\(theCandidate))"
} }
@ -69,9 +74,9 @@ private class vwrCandidateUniversal: NSView {
displayedCandidates = Array(candidates[0..<count]) displayedCandidates = Array(candidates[0..<count])
dispCandidatesWithLabels = zip(keyLabels, displayedCandidates).map { $0 + $1 } dispCandidatesWithLabels = zip(keyLabels, displayedCandidates).map { $0 + $1 }
var newWidths = [CGFloat]() var newWidths = [Double]()
var calculatedWindowWidth = CGFloat() var calculatedWindowWidth = Double()
var newHeights = [CGFloat]() var newHeights = [Double]()
let baseSize = NSSize(width: 10240.0, height: 10240.0) let baseSize = NSSize(width: 10240.0, height: 10240.0)
for index in 0..<count { for index in 0..<count {
let rctCandidate = (dispCandidatesWithLabels[index] as NSString).boundingRect( let rctCandidate = (dispCandidatesWithLabels[index] as NSString).boundingRect(
@ -133,55 +138,15 @@ private class vwrCandidateUniversal: NSView {
cellPadding = ceil(biggestSize / 4.0) * 2 cellPadding = ceil(biggestSize / 4.0) * 2
} }
func ensureLangIdentifier(for attr: inout [NSAttributedString.Key: AnyObject]) {
if PrefMgr.shared.handleDefaultCandidateFontsByLangIdentifier {
switch IMEApp.currentInputMode {
case .imeModeCHS:
if #available(macOS 12.0, *) {
attr[.languageIdentifier] = "zh-Hans" as AnyObject
}
case .imeModeCHT:
if #available(macOS 12.0, *) {
attr[.languageIdentifier] =
(PrefMgr.shared.shiftJISShinjitaiOutputEnabled || PrefMgr.shared.chineseConversionEnabled)
? "ja" as AnyObject : "zh-Hant" as AnyObject
}
default:
break
}
}
}
var highlightedColor: NSColor {
var result = NSColor.alternateSelectedControlColor
var colorBlendAmount: CGFloat = NSApplication.isDarkMode ? 0.3 : 0.0
if #available(macOS 10.14, *), !NSApplication.isDarkMode, IMEApp.currentInputMode == .imeModeCHT {
colorBlendAmount = 0.15
}
// The background color of the highlightened candidate
switch IMEApp.currentInputMode {
case .imeModeCHS:
result = NSColor.systemRed
case .imeModeCHT:
result = NSColor.systemBlue
default: break
}
var blendingAgainstTarget: NSColor = NSApplication.isDarkMode ? NSColor.black : NSColor.white
if #unavailable(macOS 10.14) {
colorBlendAmount = 0.3
blendingAgainstTarget = NSColor.white
}
return result.blended(withFraction: colorBlendAmount, of: blendingAgainstTarget)!
}
override func draw(_: NSRect) { override func draw(_: NSRect) {
guard let controller = controller as? CtlCandidateUniversal else { return }
let bounds = bounds let bounds = bounds
NSColor.controlBackgroundColor.setFill() // Candidate list panel base background NSColor.controlBackgroundColor.setFill() // Candidate list panel base background
NSBezierPath.fill(bounds) NSBezierPath.fill(bounds)
switch isVerticalLayout { switch isVerticalLayout {
case true: case true:
var accuHeight: CGFloat = 0 var accuHeight: Double = 0
for (index, elementHeight) in elementHeights.enumerated() { for (index, elementHeight) in elementHeights.enumerated() {
let currentHeight = elementHeight let currentHeight = elementHeight
let rctCandidateArea = NSRect( let rctCandidateArea = NSRect(
@ -200,7 +165,7 @@ private class vwrCandidateUniversal: NSView {
var activeCandidateIndexAttr = keyLabelAttrDict var activeCandidateIndexAttr = keyLabelAttrDict
var activeCandidateAttr = candidateAttrDict var activeCandidateAttr = candidateAttrDict
if index == highlightedIndex { if index == highlightedIndex {
highlightedColor.setFill() controller.highlightedColor().setFill()
// Highlightened index text color // Highlightened index text color
activeCandidateIndexAttr[.foregroundColor] = NSColor.selectedMenuItemTextColor activeCandidateIndexAttr[.foregroundColor] = NSColor.selectedMenuItemTextColor
.withAlphaComponent(0.84) .withAlphaComponent(0.84)
@ -209,7 +174,11 @@ private class vwrCandidateUniversal: NSView {
let path: NSBezierPath = .init(roundedRect: rctCandidateArea, xRadius: 6, yRadius: 6) let path: NSBezierPath = .init(roundedRect: rctCandidateArea, xRadius: 6, yRadius: 6)
path.fill() path.fill()
} }
ensureLangIdentifier(for: &activeCandidateAttr) if #available(macOS 12, *) {
if controller.useLangIdentifier {
activeCandidateAttr[.languageIdentifier] = controller.locale as AnyObject
}
}
(keyLabels[index] as NSString).draw( (keyLabels[index] as NSString).draw(
in: rctLabel, withAttributes: activeCandidateIndexAttr in: rctLabel, withAttributes: activeCandidateIndexAttr
) )
@ -219,7 +188,7 @@ private class vwrCandidateUniversal: NSView {
accuHeight += currentHeight accuHeight += currentHeight
} }
case false: case false:
var accuWidth: CGFloat = 0 var accuWidth: Double = 0
for (index, elementWidth) in elementWidths.enumerated() { for (index, elementWidth) in elementWidths.enumerated() {
let currentWidth = elementWidth let currentWidth = elementWidth
let rctCandidateArea = NSRect( let rctCandidateArea = NSRect(
@ -239,7 +208,7 @@ private class vwrCandidateUniversal: NSView {
var activeCandidateIndexAttr = keyLabelAttrDict var activeCandidateIndexAttr = keyLabelAttrDict
var activeCandidateAttr = candidateAttrDict var activeCandidateAttr = candidateAttrDict
if index == highlightedIndex { if index == highlightedIndex {
highlightedColor.setFill() controller.highlightedColor().setFill()
// Highlightened index text color // Highlightened index text color
activeCandidateIndexAttr[.foregroundColor] = NSColor.selectedMenuItemTextColor activeCandidateIndexAttr[.foregroundColor] = NSColor.selectedMenuItemTextColor
.withAlphaComponent(0.84) .withAlphaComponent(0.84)
@ -248,7 +217,11 @@ private class vwrCandidateUniversal: NSView {
let path: NSBezierPath = .init(roundedRect: rctCandidateArea, xRadius: 6, yRadius: 6) let path: NSBezierPath = .init(roundedRect: rctCandidateArea, xRadius: 6, yRadius: 6)
path.fill() path.fill()
} }
ensureLangIdentifier(for: &activeCandidateAttr) if #available(macOS 12, *) {
if controller.useLangIdentifier {
activeCandidateAttr[.languageIdentifier] = controller.locale as AnyObject
}
}
(keyLabels[index] as NSString).draw( (keyLabels[index] as NSString).draw(
in: rctLabel, withAttributes: activeCandidateIndexAttr in: rctLabel, withAttributes: activeCandidateIndexAttr
) )
@ -267,7 +240,7 @@ private class vwrCandidateUniversal: NSView {
} }
switch isVerticalLayout { switch isVerticalLayout {
case true: case true:
var accuHeight: CGFloat = 0.0 var accuHeight = 0.0
for (index, elementHeight) in elementHeights.enumerated() { for (index, elementHeight) in elementHeights.enumerated() {
let currentHeight = elementHeight let currentHeight = elementHeight
@ -277,7 +250,7 @@ private class vwrCandidateUniversal: NSView {
accuHeight += currentHeight accuHeight += currentHeight
} }
case false: case false:
var accuWidth: CGFloat = 0.0 var accuWidth = 0.0
for (index, elementWidth) in elementWidths.enumerated() { for (index, elementWidth) in elementWidths.enumerated() {
let currentWidth = elementWidth let currentWidth = elementWidth
@ -322,7 +295,7 @@ private class vwrCandidateUniversal: NSView {
} }
} }
public class ctlCandidateUniversal: ctlCandidate { public class CtlCandidateUniversal: CtlCandidate {
private var candidateView: vwrCandidateUniversal private var candidateView: vwrCandidateUniversal
private var prevPageButton: NSButton private var prevPageButton: NSButton
private var nextPageButton: NSButton private var nextPageButton: NSButton
@ -408,6 +381,7 @@ public class ctlCandidateUniversal: ctlCandidate {
super.init(layout) super.init(layout)
window = panel window = panel
currentLayout = layout currentLayout = layout
candidateView.controller = self
candidateView.target = self candidateView.target = self
candidateView.action = #selector(candidateViewMouseDidClick(_:)) candidateView.action = #selector(candidateViewMouseDidClick(_:))
@ -431,9 +405,9 @@ public class ctlCandidateUniversal: ctlCandidate {
} }
@discardableResult override public func showNextPage() -> Bool { @discardableResult override public func showNextPage() -> Bool {
guard delegate != nil else { return false } guard let delegate = delegate else { return false }
if pageCount == 1 { return highlightNextCandidate() } if pageCount == 1 { return highlightNextCandidate() }
if currentPageIndex + 1 >= pageCount { IMEApp.buzz() } if currentPageIndex + 1 >= pageCount { delegate.buzz() }
currentPageIndex = (currentPageIndex + 1 >= pageCount) ? 0 : currentPageIndex + 1 currentPageIndex = (currentPageIndex + 1 >= pageCount) ? 0 : currentPageIndex + 1
if currentPageIndex == pageCount - 1 { if currentPageIndex == pageCount - 1 {
candidateView.highlightedIndex = min(lastPageContentCount - 1, candidateView.highlightedIndex) candidateView.highlightedIndex = min(lastPageContentCount - 1, candidateView.highlightedIndex)
@ -444,9 +418,9 @@ public class ctlCandidateUniversal: ctlCandidate {
} }
@discardableResult override public func showPreviousPage() -> Bool { @discardableResult override public func showPreviousPage() -> Bool {
guard delegate != nil else { return false } guard let delegate = delegate else { return false }
if pageCount == 1 { return highlightPreviousCandidate() } if pageCount == 1 { return highlightPreviousCandidate() }
if currentPageIndex == 0 { IMEApp.buzz() } if currentPageIndex == 0 { delegate.buzz() }
currentPageIndex = (currentPageIndex == 0) ? pageCount - 1 : currentPageIndex - 1 currentPageIndex = (currentPageIndex == 0) ? pageCount - 1 : currentPageIndex - 1
if currentPageIndex == pageCount - 1 { if currentPageIndex == pageCount - 1 {
candidateView.highlightedIndex = min(lastPageContentCount - 1, candidateView.highlightedIndex) candidateView.highlightedIndex = min(lastPageContentCount - 1, candidateView.highlightedIndex)
@ -459,7 +433,7 @@ public class ctlCandidateUniversal: ctlCandidate {
@discardableResult override public func highlightNextCandidate() -> Bool { @discardableResult override public func highlightNextCandidate() -> Bool {
guard let delegate = delegate else { return false } guard let delegate = delegate else { return false }
selectedCandidateIndex = selectedCandidateIndex =
(selectedCandidateIndex + 1 >= delegate.candidateCountForController(self)) (selectedCandidateIndex + 1 >= delegate.candidatePairs().count)
? 0 : selectedCandidateIndex + 1 ? 0 : selectedCandidateIndex + 1
return true return true
} }
@ -468,7 +442,7 @@ public class ctlCandidateUniversal: ctlCandidate {
guard let delegate = delegate else { return false } guard let delegate = delegate else { return false }
selectedCandidateIndex = selectedCandidateIndex =
(selectedCandidateIndex == 0) (selectedCandidateIndex == 0)
? delegate.candidateCountForController(self) - 1 : selectedCandidateIndex - 1 ? delegate.candidatePairs().count - 1 : selectedCandidateIndex - 1
return true return true
} }
@ -478,7 +452,7 @@ public class ctlCandidateUniversal: ctlCandidate {
} }
let result = currentPageIndex * keyLabels.count + index let result = currentPageIndex * keyLabels.count + index
return result < delegate.candidateCountForController(self) ? result : Int.max return result < delegate.candidatePairs().count ? result : Int.max
} }
override public var selectedCandidateIndex: Int { override public var selectedCandidateIndex: Int {
@ -490,7 +464,7 @@ public class ctlCandidateUniversal: ctlCandidate {
return return
} }
let keyLabelCount = keyLabels.count let keyLabelCount = keyLabels.count
if newValue < delegate.candidateCountForController(self) { if newValue < delegate.candidatePairs().count {
currentPageIndex = newValue / keyLabelCount currentPageIndex = newValue / keyLabelCount
candidateView.highlightedIndex = newValue % keyLabelCount candidateView.highlightedIndex = newValue % keyLabelCount
layoutCandidateView() layoutCandidateView()
@ -499,12 +473,12 @@ public class ctlCandidateUniversal: ctlCandidate {
} }
} }
extension ctlCandidateUniversal { extension CtlCandidateUniversal {
private var pageCount: Int { private var pageCount: Int {
guard let delegate = delegate else { guard let delegate = delegate else {
return 0 return 0
} }
let totalCount = delegate.candidateCountForController(self) let totalCount = delegate.candidatePairs().count
let keyLabelCount = keyLabels.count let keyLabelCount = keyLabels.count
return totalCount / keyLabelCount + ((totalCount % keyLabelCount) != 0 ? 1 : 0) return totalCount / keyLabelCount + ((totalCount % keyLabelCount) != 0 ? 1 : 0)
} }
@ -513,24 +487,22 @@ extension ctlCandidateUniversal {
guard let delegate = delegate else { guard let delegate = delegate else {
return 0 return 0
} }
let totalCount = delegate.candidateCountForController(self) let totalCount = delegate.candidatePairs().count
let keyLabelCount = keyLabels.count let keyLabelCount = keyLabels.count
return totalCount % keyLabelCount return totalCount % keyLabelCount
} }
private func layoutCandidateView() { private func layoutCandidateView() {
guard let delegate = delegate else { guard let delegate = delegate, let window = window else { return }
return
}
candidateView.set(keyLabelFont: keyLabelFont, candidateFont: candidateFont) candidateView.set(keyLabelFont: keyLabelFont, candidateFont: candidateFont)
var candidates = [(String, String)]() var candidates = [(String, String)]()
let count = delegate.candidateCountForController(self) let count = delegate.candidatePairs().count
let keyLabelCount = keyLabels.count let keyLabelCount = keyLabels.count
let begin = currentPageIndex * keyLabelCount let begin = currentPageIndex * keyLabelCount
for index in begin..<min(begin + keyLabelCount, count) { for index in begin..<min(begin + keyLabelCount, count) {
let candidate = delegate.ctlCandidate(self, candidateAtIndex: index) let candidate = delegate.candidatePairAt(index)
candidates.append(candidate) candidates.append(candidate)
} }
candidateView.set( candidateView.set(
@ -540,14 +512,14 @@ extension ctlCandidateUniversal {
var frameRect = candidateView.frame var frameRect = candidateView.frame
frameRect.size = newSize frameRect.size = newSize
candidateView.frame = frameRect candidateView.frame = frameRect
let counterHeight: CGFloat = newSize.height - 24 let counterHeight: Double = newSize.height - 24.0
if pageCount > 1, PrefMgr.shared.showPageButtonsInCandidateWindow { if pageCount > 1, showPageButtons {
var buttonRect = nextPageButton.frame var buttonRect = nextPageButton.frame
let spacing: CGFloat = 0.0 let spacing = 0.0
if currentLayout == .horizontal { buttonRect.size.height = floor(newSize.height / 2) } if currentLayout == .horizontal { buttonRect.size.height = floor(newSize.height / 2) }
let buttonOriginY: CGFloat = { let buttonOriginY: Double = {
if currentLayout == .vertical { if currentLayout == .vertical {
return counterHeight return counterHeight
} }
@ -582,12 +554,12 @@ extension ctlCandidateUniversal {
rect.size.height += 3 rect.size.height += 3
rect.size.width += 4 rect.size.width += 4
let rectOriginY: CGFloat = let rectOriginY: Double =
(currentLayout == .horizontal) (currentLayout == .horizontal)
? (newSize.height - rect.height) / 2 ? (newSize.height - rect.height) / 2
: counterHeight : counterHeight
let rectOriginX: CGFloat = let rectOriginX: Double =
PrefMgr.shared.showPageButtonsInCandidateWindow showPageButtons
? newSize.width ? newSize.width
: newSize.width + 4 : newSize.width + 4
rect.origin = NSPoint(x: rectOriginX, y: rectOriginY) rect.origin = NSPoint(x: rectOriginX, y: rectOriginY)
@ -598,12 +570,12 @@ extension ctlCandidateUniversal {
pageCounterLabel.isHidden = true pageCounterLabel.isHidden = true
} }
frameRect = window?.frame ?? NSRect.seniorTheBeast frameRect = window.frame
let topLeftPoint = NSPoint(x: frameRect.origin.x, y: frameRect.origin.y + frameRect.size.height) let topLeftPoint = NSPoint(x: frameRect.origin.x, y: frameRect.origin.y + frameRect.size.height)
frameRect.size = newSize frameRect.size = newSize
frameRect.origin = NSPoint(x: topLeftPoint.x, y: topLeftPoint.y - frameRect.size.height) frameRect.origin = NSPoint(x: topLeftPoint.x, y: topLeftPoint.y - frameRect.size.height)
window?.setFrame(frameRect, display: false) window.setFrame(frameRect, display: false)
candidateView.setNeedsDisplay(candidateView.bounds) candidateView.setNeedsDisplay(candidateView.bounds)
} }
@ -619,6 +591,6 @@ extension ctlCandidateUniversal {
} }
@objc private func candidateViewMouseDidClick(_: Any) { @objc private func candidateViewMouseDidClick(_: Any) {
delegate?.candidateSelected(at: selectedCandidateIndex) delegate?.candidatePairSelected(at: selectedCandidateIndex)
} }
} }

View File

@ -54,7 +54,7 @@ extension Preferences {
} }
} }
.modifier(Section.LabelWidthModifier(maximumWidth: $maximumLabelWidth)) .modifier(Section.LabelWidthModifier(maximumWidth: $maximumLabelWidth))
.frame(width: CGFloat(contentWidth), alignment: .leading) .frame(width: Double(contentWidth), alignment: .leading)
.padding(.vertical, 20) .padding(.vertical, 20)
.padding(.horizontal, 30) .padding(.horizontal, 30)
} }
@ -65,9 +65,9 @@ extension Preferences {
if index != sections.count - 1, sections[index].bottomDivider { if index != sections.count - 1, sections[index].bottomDivider {
Divider() Divider()
// Strangely doesn't work without width being specified. Probably because of custom alignment. // Strangely doesn't work without width being specified. Probably because of custom alignment.
.frame(width: CGFloat(contentWidth), height: 20) .frame(width: Double(contentWidth), height: 20)
.alignmentGuide(.preferenceSectionLabel) { .alignmentGuide(.preferenceSectionLabel) {
$0[.leading] + CGFloat(max(minimumLabelWidth, maximumLabelWidth)) $0[.leading] + Double(max(minimumLabelWidth, maximumLabelWidth))
} }
} }
} }

View File

@ -77,8 +77,8 @@ final class SegmentedControlStyleViewController: NSViewController, PreferencesSt
) )
}() }()
let segmentBorderWidth = CGFloat(preferencePanes.count) + 1 let segmentBorderWidth = Double(preferencePanes.count) + 1
let segmentWidth = segmentSize.width * CGFloat(preferencePanes.count) + segmentBorderWidth let segmentWidth = segmentSize.width * Double(preferencePanes.count) + segmentBorderWidth
let segmentHeight = segmentSize.height let segmentHeight = segmentSize.height
segmentedControl.frame = CGRect(x: 0, y: 0, width: segmentWidth, height: segmentHeight) segmentedControl.frame = CGRect(x: 0, y: 0, width: segmentWidth, height: segmentHeight)

View File

@ -0,0 +1,9 @@
.DS_Store
/.build
/Packages
/*.xcodeproj
xcuserdata/
DerivedData/
.swiftpm/config/registries.json
.swiftpm/xcode/package.xcworkspace/contents.xcworkspacedata
.netrc

View File

@ -0,0 +1,26 @@
// swift-tools-version:5.3
import PackageDescription
let package = Package(
name: "CandidateWindow",
platforms: [
.macOS(.v10_11)
],
products: [
.library(
name: "CandidateWindow",
targets: ["CandidateWindow"]
)
],
dependencies: [
.package(path: "../vChewing_Shared")
],
targets: [
.target(
name: "CandidateWindow",
dependencies: [
.product(name: "Shared", package: "vChewing_Shared")
]
)
]
)

View File

@ -0,0 +1,13 @@
# CandidateWindow
用以定義與威注音的選字窗有關的基礎內容,目前尚未完工。
```
// (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.
```

View File

@ -0,0 +1,147 @@
// (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 Cocoa
import Shared
open class CtlCandidate: NSWindowController, CtlCandidateProtocol {
open var showPageButtons: Bool = false
open var currentLayout: CandidateLayout = .horizontal
open var locale: String = ""
open var useLangIdentifier: Bool = false
open func highlightedColor() -> NSColor {
var result = NSColor.alternateSelectedControlColor
var colorBlendAmount: Double = NSApplication.isDarkMode ? 0.3 : 0.0
if #available(macOS 10.14, *), !NSApplication.isDarkMode, locale == "zh-Hant" {
colorBlendAmount = 0.15
}
// The background color of the highlightened candidate
switch locale {
case "zh-Hans":
result = NSColor.systemRed
case "zh-Hant":
result = NSColor.systemBlue
case "ja":
result = NSColor.systemBrown
default: break
}
var blendingAgainstTarget: NSColor = NSApplication.isDarkMode ? NSColor.black : NSColor.white
if #unavailable(macOS 10.14) {
colorBlendAmount = 0.3
blendingAgainstTarget = NSColor.white
}
return result.blended(withFraction: colorBlendAmount, of: blendingAgainstTarget)!
}
open weak var delegate: CtlCandidateDelegate? {
didSet {
reloadData()
}
}
open var windowTopLeftPoint: NSPoint {
get {
guard let frameRect = window?.frame else { return NSPoint.zero }
return NSPoint(x: frameRect.minX, y: frameRect.maxY)
}
set {
DispatchQueue.main.async {
self.set(windowTopLeftPoint: newValue, bottomOutOfScreenAdjustmentHeight: 0)
}
}
}
open var selectedCandidateIndex: Int = .max
open var visible = false {
didSet {
NSObject.cancelPreviousPerformRequests(withTarget: self)
DispatchQueue.main.async { [self] in
_ = visible ? window?.orderFront(self) : window?.orderOut(self)
}
}
}
public required init(_: CandidateLayout = .horizontal) {
super.init(window: .init())
visible = false
}
/// Sets the location of the candidate window.
///
/// Please note that the method has side effects that modifies
/// `windowTopLeftPoint` to make the candidate window to stay in at least
/// in a screen.
///
/// - Parameters:
/// - windowTopLeftPoint: The given location.
/// - height: The height that helps the window not to be out of the bottom
/// of a screen.
public func set(windowTopLeftPoint: NSPoint, bottomOutOfScreenAdjustmentHeight heightDelta: Double) {
DispatchQueue.main.async { [self] in
guard let window = window, var screenFrame = NSScreen.main?.visibleFrame else { return }
let windowSize = window.frame.size
var adjustedPoint = windowTopLeftPoint
var delta = heightDelta
for frame in NSScreen.screens.map(\.visibleFrame).filter({ $0.contains(windowTopLeftPoint) }) {
screenFrame = frame
break
}
if delta > screenFrame.size.height / 2.0 { delta = 0.0 }
if adjustedPoint.y < screenFrame.minY + windowSize.height {
adjustedPoint.y = windowTopLeftPoint.y + windowSize.height + delta
}
adjustedPoint.y = min(adjustedPoint.y, screenFrame.maxY - 1.0)
adjustedPoint.x = min(max(adjustedPoint.x, screenFrame.minX), screenFrame.maxX - windowSize.width - 1.0)
window.setFrameTopLeftPoint(adjustedPoint)
}
}
// MARK: - Contents that are not needed to be implemented here.
@available(*, unavailable)
public required init?(coder _: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
open var keyLabels: [CandidateKeyLabel] = ["1", "2", "3", "4", "5", "6", "7", "8", "9"]
.map {
CandidateKeyLabel(key: $0, displayedText: $0)
}
open var candidateFont = NSFont.systemFont(ofSize: 18)
open var keyLabelFont = NSFont.monospacedDigitSystemFont(ofSize: 14, weight: .medium)
open var tooltip: String = ""
@discardableResult open func highlightNextCandidate() -> Bool {
false
}
@discardableResult open func highlightPreviousCandidate() -> Bool {
false
}
@discardableResult open func showNextPage() -> Bool {
false
}
@discardableResult open func showPreviousPage() -> Bool {
false
}
open func candidateIndexAtKeyLabelIndex(_: Int) -> Int {
Int.max
}
open func reloadData() {}
}

View File

@ -221,6 +221,15 @@ extension vChewingLM {
return !unigramsFor(key: key).isEmpty return !unigramsFor(key: key).isEmpty
} }
///
/// - Parameters:
/// - key:
/// - value:
/// - Returns:
public func hasKeyValuePairFor(key: String, value: String) -> Bool {
unigramsFor(key: key).map(\.value).contains(value)
}
/// LMI /// LMI
/// - Parameter key: /// - Parameter key:
/// - Returns: /// - Returns:

View File

@ -13,7 +13,7 @@ Megrez Engine is a module made for processing lingual data of an input method. T
### §1. 初期化 ### §1. 初期化
在你的 ctlInputMethod (InputMethodController) 或者 KeyHandler 內初期化一份 Megrez.Compositor 組字器副本(這裡將該副本命名為「`compositor`」)。由於 Megrez.Compositor 的型別是 Struct 型別(為了讓 Compositor 可以 deep copy所以其副本可以用 var 來宣告。 在你的 IMKInputController 或者 KeyHandler 內初期化一份 Megrez.Compositor 組字器副本(這裡將該副本命名為「`compositor`」)。由於 Megrez.Compositor 的型別是 Struct 型別(為了讓 Compositor 可以 deep copy所以其副本可以用 var 來宣告。
以 KeyHandler 為例: 以 KeyHandler 為例:
```swift ```swift
@ -24,17 +24,17 @@ class KeyHandler {
} }
``` ```
ctlInputMethod 為例: IMKInputController 為例:
```swift ```swift
@objc(ctlInputMethod) // 根據 info.plist 內的情況來確定型別的命名 @objc(IMKMyInputController) // 根據 info.plist 內的情況來確定型別的命名
class ctlInputMethod: IMKInputController { class IMKMyInputController: IMKInputController {
// 先設定好變數 // 先設定好變數
var compositor: Megrez.Compositor = .init() var compositor: Megrez.Compositor = .init()
... ...
} }
``` ```
由於 Swift 會在某個大副本KeyHandler 或者 ctlInputMethod 副本)被銷毀的時候自動銷毀其中的全部副本,所以 Megrez.Compositor 的副本初期化沒必要寫在 init() 當中。但你很可能會想在 init() 時指定 Tekkon.Composer 所對接的語言模組型別、以及其可以允許的最大詞長。 由於 Swift 會在某個大副本KeyHandler 或者 IMKInputController 副本)被銷毀的時候自動銷毀其中的全部副本,所以 Megrez.Compositor 的副本初期化沒必要寫在 init() 當中。但你很可能會想在 init() 時指定 Tekkon.Composer 所對接的語言模組型別、以及其可以允許的最大詞長。
這裡就需要在 init() 時使用參數: 這裡就需要在 init() 時使用參數:
```swift ```swift

View File

@ -0,0 +1,9 @@
.DS_Store
/.build
/Packages
/*.xcodeproj
xcuserdata/
DerivedData/
.swiftpm/config/registries.json
.swiftpm/xcode/package.xcworkspace/contents.xcworkspacedata
.netrc

View File

@ -0,0 +1,22 @@
// swift-tools-version:5.3
import PackageDescription
let package = Package(
name: "NotifierUI",
platforms: [
.macOS(.v10_11)
],
products: [
.library(
name: "NotifierUI",
targets: ["NotifierUI"]
)
],
dependencies: [],
targets: [
.target(
name: "NotifierUI",
dependencies: []
)
]
)

View File

@ -0,0 +1,13 @@
# NotifierUI
威注音的飄雲通知視窗。
```
// (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.
```

View File

@ -0,0 +1,155 @@
// (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 Cocoa
public class Notifier: NSWindowController {
public static func notify(message: String) {
Self.message = message
}
static var message: String = "" {
didSet {
if !Self.message.isEmpty {
Self.message = Notifier(message).blankValue
}
}
}
// MARK: - Private Declarations
private static var instanceStack: [Notifier] = []
private let blankValue = ""
@discardableResult private init(_ message: String) {
let rawMessage = message.replacingOccurrences(of: "\n", with: "")
guard let screenRect = NSScreen.main?.visibleFrame, !rawMessage.isEmpty else {
super.init(window: nil)
return
}
let kLargeFontSize: Double = 17
let kSmallFontSize: Double = 15
let messageArray = message.components(separatedBy: "\n")
let paraStyle = NSMutableParagraphStyle()
paraStyle.setParagraphStyle(NSParagraphStyle.default)
paraStyle.alignment = .center
let attrTitle: [NSAttributedString.Key: AnyObject] = [
.foregroundColor: NSColor.controlTextColor,
.font: NSFont.boldSystemFont(ofSize: kLargeFontSize),
.paragraphStyle: paraStyle,
]
let attrString = NSMutableAttributedString(string: messageArray[0], attributes: attrTitle)
let attrAlt: [NSAttributedString.Key: AnyObject] = [
.foregroundColor: NSColor.secondaryLabelColor,
.font: NSFont.systemFont(ofSize: kSmallFontSize),
.paragraphStyle: paraStyle,
]
let additionalString = messageArray.count > 1 ? "\n\(messageArray[1])" : ""
let attrStringAlt = NSMutableAttributedString(string: additionalString, attributes: attrAlt)
attrString.insert(attrStringAlt, at: attrString.length)
let textRect: NSRect = attrString.boundingRect(
with: NSSize(width: 1600.0, height: 1600.0), options: [.usesLineFragmentOrigin]
)
let windowWidth = Double(4) * kLargeFontSize + textRect.width
let contentRect = NSRect(x: 0, y: 0, width: windowWidth, height: 60.0)
var windowRect = contentRect
windowRect.origin.x = screenRect.maxX - windowRect.width - 10
windowRect.origin.y = screenRect.maxY - windowRect.height - 10
let styleMask: NSWindow.StyleMask = [.borderless]
let transparentVisualEffect = NSVisualEffectView()
transparentVisualEffect.blendingMode = .behindWindow
transparentVisualEffect.state = .active
let theWindow = NSWindow(
contentRect: windowRect, styleMask: styleMask, backing: .buffered, defer: false
)
theWindow.contentView = transparentVisualEffect
theWindow.isMovableByWindowBackground = true
theWindow.level = NSWindow.Level(Int(kCGPopUpMenuWindowLevel))
theWindow.hasShadow = true
theWindow.backgroundColor = .textBackgroundColor
theWindow.title = ""
theWindow.titlebarAppearsTransparent = true
theWindow.titleVisibility = .hidden
theWindow.showsToolbarButton = false
theWindow.standardWindowButton(NSWindow.ButtonType.zoomButton)?.isHidden = true
theWindow.standardWindowButton(NSWindow.ButtonType.miniaturizeButton)?.isHidden = true
theWindow.standardWindowButton(NSWindow.ButtonType.closeButton)?.isHidden = true
theWindow.standardWindowButton(NSWindow.ButtonType.zoomButton)?.isHidden = true
theWindow.isReleasedWhenClosed = true
theWindow.isMovable = false
let lblMessage = NSTextField()
lblMessage.attributedStringValue = attrString
lblMessage.drawsBackground = false
lblMessage.font = .boldSystemFont(ofSize: NSFont.systemFontSize(for: .regular))
lblMessage.frame = contentRect
lblMessage.isBezeled = false
lblMessage.isEditable = false
lblMessage.isSelectable = false
lblMessage.textColor = .controlTextColor
theWindow.contentView?.addSubview(lblMessage)
let x = lblMessage.frame.origin.x
let y = ((theWindow.frame.height) - textRect.height) / 1.9
let newFrame = NSRect(x: x, y: y, width: theWindow.frame.width, height: textRect.height)
lblMessage.frame = newFrame
super.init(window: theWindow)
display()
}
@available(*, unavailable)
required init?(coder _: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
override public func close() {
super.close()
}
}
// MARK: - Private Functions
extension Notifier {
private func shiftExistingWindowPositions() {
guard let window = window, !Self.instanceStack.isEmpty else { return }
for theInstanceWindow in Self.instanceStack.compactMap(\.window) {
var theOrigin = theInstanceWindow.frame
theOrigin.origin.y -= (10 + window.frame.height)
theInstanceWindow.setFrame(theOrigin, display: true)
}
}
private func fadeIn() {
guard let window = window else { return }
let afterRect = window.frame
var beforeRect = afterRect
beforeRect.origin.x -= 20
window.setFrame(beforeRect, display: true)
window.orderFront(self)
window.setFrame(afterRect, display: true, animate: true)
}
private func display() {
let existingInstanceArray = Self.instanceStack.compactMap(\.window)
if !existingInstanceArray.isEmpty {
existingInstanceArray.forEach { $0.alphaValue *= 0.5 }
}
shiftExistingWindowPositions()
fadeIn()
Self.instanceStack.insert(self, at: 0)
DispatchQueue.main.asyncAfter(deadline: .now() + 2) {
self.close()
Self.instanceStack.removeAll(where: { $0.window == nil })
}
}
}

View File

@ -0,0 +1,9 @@
.DS_Store
/.build
/Packages
/*.xcodeproj
xcuserdata/
DerivedData/
.swiftpm/config/registries.json
.swiftpm/xcode/package.xcworkspace/contents.xcworkspacedata
.netrc

View File

@ -0,0 +1,26 @@
// swift-tools-version:5.3
import PackageDescription
let package = Package(
name: "PopupCompositionBuffer",
platforms: [
.macOS(.v10_11)
],
products: [
.library(
name: "PopupCompositionBuffer",
targets: ["PopupCompositionBuffer"]
)
],
dependencies: [
.package(path: "../vChewing_Shared")
],
targets: [
.target(
name: "PopupCompositionBuffer",
dependencies: [
.product(name: "Shared", package: "vChewing_Shared")
]
)
]
)

View File

@ -0,0 +1,13 @@
# NotifierUI
威注音的浮動組字窗。
```
// (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.
```

View File

@ -6,7 +6,10 @@
// 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.
public class ctlPopupCompositionBuffer: NSWindowController { import Cocoa
import Shared
public class PopupCompositionBuffer: NSWindowController {
public var isTypingDirectionVertical = false { public var isTypingDirectionVertical = false {
didSet { didSet {
if #unavailable(macOS 10.14) { if #unavailable(macOS 10.14) {
@ -33,7 +36,7 @@ public class ctlPopupCompositionBuffer: NSWindowController {
panel.hasShadow = true panel.hasShadow = true
panel.backgroundColor = NSColor.controlBackgroundColor panel.backgroundColor = NSColor.controlBackgroundColor
panel.styleMask = .fullSizeContentView panel.styleMask = .fullSizeContentView
panel.isMovable = false
messageTextField = NSTextField() messageTextField = NSTextField()
messageTextField.isEditable = false messageTextField.isEditable = false
messageTextField.isSelectable = false messageTextField.isSelectable = false
@ -58,7 +61,7 @@ public class ctlPopupCompositionBuffer: NSWindowController {
return return
} }
let attrString: NSMutableAttributedString = .init(string: state.data.displayedTextConverted) let attrString: NSMutableAttributedString = .init(string: state.displayedTextConverted)
let verticalAttributes: [NSAttributedString.Key: Any] = [ let verticalAttributes: [NSAttributedString.Key: Any] = [
.verticalGlyphForm: true, .verticalGlyphForm: true,
.paragraphStyle: { .paragraphStyle: {
@ -75,7 +78,7 @@ public class ctlPopupCompositionBuffer: NSWindowController {
if isTypingDirectionVertical { if isTypingDirectionVertical {
attrString.setAttributes( attrString.setAttributes(
verticalAttributes, range: NSRange(location: 0, length: attrString.string.utf16.count) verticalAttributes, range: NSRange(location: 0, length: attrString.length)
) )
} }
@ -95,8 +98,8 @@ public class ctlPopupCompositionBuffer: NSWindowController {
attrString.setAttributes( attrString.setAttributes(
markerAttributes, markerAttributes,
range: NSRange( range: NSRange(
location: state.data.u16MarkedRange.lowerBound, location: state.u16MarkedRange.lowerBound,
length: state.data.u16MarkedRange.upperBound - state.data.u16MarkedRange.lowerBound length: state.u16MarkedRange.upperBound - state.u16MarkedRange.lowerBound
) )
) )
@ -123,12 +126,12 @@ public class ctlPopupCompositionBuffer: NSWindowController {
isTypingDirectionVertical isTypingDirectionVertical
? NSMutableAttributedString(string: "", attributes: cursorAttributes) ? NSMutableAttributedString(string: "", attributes: cursorAttributes)
: NSMutableAttributedString(string: "_", attributes: cursorAttributes) : NSMutableAttributedString(string: "_", attributes: cursorAttributes)
attrString.insert(attrCursor, at: state.data.u16Cursor) attrString.insert(attrCursor, at: state.u16Cursor)
textShown = attrString textShown = attrString
messageTextField.maximumNumberOfLines = 1 messageTextField.maximumNumberOfLines = 1
if let editor = messageTextField.currentEditor() { if let editor = messageTextField.currentEditor() {
editor.selectedRange = NSRange(state.data.u16MarkedRange) editor.selectedRange = NSRange(state.u16MarkedRange)
} }
window?.orderFront(nil) window?.orderFront(nil)
set(windowOrigin: point) set(windowOrigin: point)
@ -165,7 +168,7 @@ public class ctlPopupCompositionBuffer: NSWindowController {
with: NSSize(width: 1600.0, height: 1600.0), with: NSSize(width: 1600.0, height: 1600.0),
options: [.usesLineFragmentOrigin, .usesFontLeading] options: [.usesLineFragmentOrigin, .usesFontLeading]
) )
rect.size.width = max(rect.size.width, 20 * CGFloat(attrString.string.count)) + 2 rect.size.width = max(rect.size.width, 20 * Double(attrString.string.count)) + 2
rect.size.height *= 1.2 rect.size.height *= 1.2
rect.size.height = max(22, rect.size.height) rect.size.height = max(22, rect.size.height)
if isTypingDirectionVertical { if isTypingDirectionVertical {

View File

@ -0,0 +1,41 @@
// (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 Cocoa
public protocol CtlCandidateDelegate: AnyObject {
func candidatePairs() -> [(String, String)]
func candidatePairAt(_ index: Int) -> (String, String)
func candidatePairSelected(at index: Int)
func buzz()
func kanjiConversionIfRequired(_ target: String) -> String
}
public protocol CtlCandidateProtocol {
var locale: String { get set }
var currentLayout: CandidateLayout { get set }
var delegate: CtlCandidateDelegate? { get set }
var selectedCandidateIndex: Int { get set }
var visible: Bool { get set }
var windowTopLeftPoint: NSPoint { get set }
var keyLabels: [CandidateKeyLabel] { get set }
var keyLabelFont: NSFont { get set }
var candidateFont: NSFont { get set }
var tooltip: String { get set }
var useLangIdentifier: Bool { get set }
var showPageButtons: Bool { get set }
init(_ layout: CandidateLayout)
func reloadData()
func showNextPage() -> Bool
func showPreviousPage() -> Bool
func highlightNextCandidate() -> Bool
func highlightPreviousCandidate() -> Bool
func candidateIndexAtKeyLabelIndex(_: Int) -> Int
func set(windowTopLeftPoint: NSPoint, bottomOutOfScreenAdjustmentHeight height: Double)
}

View File

@ -0,0 +1,64 @@
// (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 Cocoa
// IMEState
public protocol IMEStateProtocol {
var type: StateType { get }
var data: StateDataProtocol { get }
var isASCIIMode: Bool { get set }
var isVerticalTyping: Bool { get set }
var isVerticalCandidateWindow: Bool { get set }
var candidates: [(String, String)] { get set }
var hasComposition: Bool { get }
var isCandidateContainer: Bool { get }
var displayedText: String { get }
var displayedTextConverted: String { get }
var textToCommit: String { get set }
var tooltip: String { get set }
var attributedString: NSAttributedString { get }
var convertedToInputting: IMEStateProtocol { get }
var isFilterable: Bool { get }
var isMarkedLengthValid: Bool { get }
var node: CandidateNode { get set }
var displayTextSegments: [String] { get }
var tooltipBackupForInputting: String { get set }
var markedRange: Range<Int> { get }
var u16MarkedRange: Range<Int> { get }
var u16Cursor: Int { get }
var cursor: Int { get set }
var marker: Int { get set }
}
public protocol StateDataProtocol {
var cursor: Int { get set }
var marker: Int { get set }
var markedRange: Range<Int> { get }
var u16MarkedRange: Range<Int> { get }
var u16Cursor: Int { get }
var textToCommit: String { get set }
var markedReadings: [String] { get set }
var displayTextSegments: [String] { get set }
var isFilterable: Bool { get }
var isVerticalTyping: Bool { get set }
var isMarkedLengthValid: Bool { get }
var candidates: [(String, String)] { get set }
var displayedText: String { get set }
var displayedTextConverted: String { get }
var tooltipBackupForInputting: String { get set }
var tooltip: String { get set }
var attributedStringNormal: NSAttributedString { get }
var attributedStringMarking: NSAttributedString { get }
var attributedStringPlaceholder: NSAttributedString { get }
var userPhraseDumped: String { get }
var userPhraseDumpedConverted: String { get }
var doesUserPhraseExist: Bool { get }
var tooltipColorState: TooltipColorState { get set }
mutating func updateTooltipForMarking()
}

View File

@ -103,6 +103,50 @@ public enum UserDef: String, CaseIterable {
} }
} }
// MARK: - Enums and Structs used by Candidate Window
public enum CandidateLayout {
case horizontal
case vertical
}
public struct CandidateKeyLabel {
public private(set) var key: String
public private(set) var displayedText: String
public init(key: String, displayedText: String) {
self.key = key
self.displayedText = displayedText
}
}
// MARK: - Tooltip Color States
public enum TooltipColorState {
case normal
case redAlert
case warning
case denialOverflow
case denialInsufficiency
case prompt
}
// MARK: - IMEState types.
// enum
public enum StateType: String {
case ofDeactivated = "Deactivated"
case ofEmpty = "Empty"
case ofAbortion = "Abortion" // Empty
case ofCommitting = "Committing"
case ofAssociates = "Associates"
case ofNotEmpty = "NotEmpty"
case ofInputting = "Inputting"
case ofMarking = "Marking"
case ofCandidates = "Candidates"
case ofSymbolTable = "SymbolTable"
}
// MARK: - Parser for Syllable composer // MARK: - Parser for Syllable composer
public enum KeyboardParser: Int, CaseIterable { public enum KeyboardParser: Int, CaseIterable {

View File

@ -23,7 +23,7 @@ Regarding pinyin input support, we only support: Hanyu Pinyin, Secondary Pinyin,
### §1. 初期化 ### §1. 初期化
在你的 ctlInputMethod (InputMethodController) 或者 KeyHandler 內初期化一份 Tekkon.Composer 注拼槽副本(這裡將該副本命名為「`_composer`」)。由於 Tekkon.Composer 的型別是 Struct 型別所以其副本必須為變數var否則無法自我 mutate。 在你的 IMKInputController (InputMethodController) 或者 KeyHandler 內初期化一份 Tekkon.Composer 注拼槽副本(這裡將該副本命名為「`_composer`」)。由於 Tekkon.Composer 的型別是 Struct 型別所以其副本必須為變數var否則無法自我 mutate。
以 KeyHandler 為例: 以 KeyHandler 為例:
```swift ```swift
@ -34,10 +34,10 @@ class KeyHandler: NSObject {
} }
``` ```
ctlInputMethod 為例: IMKInputController 為例:
```swift ```swift
@objc(ctlInputMethod) // 根據 info.plist 內的情況來確定型別的命名 @objc(IMKMyInputController) // 根據 info.plist 內的情況來確定型別的命名
class ctlInputMethod: IMKInputController { class IMKMyInputController: IMKInputController {
// 先設定好變數 // 先設定好變數
var _composer: Tekkon.Composer = .init() var _composer: Tekkon.Composer = .init()
... ...
@ -45,7 +45,7 @@ class ctlInputMethod: IMKInputController {
``` ```
由於 Swift 會在某個大副本KeyHandler 或者 ctlInputMethod 副本)被銷毀的時候自動銷毀其中的全部副本,所以 Tekkon.Composer 的副本初期化沒必要寫在 init() 當中。但你很可能會想在 init() 時指定 Tekkon.Composer 所使用的注音排列(是大千?還是倚天傳統?還是神通?等)。 由於 Swift 會在某個大副本KeyHandler 或者 IMKInputController 副本)被銷毀的時候自動銷毀其中的全部副本,所以 Tekkon.Composer 的副本初期化沒必要寫在 init() 當中。但你很可能會想在 init() 時指定 Tekkon.Composer 所使用的注音排列(是大千?還是倚天傳統?還是神通?等)。
這裡就需要在 _composer 這個副本所在的型別當中額外寫一個過程函式。 這裡就需要在 _composer 這個副本所在的型別當中額外寫一個過程函式。
@ -159,9 +159,9 @@ final class TekkonTests: XCTestCase {
#### // 2. 訊號處理 #### // 2. 訊號處理
無論是 KeyHandler 還是 ctlInputMethod 都得要處理被傳入的 NSEvent 當中的 charCode 訊號。 無論是 KeyHandler 還是 IMKInputController 都得要處理被傳入的 NSEvent 當中的 charCode 訊號。
比如 ctlInputMethod 內: 比如 IMKInputController 內:
```swift ```swift
func handleInputText(_ inputText: String?, key keyCode: Int, modifiers flags: Int, client: Any?) -> Bool { func handleInputText(_ inputText: String?, key keyCode: Int, modifiers flags: Int, client: Any?) -> Bool {
... ...

View File

@ -0,0 +1,9 @@
.DS_Store
/.build
/Packages
/*.xcodeproj
xcuserdata/
DerivedData/
.swiftpm/config/registries.json
.swiftpm/xcode/package.xcworkspace/contents.xcworkspacedata
.netrc

View File

@ -0,0 +1,30 @@
// swift-tools-version:5.3
import PackageDescription
let package = Package(
name: "TooltipUI",
platforms: [
.macOS(.v10_11)
],
products: [
.library(
name: "TooltipUI",
targets: ["TooltipUI"]
)
],
dependencies: [
.package(path: "../Fuziki_NSAttributedTextView"),
.package(path: "../vChewing_CocoaExtension"),
.package(path: "../vChewing_Shared"),
],
targets: [
.target(
name: "TooltipUI",
dependencies: [
.product(name: "NSAttributedTextView", package: "Fuziki_NSAttributedTextView"),
.product(name: "CocoaExtension", package: "vChewing_CocoaExtension"),
.product(name: "Shared", package: "vChewing_Shared"),
]
)
]
)

View File

@ -0,0 +1,13 @@
# NotifierUI
威注音的工具提示視窗。
```
// (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.
```

View File

@ -6,18 +6,12 @@
// 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 Cocoa
import CocoaExtension
import NSAttributedTextView import NSAttributedTextView
import Shared
public class ctlTooltip: NSWindowController { public class TooltipUI: NSWindowController {
public enum ColorStates {
case normal
case redAlert
case warning
case denialOverflow
case denialInsufficiency
case prompt
}
private var messageText: NSAttributedTooltipTextView private var messageText: NSAttributedTooltipTextView
private var tooltip: String = "" { private var tooltip: String = "" {
didSet { didSet {
@ -43,6 +37,7 @@ public class ctlTooltip: NSWindowController {
panel.level = NSWindow.Level(Int(kCGPopUpMenuWindowLevel) + 2) panel.level = NSWindow.Level(Int(kCGPopUpMenuWindowLevel) + 2)
panel.hasShadow = true panel.hasShadow = true
panel.backgroundColor = NSColor.controlBackgroundColor panel.backgroundColor = NSColor.controlBackgroundColor
panel.isMovable = false
messageText = NSAttributedTooltipTextView() messageText = NSAttributedTooltipTextView()
messageText.backgroundColor = NSColor.controlBackgroundColor messageText.backgroundColor = NSColor.controlBackgroundColor
messageText.textColor = NSColor.textColor messageText.textColor = NSColor.textColor
@ -57,7 +52,7 @@ public class ctlTooltip: NSWindowController {
public func show( public func show(
tooltip: String = "", at point: NSPoint, tooltip: String = "", at point: NSPoint,
bottomOutOfScreenAdjustmentHeight heightDelta: CGFloat, bottomOutOfScreenAdjustmentHeight heightDelta: Double,
direction: NSAttributedTooltipTextView.writingDirection = .horizontal direction: NSAttributedTooltipTextView.writingDirection = .horizontal
) { ) {
self.direction = direction self.direction = direction
@ -66,7 +61,7 @@ public class ctlTooltip: NSWindowController {
set(windowTopLeftPoint: point, bottomOutOfScreenAdjustmentHeight: heightDelta) set(windowTopLeftPoint: point, bottomOutOfScreenAdjustmentHeight: heightDelta)
} }
public func setColor(state: ColorStates) { public func setColor(state: TooltipColorState) {
var backgroundColor = NSColor.controlBackgroundColor var backgroundColor = NSColor.controlBackgroundColor
var textColor = NSColor.textColor var textColor = NSColor.textColor
switch state { switch state {
@ -123,7 +118,7 @@ public class ctlTooltip: NSWindowController {
window?.orderOut(nil) window?.orderOut(nil)
} }
private func set(windowTopLeftPoint: NSPoint, bottomOutOfScreenAdjustmentHeight heightDelta: CGFloat) { private func set(windowTopLeftPoint: NSPoint, bottomOutOfScreenAdjustmentHeight heightDelta: Double) {
guard let window = window else { return } guard let window = window else { return }
let windowSize = window.frame.size let windowSize = window.frame.size

View File

@ -91,7 +91,7 @@ P.S.: 威注音输入法的 Shift 按键监测功能仅借由对 NSEvent 讯号
威注音专案目前仅用到小麦注音的下述程式组件MIT License 威注音专案目前仅用到小麦注音的下述程式组件MIT License
- 仅供研发人员调试方便而使用的 App 版安装程式 (by Zonble Yang),不对公众使用。 - 仅供研发人员调试方便而使用的 App 版安装程式 (by Zonble Yang),不对公众使用。
- Voltaire MK2 选字窗、飘云通知视窗 (by Zonble Yang),有大幅度修改。 - Voltaire MK2 选字窗 (by Zonble Yang),有大幅度修改。
威注音专案目前还用到如下的来自 Lukhnos Liu 的算法: 威注音专案目前还用到如下的来自 Lukhnos Liu 的算法:

View File

@ -91,7 +91,7 @@ P.S.: 威注音輸入法的 Shift 按鍵監測功能僅藉由對 NSEvent 訊號
威注音專案目前僅用到小麥注音的下述程式組件MIT License 威注音專案目前僅用到小麥注音的下述程式組件MIT License
- 僅供研發人員調試方便而使用的 App 版安裝程式 (by Zonble Yang),不對公眾使用。 - 僅供研發人員調試方便而使用的 App 版安裝程式 (by Zonble Yang),不對公眾使用。
- Voltaire MK2 選字窗、飄雲通知視窗 (by Zonble Yang),有大幅度修改。 - Voltaire MK2 選字窗 (by Zonble Yang),有大幅度修改。
威注音專案目前還用到如下的來自 Lukhnos Liu 的算法: 威注音專案目前還用到如下的來自 Lukhnos Liu 的算法:

@ -1 +1 @@
Subproject commit 33487f554d2306f43d100c9c5b8ce99c2109ca52 Subproject commit 6f71610f126eee8efcce4a4ff832bec03af7c79b

View File

@ -73,7 +73,7 @@ public enum ChineseConverter {
/// ///
/// - Parameter string: Text in Original Script. /// - Parameter string: Text in Original Script.
/// - Returns: Text converted to Different Script. /// - Returns: Text converted to Different Script.
public static func crossConvert(_ string: String) -> String? { public static func crossConvert(_ string: String) -> String {
switch IMEApp.currentInputMode { switch IMEApp.currentInputMode {
case .imeModeCHS: case .imeModeCHS:
return shared.convert(string, to: .zhHantTW) return shared.convert(string, to: .zhHantTW)

View File

@ -7,46 +7,9 @@
// requirements defined in MIT License. // requirements defined in MIT License.
import LangModelAssembly import LangModelAssembly
import Shared
// enum /// SessionCtl
public enum StateType: String {
case ofDeactivated = "Deactivated"
case ofEmpty = "Empty"
case ofAbortion = "Abortion" // Empty
case ofCommitting = "Committing"
case ofAssociates = "Associates"
case ofNotEmpty = "NotEmpty"
case ofInputting = "Inputting"
case ofMarking = "Marking"
case ofCandidates = "Candidates"
case ofSymbolTable = "SymbolTable"
}
// IMEState
public protocol IMEStateProtocol {
var type: StateType { get }
var data: StateData { get }
var isASCIIMode: Bool { get set }
var isVerticalTyping: Bool { get set }
var isVerticalCandidateWindow: Bool { get set }
var candidates: [(String, String)] { get }
var hasComposition: Bool { get }
var isCandidateContainer: Bool { get }
var displayedText: String { get }
var textToCommit: String { get set }
var tooltip: String { get set }
var attributedString: NSAttributedString { get }
var convertedToInputting: IMEState { get }
var isFilterable: Bool { get }
var isMarkedLengthValid: Bool { get }
var node: CandidateNode { get set }
var cursor: Int { get }
var displayTextSegments: [String] { get }
var tooltipBackupForInputting: String { get set }
var markedRange: Range<Int> { get }
}
/// ctlInputMethod
/// ///
/// Finite State Machine/ /// Finite State Machine/
/// 使 /// 使
@ -79,17 +42,17 @@ public protocol IMEStateProtocol {
/// - .SymbolTable: /// - .SymbolTable:
public struct IMEState: IMEStateProtocol { public struct IMEState: IMEStateProtocol {
public var type: StateType = .ofEmpty public var type: StateType = .ofEmpty
public var data: StateData = .init() public var data: StateDataProtocol = StateData() as StateDataProtocol
public var node: CandidateNode = .init(name: "") public var node: CandidateNode = .init(name: "")
public var isASCIIMode = false public var isASCIIMode = false
public var isVerticalCandidateWindow = false public var isVerticalCandidateWindow = false
init(_ data: StateData = .init(), type: StateType = .ofEmpty) { init(_ data: StateDataProtocol = StateData() as StateDataProtocol, type: StateType = .ofEmpty) {
self.data = data self.data = data
self.type = type self.type = type
isVerticalTyping = ctlInputMethod.isVerticalTyping isVerticalTyping = SessionCtl.isVerticalTyping
} }
init(_ data: StateData = .init(), type: StateType = .ofEmpty, node: CandidateNode) { init(_ data: StateDataProtocol = StateData() as StateDataProtocol, type: StateType = .ofEmpty, node: CandidateNode) {
self.data = data self.data = data
self.type = type self.type = type
self.node = node self.node = node
@ -105,14 +68,14 @@ extension IMEState {
public static func ofAbortion() -> IMEState { .init(type: .ofAbortion) } public static func ofAbortion() -> IMEState { .init(type: .ofAbortion) }
public static func ofCommitting(textToCommit: String) -> IMEState { public static func ofCommitting(textToCommit: String) -> IMEState {
var result = IMEState(type: .ofCommitting) var result = IMEState(type: .ofCommitting)
result.data.textToCommit = textToCommit result.textToCommit = textToCommit
ChineseConverter.ensureCurrencyNumerals(target: &result.data.textToCommit) ChineseConverter.ensureCurrencyNumerals(target: &result.data.textToCommit)
return result return result
} }
public static func ofAssociates(candidates: [(String, String)]) -> IMEState { public static func ofAssociates(candidates: [(String, String)]) -> IMEState {
var result = IMEState(type: .ofAssociates) var result = IMEState(type: .ofAssociates)
result.data.candidates = candidates result.candidates = candidates
return result return result
} }
@ -120,10 +83,10 @@ extension IMEState {
var result = IMEState(type: .ofNotEmpty) var result = IMEState(type: .ofNotEmpty)
// displayTextSegments // displayTextSegments
result.data.displayTextSegments = displayTextSegments.map { result.data.displayTextSegments = displayTextSegments.map {
if !ctlInputMethod.isVerticalTyping { return $0 } if !SessionCtl.isVerticalTyping { return $0 }
guard PrefMgr.shared.hardenVerticalPunctuations else { return $0 } guard PrefMgr.shared.hardenVerticalPunctuations else { return $0 }
var neta = $0 var neta = $0
ChineseConverter.hardenVerticalPunctuations(target: &neta, convert: ctlInputMethod.isVerticalTyping) ChineseConverter.hardenVerticalPunctuations(target: &neta, convert: SessionCtl.isVerticalTyping)
return neta return neta
} }
@ -133,7 +96,7 @@ extension IMEState {
} }
public static func ofInputting(displayTextSegments: [String], cursor: Int) -> IMEState { public static func ofInputting(displayTextSegments: [String], cursor: Int) -> IMEState {
var result = IMEState.ofNotEmpty(displayTextSegments: displayTextSegments, cursor: cursor) var result = Self.ofNotEmpty(displayTextSegments: displayTextSegments, cursor: cursor)
result.type = .ofInputting result.type = .ofInputting
return result return result
} }
@ -143,7 +106,7 @@ extension IMEState {
) )
-> IMEState -> IMEState
{ {
var result = IMEState.ofNotEmpty(displayTextSegments: displayTextSegments, cursor: cursor) var result = Self.ofNotEmpty(displayTextSegments: displayTextSegments, cursor: cursor)
result.type = .ofMarking result.type = .ofMarking
result.data.marker = marker result.data.marker = marker
result.data.markedReadings = markedReadings result.data.markedReadings = markedReadings
@ -154,7 +117,7 @@ extension IMEState {
public static func ofCandidates(candidates: [(String, String)], displayTextSegments: [String], cursor: Int) public static func ofCandidates(candidates: [(String, String)], displayTextSegments: [String], cursor: Int)
-> IMEState -> IMEState
{ {
var result = IMEState.ofNotEmpty(displayTextSegments: displayTextSegments, cursor: cursor) var result = Self.ofNotEmpty(displayTextSegments: displayTextSegments, cursor: cursor)
result.type = .ofCandidates result.type = .ofCandidates
result.data.candidates = candidates result.data.candidates = candidates
return result return result
@ -172,35 +135,44 @@ extension IMEState {
extension IMEState { extension IMEState {
public var isFilterable: Bool { data.isFilterable } public var isFilterable: Bool { data.isFilterable }
public var isMarkedLengthValid: Bool { data.isMarkedLengthValid } public var isMarkedLengthValid: Bool { data.isMarkedLengthValid }
public var candidates: [(String, String)] { data.candidates }
public var displayedText: String { data.displayedText } public var displayedText: String { data.displayedText }
public var cursor: Int { data.cursor } public var displayedTextConverted: String { data.displayedTextConverted }
public var displayTextSegments: [String] { data.displayTextSegments } public var displayTextSegments: [String] { data.displayTextSegments }
public var markedRange: Range<Int> { data.markedRange } public var markedRange: Range<Int> { data.markedRange }
public var convertedToInputting: IMEState { public var u16MarkedRange: Range<Int> { data.u16MarkedRange }
public var u16Cursor: Int { data.u16Cursor }
public var cursor: Int {
get { data.cursor }
set { data.cursor = newValue }
}
public var marker: Int {
get { data.marker }
set { data.marker = newValue }
}
public var convertedToInputting: IMEStateProtocol {
if type == .ofInputting { return self } if type == .ofInputting { return self }
var result = IMEState.ofInputting(displayTextSegments: data.displayTextSegments, cursor: data.cursor) var result = Self.ofInputting(displayTextSegments: data.displayTextSegments, cursor: data.cursor)
result.tooltip = data.tooltipBackupForInputting result.tooltip = data.tooltipBackupForInputting
result.isVerticalTyping = isVerticalTyping result.isVerticalTyping = isVerticalTyping
return result return result
} }
public var candidates: [(String, String)] {
get { data.candidates }
set { data.candidates = newValue }
}
public var textToCommit: String { public var textToCommit: String {
get { get { data.textToCommit }
data.textToCommit set { data.textToCommit = newValue }
}
set {
data.textToCommit = newValue
}
} }
public var tooltip: String { public var tooltip: String {
get { get { data.tooltip }
data.tooltip set { data.tooltip = newValue }
}
set {
data.tooltip = newValue
}
} }
public var attributedString: NSAttributedString { public var attributedString: NSAttributedString {
@ -231,11 +203,7 @@ extension IMEState {
} }
public var tooltipBackupForInputting: String { public var tooltipBackupForInputting: String {
get { get { data.tooltipBackupForInputting }
data.tooltipBackupForInputting set { data.tooltipBackupForInputting = newValue }
}
set {
data.tooltipBackupForInputting = newValue
}
} }
} }

View File

@ -6,9 +6,11 @@
// 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 Shared
import Tekkon import Tekkon
import TooltipUI
public struct StateData { public struct StateData: StateDataProtocol {
private static var minCandidateLength: Int { private static var minCandidateLength: Int {
PrefMgr.shared.allowBoostingSingleKanjiAsUserPhrase ? 1 : 2 PrefMgr.shared.allowBoostingSingleKanjiAsUserPhrase ? 1 : 2
} }
@ -17,8 +19,8 @@ public struct StateData {
Self.minCandidateLength...PrefMgr.shared.maxCandidateLength Self.minCandidateLength...PrefMgr.shared.maxCandidateLength
} }
var displayedText: String = "" public var displayedText: String = ""
var displayedTextConverted: String { public var displayedTextConverted: String {
/// ///
var result = ChineseConverter.kanjiConversionIfRequired(displayedText) var result = ChineseConverter.kanjiConversionIfRequired(displayedText)
if result.utf16.count != displayedText.utf16.count if result.utf16.count != displayedText.utf16.count
@ -31,19 +33,19 @@ public struct StateData {
// MARK: Cursor & Marker & Range for UTF8 // MARK: Cursor & Marker & Range for UTF8
var cursor: Int = 0 { public var cursor: Int = 0 {
didSet { didSet {
cursor = min(max(cursor, 0), displayedText.count) cursor = min(max(cursor, 0), displayedText.count)
} }
} }
var marker: Int = 0 { public var marker: Int = 0 {
didSet { didSet {
marker = min(max(marker, 0), displayedText.count) marker = min(max(marker, 0), displayedText.count)
} }
} }
var markedRange: Range<Int> { public var markedRange: Range<Int> {
min(cursor, marker)..<max(cursor, marker) min(cursor, marker)..<max(cursor, marker)
} }
@ -52,58 +54,58 @@ public struct StateData {
/// IMK UTF8 emoji /// IMK UTF8 emoji
/// Swift.utf16NSString.length() /// Swift.utf16NSString.length()
/// ///
var u16Cursor: Int { public var u16Cursor: Int {
displayedText.charComponents[0..<cursor].joined().utf16.count displayedText.charComponents[0..<cursor].joined().utf16.count
} }
var u16Marker: Int { public var u16Marker: Int {
displayedText.charComponents[0..<marker].joined().utf16.count displayedText.charComponents[0..<marker].joined().utf16.count
} }
var u16MarkedRange: Range<Int> { public var u16MarkedRange: Range<Int> {
min(u16Cursor, u16Marker)..<max(u16Cursor, u16Marker) min(u16Cursor, u16Marker)..<max(u16Cursor, u16Marker)
} }
// MARK: Other data for non-empty states. // MARK: Other data for non-empty states.
var isVerticalTyping = false public var isVerticalTyping = false
var markedTargetExists: Bool { public var markedTargetExists: Bool {
let pair = userPhraseKVPair let pair = userPhraseKVPair
return LMMgr.checkIfUserPhraseExist( return LMMgr.checkIfUserPhraseExist(
userPhrase: pair.1, mode: IMEApp.currentInputMode, key: pair.0 userPhrase: pair.1, mode: IMEApp.currentInputMode, key: pair.0
) )
} }
var displayTextSegments = [String]() { public var displayTextSegments = [String]() {
didSet { didSet {
displayedText = displayTextSegments.joined() displayedText = displayTextSegments.joined()
} }
} }
var reading: String = "" public var reading: String = ""
var markedReadings = [String]() public var markedReadings = [String]()
var candidates = [(String, String)]() public var candidates = [(String, String)]()
var textToCommit: String = "" public var textToCommit: String = ""
var tooltip: String = "" public var tooltip: String = ""
var tooltipBackupForInputting: String = "" public var tooltipBackupForInputting: String = ""
var attributedStringPlaceholder: NSAttributedString = .init( public var attributedStringPlaceholder: NSAttributedString = .init(
string: " ", string: " ",
attributes: [ attributes: [
.underlineStyle: NSUnderlineStyle.single.rawValue, .underlineStyle: NSUnderlineStyle.single.rawValue,
.markedClauseSegment: 0, .markedClauseSegment: 0,
] ]
) )
var isFilterable: Bool { public var isFilterable: Bool {
markedTargetExists ? isMarkedLengthValid : false markedTargetExists ? isMarkedLengthValid : false
} }
var isMarkedLengthValid: Bool { public var isMarkedLengthValid: Bool {
Self.allowedMarkLengthRange.contains(markedRange.count) Self.allowedMarkLengthRange.contains(markedRange.count)
} }
var tooltipColorState: ctlTooltip.ColorStates = .normal public var tooltipColorState: TooltipColorState = .normal
var attributedStringNormal: NSAttributedString { public var attributedStringNormal: NSAttributedString {
/// ///
/// JIS /// JIS
let attributedString = NSMutableAttributedString(string: displayedTextConverted) let attributedString = NSMutableAttributedString(string: displayedTextConverted)
@ -121,7 +123,7 @@ public struct StateData {
return attributedString return attributedString
} }
var attributedStringMarking: NSAttributedString { public var attributedStringMarking: NSAttributedString {
/// ///
/// JIS /// JIS
let attributedString = NSMutableAttributedString(string: displayedTextConverted) let attributedString = NSMutableAttributedString(string: displayedTextConverted)
@ -160,7 +162,7 @@ public struct StateData {
// MARK: - IMEState // MARK: - IMEState
extension StateData { extension StateData {
var chkIfUserPhraseExists: Bool { public var doesUserPhraseExist: Bool {
let text = displayedText.charComponents[markedRange].joined() let text = displayedText.charComponents[markedRange].joined()
let joined = markedReadings.joined(separator: "-") let joined = markedReadings.joined(separator: "-")
return LMMgr.checkIfUserPhraseExist( return LMMgr.checkIfUserPhraseExist(
@ -168,7 +170,7 @@ extension StateData {
) )
} }
var readingThreadForDisplay: String { public var readingThreadForDisplay: String {
var arrOutput = [String]() var arrOutput = [String]()
for neta in markedReadings { for neta in markedReadings {
var neta = neta var neta = neta
@ -192,27 +194,27 @@ extension StateData {
return arrOutput.joined(separator: "\u{A0}") return arrOutput.joined(separator: "\u{A0}")
} }
var userPhraseKVPair: (String, String) { public var userPhraseKVPair: (String, String) {
let key = markedReadings.joined(separator: "-") let key = markedReadings.joined(separator: "-")
let value = displayedText.charComponents[markedRange].joined() let value = displayedText.charComponents[markedRange].joined()
return (key, value) return (key, value)
} }
var userPhraseDumped: String { public var userPhraseDumped: String {
let pair = userPhraseKVPair let pair = userPhraseKVPair
let nerfedScore = ctlInputMethod.areWeNerfing && markedTargetExists ? " -114.514" : "" let nerfedScore = SessionCtl.areWeNerfing && markedTargetExists ? " -114.514" : ""
return "\(pair.1) \(pair.0)\(nerfedScore)" return "\(pair.1) \(pair.0)\(nerfedScore)"
} }
var userPhraseDumpedConverted: String { public var userPhraseDumpedConverted: String {
let pair = userPhraseKVPair let pair = userPhraseKVPair
let text = ChineseConverter.crossConvert(pair.1) ?? "" let text = ChineseConverter.crossConvert(pair.1)
let nerfedScore = ctlInputMethod.areWeNerfing && markedTargetExists ? " -114.514" : "" let nerfedScore = SessionCtl.areWeNerfing && markedTargetExists ? " -114.514" : ""
let convertedMark = "#𝙃𝙪𝙢𝙖𝙣𝘾𝙝𝙚𝙘𝙠𝙍𝙚𝙦𝙪𝙞𝙧𝙚𝙙" let convertedMark = "#𝙃𝙪𝙢𝙖𝙣𝘾𝙝𝙚𝙘𝙠𝙍𝙚𝙦𝙪𝙞𝙧𝙚𝙙"
return "\(text) \(pair.0)\(nerfedScore)\t\(convertedMark)" return "\(text) \(pair.0)\(nerfedScore)\t\(convertedMark)"
} }
mutating func updateTooltipForMarking() { public mutating func updateTooltipForMarking() {
var tooltipForMarking: String { var tooltipForMarking: String {
let pair = userPhraseKVPair let pair = userPhraseKVPair
if PrefMgr.shared.phraseReplacementEnabled { if PrefMgr.shared.phraseReplacementEnabled {

View File

@ -20,7 +20,7 @@ import Tekkon
/// KeyHandler /// KeyHandler
public protocol KeyHandlerDelegate { public protocol KeyHandlerDelegate {
var clientBundleIdentifier: String { get } var clientBundleIdentifier: String { get }
func ctlCandidate() -> ctlCandidateProtocol func candidateController() -> CtlCandidateProtocol
func candidateSelectionCalledByKeyHandler(at index: Int) func candidateSelectionCalledByKeyHandler(at index: Int)
func performUserPhraseOperation(with state: IMEStateProtocol, addToFilter: Bool) func performUserPhraseOperation(with state: IMEStateProtocol, addToFilter: Bool)
-> Bool -> Bool
@ -30,7 +30,7 @@ public protocol KeyHandlerDelegate {
/// KeyHandler 調 /// KeyHandler 調
public class KeyHandler { public class KeyHandler {
/// (ctlInputMethod)便 /// (SessionCtl)便
public var delegate: KeyHandlerDelegate? public var delegate: KeyHandlerDelegate?
public var prefs: PrefMgrProtocol public var prefs: PrefMgrProtocol

View File

@ -26,7 +26,7 @@ extension KeyHandler {
stateCallback: @escaping (IMEStateProtocol) -> Void, stateCallback: @escaping (IMEStateProtocol) -> Void,
errorCallback: @escaping (String) -> Void errorCallback: @escaping (String) -> Void
) -> Bool { ) -> Bool {
guard var ctlCandidate = delegate?.ctlCandidate() else { guard var ctlCandidate = delegate?.candidateController() else {
errorCallback("06661F6E") errorCallback("06661F6E")
return true return true
} }

View File

@ -145,7 +145,7 @@ extension KeyHandler {
stateCallback(candidateState) stateCallback(candidateState)
} }
} }
// ctlInputMethod IMK // SessionCtl IMK
return true return true
} }

View File

@ -400,7 +400,7 @@ extension KeyHandler {
// MARK: - (Still Nothing) // MARK: - (Still Nothing)
/// ctlInputMethod /// SessionCtl
/// ///
/// F1-F12 /// F1-F12
/// 便 /// 便

View File

@ -114,7 +114,6 @@ extension KeyHandler {
func buildAssociatePhraseState( func buildAssociatePhraseState(
withPair pair: Megrez.Compositor.KeyValuePaired withPair pair: Megrez.Compositor.KeyValuePaired
) -> IMEState { ) -> IMEState {
//  Xcode
IMEState.ofAssociates( IMEState.ofAssociates(
candidates: buildAssociatePhraseArray(withPair: pair)) candidates: buildAssociatePhraseArray(withPair: pair))
} }
@ -127,7 +126,7 @@ extension KeyHandler {
/// - input: /// - input:
/// - stateCallback: /// - stateCallback:
/// - errorCallback: /// - errorCallback:
/// - Returns: ctlInputMethod IMK /// - Returns: SessionCtl IMK
func handleMarkingState( func handleMarkingState(
_ state: IMEStateProtocol, _ state: IMEStateProtocol,
input: InputSignalProtocol, input: InputSignalProtocol,
@ -236,7 +235,7 @@ extension KeyHandler {
/// - isTypingVertical: /// - isTypingVertical:
/// - stateCallback: /// - stateCallback:
/// - errorCallback: /// - errorCallback:
/// - Returns: ctlInputMethod IMK /// - Returns: SessionCtl IMK
func handlePunctuation( func handlePunctuation(
_ customPunctuation: String, _ customPunctuation: String,
state: IMEStateProtocol, state: IMEStateProtocol,
@ -286,7 +285,7 @@ extension KeyHandler {
/// - Parameters: /// - Parameters:
/// - state: /// - state:
/// - stateCallback: /// - stateCallback:
/// - Returns: ctlInputMethod IMK /// - Returns: SessionCtl IMK
func handleEnter( func handleEnter(
state: IMEStateProtocol, state: IMEStateProtocol,
stateCallback: @escaping (IMEStateProtocol) -> Void stateCallback: @escaping (IMEStateProtocol) -> Void
@ -304,7 +303,7 @@ extension KeyHandler {
/// - Parameters: /// - Parameters:
/// - state: /// - state:
/// - stateCallback: /// - stateCallback:
/// - Returns: ctlInputMethod IMK /// - Returns: SessionCtl IMK
func handleCtrlCommandEnter( func handleCtrlCommandEnter(
state: IMEStateProtocol, state: IMEStateProtocol,
stateCallback: @escaping (IMEStateProtocol) -> Void stateCallback: @escaping (IMEStateProtocol) -> Void
@ -332,7 +331,7 @@ extension KeyHandler {
/// - Parameters: /// - Parameters:
/// - state: /// - state:
/// - stateCallback: /// - stateCallback:
/// - Returns: ctlInputMethod IMK /// - Returns: SessionCtl IMK
func handleCtrlOptionCommandEnter( func handleCtrlOptionCommandEnter(
state: IMEStateProtocol, state: IMEStateProtocol,
stateCallback: @escaping (IMEStateProtocol) -> Void stateCallback: @escaping (IMEStateProtocol) -> Void
@ -370,7 +369,7 @@ extension KeyHandler {
/// - input: /// - input:
/// - stateCallback: /// - stateCallback:
/// - errorCallback: /// - errorCallback:
/// - Returns: ctlInputMethod IMK /// - Returns: SessionCtl IMK
func handleBackSpace( func handleBackSpace(
state: IMEStateProtocol, state: IMEStateProtocol,
input: InputSignalProtocol, input: InputSignalProtocol,
@ -432,7 +431,7 @@ extension KeyHandler {
/// - input: /// - input:
/// - stateCallback: /// - stateCallback:
/// - errorCallback: /// - errorCallback:
/// - Returns: ctlInputMethod IMK /// - Returns: SessionCtl IMK
func handleDelete( func handleDelete(
state: IMEStateProtocol, state: IMEStateProtocol,
input: InputSignalProtocol, input: InputSignalProtocol,
@ -476,7 +475,7 @@ extension KeyHandler {
/// - state: /// - state:
/// - stateCallback: /// - stateCallback:
/// - errorCallback: /// - errorCallback:
/// - Returns: ctlInputMethod IMK /// - Returns: SessionCtl IMK
func handleClockKey( func handleClockKey(
state: IMEStateProtocol, state: IMEStateProtocol,
stateCallback: @escaping (IMEStateProtocol) -> Void, stateCallback: @escaping (IMEStateProtocol) -> Void,
@ -497,7 +496,7 @@ extension KeyHandler {
/// - state: /// - state:
/// - stateCallback: /// - stateCallback:
/// - errorCallback: /// - errorCallback:
/// - Returns: ctlInputMethod IMK /// - Returns: SessionCtl IMK
func handleHome( func handleHome(
state: IMEStateProtocol, state: IMEStateProtocol,
stateCallback: @escaping (IMEStateProtocol) -> Void, stateCallback: @escaping (IMEStateProtocol) -> Void,
@ -529,7 +528,7 @@ extension KeyHandler {
/// - state: /// - state:
/// - stateCallback: /// - stateCallback:
/// - errorCallback: /// - errorCallback:
/// - Returns: ctlInputMethod IMK /// - Returns: SessionCtl IMK
func handleEnd( func handleEnd(
state: IMEStateProtocol, state: IMEStateProtocol,
stateCallback: @escaping (IMEStateProtocol) -> Void, stateCallback: @escaping (IMEStateProtocol) -> Void,
@ -560,7 +559,7 @@ extension KeyHandler {
/// - Parameters: /// - Parameters:
/// - state: /// - state:
/// - stateCallback: /// - stateCallback:
/// - Returns: ctlInputMethod IMK /// - Returns: SessionCtl IMK
func handleEsc( func handleEsc(
state: IMEStateProtocol, state: IMEStateProtocol,
stateCallback: @escaping (IMEStateProtocol) -> Void stateCallback: @escaping (IMEStateProtocol) -> Void
@ -592,7 +591,7 @@ extension KeyHandler {
/// - input: /// - input:
/// - stateCallback: /// - stateCallback:
/// - errorCallback: /// - errorCallback:
/// - Returns: ctlInputMethod IMK /// - Returns: SessionCtl IMK
func handleForward( func handleForward(
state: IMEStateProtocol, state: IMEStateProtocol,
input: InputSignalProtocol, input: InputSignalProtocol,
@ -661,7 +660,7 @@ extension KeyHandler {
/// - input: /// - input:
/// - stateCallback: /// - stateCallback:
/// - errorCallback: /// - errorCallback:
/// - Returns: ctlInputMethod IMK /// - Returns: SessionCtl IMK
func handleBackward( func handleBackward(
state: IMEStateProtocol, state: IMEStateProtocol,
input: InputSignalProtocol, input: InputSignalProtocol,
@ -730,7 +729,7 @@ extension KeyHandler {
/// - reverseModifier: /// - reverseModifier:
/// - stateCallback: /// - stateCallback:
/// - errorCallback: /// - errorCallback:
/// - Returns: ctlInputMethod IMK /// - Returns: SessionCtl IMK
func handleInlineCandidateRotation( func handleInlineCandidateRotation(
state: IMEStateProtocol, state: IMEStateProtocol,
reverseModifier: Bool, reverseModifier: Bool,

View File

@ -8,7 +8,7 @@
import BookmarkManager import BookmarkManager
import LangModelAssembly import LangModelAssembly
import Megrez import NotifierUI
import Shared import Shared
/// 使 /// 使
@ -98,7 +98,7 @@ public enum LMMgr {
} }
if !Self.lmCHT.isLanguageModelLoaded { if !Self.lmCHT.isLanguageModelLoaded {
showFinishNotification = true showFinishNotification = true
NotifierController.notify( Notifier.notify(
message: NSLocalizedString("Loading CHT Core Dict...", comment: "") message: NSLocalizedString("Loading CHT Core Dict...", comment: "")
) )
group.enter() group.enter()
@ -109,7 +109,7 @@ public enum LMMgr {
} }
if !Self.lmCHS.isLanguageModelLoaded { if !Self.lmCHS.isLanguageModelLoaded {
showFinishNotification = true showFinishNotification = true
NotifierController.notify( Notifier.notify(
message: NSLocalizedString("Loading CHS Core Dict...", comment: "") message: NSLocalizedString("Loading CHS Core Dict...", comment: "")
) )
group.enter() group.enter()
@ -120,7 +120,7 @@ public enum LMMgr {
} }
group.notify(queue: DispatchQueue.main) { group.notify(queue: DispatchQueue.main) {
if showFinishNotification { if showFinishNotification {
NotifierController.notify( Notifier.notify(
message: NSLocalizedString("Core Dict loading complete.", comment: "") message: NSLocalizedString("Core Dict loading complete.", comment: "")
) )
} }
@ -162,7 +162,7 @@ public enum LMMgr {
case .imeModeCHS: case .imeModeCHS:
if !Self.lmCHS.isLanguageModelLoaded { if !Self.lmCHS.isLanguageModelLoaded {
showFinishNotification = true showFinishNotification = true
NotifierController.notify( Notifier.notify(
message: NSLocalizedString("Loading CHS Core Dict...", comment: "") message: NSLocalizedString("Loading CHS Core Dict...", comment: "")
) )
group.enter() group.enter()
@ -174,7 +174,7 @@ public enum LMMgr {
case .imeModeCHT: case .imeModeCHT:
if !Self.lmCHT.isLanguageModelLoaded { if !Self.lmCHT.isLanguageModelLoaded {
showFinishNotification = true showFinishNotification = true
NotifierController.notify( Notifier.notify(
message: NSLocalizedString("Loading CHT Core Dict...", comment: "") message: NSLocalizedString("Loading CHT Core Dict...", comment: "")
) )
group.enter() group.enter()
@ -187,7 +187,7 @@ public enum LMMgr {
} }
group.notify(queue: DispatchQueue.main) { group.notify(queue: DispatchQueue.main) {
if showFinishNotification { if showFinishNotification {
NotifierController.notify( Notifier.notify(
message: NSLocalizedString("Core Dict loading complete.", comment: "") message: NSLocalizedString("Core Dict loading complete.", comment: "")
) )
} }
@ -244,16 +244,12 @@ public enum LMMgr {
mode: Shared.InputMode, mode: Shared.InputMode,
key unigramKey: String key unigramKey: String
) -> Bool { ) -> Bool {
let unigrams: [Megrez.Unigram] = switch mode {
(mode == .imeModeCHT) case .imeModeCHS: return lmCHS.hasKeyValuePairFor(key: unigramKey, value: userPhrase)
? Self.lmCHT.unigramsFor(key: unigramKey) : Self.lmCHS.unigramsFor(key: unigramKey) case .imeModeCHT: return lmCHT.hasKeyValuePairFor(key: unigramKey, value: userPhrase)
for unigram in unigrams { case .imeModeNULL: return false
if unigram.value == userPhrase {
return true
} }
} }
return false
}
public static func setPhraseReplacementEnabled(_ state: Bool) { public static func setPhraseReplacementEnabled(_ state: Bool) {
Self.lmCHT.isPhraseReplacementEnabled = state Self.lmCHT.isPhraseReplacementEnabled = state

View File

@ -8,7 +8,7 @@
import Shared import Shared
// MARK: Auto parameter fix procedures, executed everytime on ctlInputMethod.activateServer(). // MARK: Auto parameter fix procedures, executed everytime on SessionCtl.activateServer().
extension PrefMgr { extension PrefMgr {
public func fixOddPreferences() { public func fixOddPreferences() {

View File

@ -9,9 +9,11 @@
// requirements defined in MIT License. // requirements defined in MIT License.
import IMKUtils import IMKUtils
import PopupCompositionBuffer
import Shared import Shared
import ShiftKeyUpChecker import ShiftKeyUpChecker
import Tekkon import TooltipUI
import Voltaire
/// ///
/// ///
@ -21,24 +23,24 @@ import Tekkon
/// 調 /// 調
/// - Remark: IMKServer /// - Remark: IMKServer
/// IMKInputController /// IMKInputController
@objc(ctlInputMethod) // ObjC IMK ObjC @objc(SessionCtl) // ObjC IMK ObjC
class ctlInputMethod: IMKInputController { class SessionCtl: IMKInputController {
/// ///
static var areWeNerfing = false static var areWeNerfing = false
/// ///
static var ctlCandidateCurrent: ctlCandidateProtocol = static var ctlCandidateCurrent: CtlCandidateProtocol =
PrefMgr.shared.useIMKCandidateWindow ? ctlCandidateIMK.init(.horizontal) : ctlCandidateUniversal.init(.horizontal) PrefMgr.shared.useIMKCandidateWindow ? CtlCandidateIMK(.horizontal) : CtlCandidateUniversal(.horizontal)
/// ///
static var tooltipInstance = ctlTooltip() static var tooltipInstance = TooltipUI()
/// ///
static var popupCompositionBuffer = ctlPopupCompositionBuffer() static var popupCompositionBuffer = PopupCompositionBuffer()
// MARK: - // MARK: -
/// ctlInputMethod /// SessionCtl
var isASCIIMode = false { var isASCIIMode = false {
didSet { didSet {
resetKeyHandler() resetKeyHandler()
@ -75,8 +77,46 @@ class ctlInputMethod: IMKInputController {
return result return result
} }
/// InputMode
/// IME UserPrefs
var inputMode: Shared.InputMode = IMEApp.currentInputMode {
willSet {
/// Prefs IME
IMEApp.currentInputMode = newValue
PrefMgr.shared.mostRecentInputMode = IMEApp.currentInputMode.rawValue
}
didSet {
///
keyHandler.currentLM = LMMgr.currentLM() //
keyHandler.currentUOM = LMMgr.currentUOM()
///
keyHandler.ensureKeyboardParser()
///
syncBaseLMPrefs()
}
}
///
///
/// inputClient IMKServer IMKTextInput
/// - Remark: IMKInputController client()
/// - Parameters:
/// - server: IMKServer
/// - delegate:
/// - inputClient:
override init!(server: IMKServer!, delegate: Any!, client inputClient: Any!) {
super.init(server: server, delegate: delegate, client: inputClient)
keyHandler.delegate = self
syncBaseLMPrefs()
//
resetKeyHandler()
activateServer(inputClient)
}
}
// MARK: - // MARK: -
extension SessionCtl {
/// ///
func setKeyLayout() { func setKeyLayout() {
guard let client = client() else { return } guard let client = client() else { return }
@ -101,28 +141,11 @@ class ctlInputMethod: IMKInputController {
} }
handle(state: isSecureMode ? IMEState.ofAbortion() : IMEState.ofEmpty()) handle(state: isSecureMode ? IMEState.ofAbortion() : IMEState.ofEmpty())
} }
// MARK: - IMKInputController
///
///
/// inputClient IMKServer IMKTextInput
/// - Remark: IMKInputController client()
/// - Parameters:
/// - server: IMKServer
/// - delegate:
/// - inputClient:
override init!(server: IMKServer!, delegate: Any!, client inputClient: Any!) {
super.init(server: server, delegate: delegate, client: inputClient)
keyHandler.delegate = self
syncBaseLMPrefs()
//
resetKeyHandler()
activateServer(inputClient)
} }
// MARK: - IMKStateSetting // MARK: - IMKStateSetting
extension SessionCtl {
/// ///
/// - Parameter sender: 使 /// - Parameter sender: 使
override func activateServer(_ sender: Any!) { override func activateServer(_ sender: Any!) {
@ -192,25 +215,6 @@ class ctlInputMethod: IMKInputController {
} }
} }
/// InputMode
/// IME UserPrefs
var inputMode: Shared.InputMode = IMEApp.currentInputMode {
willSet {
/// Prefs IME
IMEApp.currentInputMode = newValue
PrefMgr.shared.mostRecentInputMode = IMEApp.currentInputMode.rawValue
}
didSet {
///
keyHandler.currentLM = LMMgr.currentLM() //
keyHandler.currentUOM = LMMgr.currentUOM()
///
keyHandler.ensureKeyboardParser()
///
syncBaseLMPrefs()
}
}
/// ///
func syncBaseLMPrefs() { func syncBaseLMPrefs() {
LMMgr.currentLM().isPhraseReplacementEnabled = PrefMgr.shared.phraseReplacementEnabled LMMgr.currentLM().isPhraseReplacementEnabled = PrefMgr.shared.phraseReplacementEnabled
@ -219,9 +223,13 @@ class ctlInputMethod: IMKInputController {
LMMgr.currentLM().isSCPCEnabled = PrefMgr.shared.useSCPCTypingMode LMMgr.currentLM().isSCPCEnabled = PrefMgr.shared.useSCPCTypingMode
LMMgr.currentLM().deltaOfCalendarYears = PrefMgr.shared.deltaOfCalendarYears LMMgr.currentLM().deltaOfCalendarYears = PrefMgr.shared.deltaOfCalendarYears
} }
}
// MARK: - IMKServerInput // MARK: - IMKServerInput
// handle(_ event:) SessionCtl_HandleEvent.swift
extension SessionCtl {
/// ///
/// ///
/// ///
@ -237,103 +245,6 @@ class ctlInputMethod: IMKInputController {
return Int(events.rawValue) return Int(events.rawValue)
} }
/// NSEvent
/// - Parameters:
/// - event: nil
/// - sender: 使
/// - Returns: `true` IMK`false`
@objc(handleEvent:client:) override func handle(_ event: NSEvent!, client sender: Any!) -> Bool {
_ = sender //
// MARK:
//
state.isASCIIMode = isASCIIMode
state.isVerticalTyping = isVerticalTyping
// NSEvent nilApple InputMethodKit
// client()
guard let event = event, sender is IMKTextInput else {
resetKeyHandler()
return false
}
// Shift macOS 10.15 macOS
let shouldUseShiftToggleHandle: Bool = {
switch PrefMgr.shared.shiftKeyAccommodationBehavior {
case 0: return false
case 1: return Shared.arrClientShiftHandlingExceptionList.contains(clientBundleIdentifier)
case 2: return true
default: return false
}
}()
/// event event var Shift
if #available(macOS 10.15, *) {
if Self.theShiftKeyDetector.check(event), !PrefMgr.shared.disableShiftTogglingAlphanumericalMode {
if !shouldUseShiftToggleHandle || (!rencentKeyHandledByKeyHandlerEtc && shouldUseShiftToggleHandle) {
NotifierController.notify(
message: isASCIIMode.toggled()
? NSLocalizedString("Alphanumerical Input Mode", comment: "")
: NSLocalizedString("Chinese Input Mode", comment: "")
)
}
if shouldUseShiftToggleHandle {
rencentKeyHandledByKeyHandlerEtc = false
}
return false
}
}
// MARK:
// Shift
if isASCIIMode { return false }
/// flags使 KeyHandler
/// flags
/// event.type == .flagsChanged return false
/// NSInternalInconsistencyException
if event.type == .flagsChanged { return false }
///
guard client() != nil else { return false }
var eventToDeal = event
//
if event.isUp || event.isDown || event.isLeft || event.isRight {
eventToDeal = event.reinitiate(charactersIgnoringModifiers: isVerticalTyping ? "Vertical" : "Horizontal") ?? event
}
// 使 NSEvent Emacs NSEvent NSEvent
if eventToDeal.isEmacsKey {
let verticalProcessing =
(state.isCandidateContainer)
? state.isVerticalCandidateWindow : state.isVerticalTyping
eventToDeal = eventToDeal.convertFromEmacKeyEvent(isVerticalContext: verticalProcessing)
}
//
Self.areWeNerfing = eventToDeal.modifierFlags.contains([.shift, .command])
// IMK IMK
if let result = imkCandidatesEventHandler(event: eventToDeal) {
if shouldUseShiftToggleHandle {
rencentKeyHandledByKeyHandlerEtc = result
}
return result
}
/// NSEvent commonEventHandler
/// IMK 便
let result = commonEventHandler(eventToDeal)
if shouldUseShiftToggleHandle {
rencentKeyHandledByKeyHandlerEtc = result
}
return result
}
/// App Ctrl+Enter / Shift+Enter /// App Ctrl+Enter / Shift+Enter
/// handle(event:) Event /// handle(event:) Event
/// commitComposition /// commitComposition
@ -344,13 +255,13 @@ class ctlInputMethod: IMKInputController {
// super.commitComposition(sender) // // super.commitComposition(sender) //
} }
/// /// InputMethodKit
/// - Parameter sender: 使 /// - Parameter sender: 使
/// - Returns: nil /// - Returns: nil
override func composedString(_ sender: Any!) -> Any! { override func composedString(_ sender: Any!) -> Any! {
_ = sender // _ = sender //
guard state.hasComposition else { return "" } guard state.hasComposition else { return "" }
return state.displayedText return state.displayedTextConverted
} }
/// ///
@ -360,121 +271,4 @@ class ctlInputMethod: IMKInputController {
resetKeyHandler() resetKeyHandler()
super.inputControllerWillClose() super.inputControllerWillClose()
} }
// MARK: - IMKCandidates
/// IMK
/// - Parameter sender: 使
/// - Returns: IMK
override func candidates(_ sender: Any!) -> [Any]! {
_ = sender //
var arrResult = [String]()
// 便 IMEState
func handleIMKCandidatesPrepared(_ candidates: [(String, String)], prefix: String = "") {
for theCandidate in candidates {
let theConverted = ChineseConverter.kanjiConversionIfRequired(theCandidate.1)
var result = (theCandidate.1 == theConverted) ? theCandidate.1 : "\(theConverted)\u{1A}(\(theCandidate.1))"
if arrResult.contains(result) {
let reading: String =
PrefMgr.shared.showHanyuPinyinInCompositionBuffer
? Tekkon.cnvPhonaToHanyuPinyin(target: Tekkon.restoreToneOneInZhuyinKey(target: theCandidate.0))
: theCandidate.0
result = "\(result)\u{17}(\(reading))"
}
arrResult.append(prefix + result)
}
}
if state.type == .ofAssociates {
handleIMKCandidatesPrepared(state.candidates, prefix: "")
} else if state.type == .ofSymbolTable {
// / JIS 使
arrResult = state.candidates.map(\.1)
} else if state.type == .ofCandidates {
guard !state.candidates.isEmpty else { return .init() }
if state.candidates[0].0.contains("_punctuation") {
arrResult = state.candidates.map(\.1) //
} else {
handleIMKCandidatesPrepared(state.candidates)
}
}
return arrResult
}
/// IMK
/// - Parameter _:
override open func candidateSelectionChanged(_: NSAttributedString!) {
//
// IMKServer.commitCompositionWithReply() commitComposition()
// keyHandler
//
//
// ctlCandidateIMK identifier
// NSNotFound NSLog identifier
// console ips
// candidateSelected() identifier NSNotFound
// IMK 西
}
/// IMK
/// - Parameter candidateString:
override open func candidateSelected(_ candidateString: NSAttributedString!) {
let candidateString: String = candidateString?.string ?? ""
if state.type == .ofAssociates {
if !PrefMgr.shared.alsoConfirmAssociatedCandidatesByEnter {
handle(state: IMEState.ofAbortion())
return
}
}
var indexDeducted = 0
// 便 IMEState
func handleIMKCandidatesSelected(_ candidates: [(String, String)], prefix: String = "") {
for (i, neta) in candidates.enumerated() {
let theConverted = ChineseConverter.kanjiConversionIfRequired(neta.1)
let netaShown = (neta.1 == theConverted) ? neta.1 : "\(theConverted)\u{1A}(\(neta.1))"
let reading: String =
PrefMgr.shared.showHanyuPinyinInCompositionBuffer
? Tekkon.cnvPhonaToHanyuPinyin(target: Tekkon.restoreToneOneInZhuyinKey(target: neta.0)) : neta.0
let netaShownWithPronunciation = "\(netaShown)\u{17}(\(reading))"
if candidateString == prefix + netaShownWithPronunciation {
indexDeducted = i
break
}
if candidateString == prefix + netaShown {
indexDeducted = i
break
}
}
}
// / JIS 使
func handleSymbolCandidatesSelected(_ candidates: [(String, String)]) {
for (i, neta) in candidates.enumerated() {
if candidateString == neta.1 {
indexDeducted = i
break
}
}
}
if state.type == .ofAssociates {
handleIMKCandidatesSelected(state.candidates, prefix: "")
} else if state.type == .ofSymbolTable {
handleSymbolCandidatesSelected(state.candidates)
} else if state.type == .ofCandidates {
guard !state.candidates.isEmpty else { return }
if state.candidates[0].0.contains("_punctuation") {
handleSymbolCandidatesSelected(state.candidates) //
} else {
handleIMKCandidatesSelected(state.candidates)
}
}
candidateSelected(at: indexDeducted)
}
} }

View File

@ -12,31 +12,29 @@ import Shared
// MARK: - KeyHandler Delegate // MARK: - KeyHandler Delegate
extension ctlInputMethod: KeyHandlerDelegate { extension SessionCtl: KeyHandlerDelegate {
var clientBundleIdentifier: String { var clientBundleIdentifier: String {
guard let client = client() else { return "" } guard let client = client() else { return "" }
return client.bundleIdentifier() ?? "" return client.bundleIdentifier() ?? ""
} }
func ctlCandidate() -> ctlCandidateProtocol { ctlInputMethod.ctlCandidateCurrent } func candidateController() -> CtlCandidateProtocol { Self.ctlCandidateCurrent }
func candidateSelectionCalledByKeyHandler(at index: Int) { func candidateSelectionCalledByKeyHandler(at index: Int) {
candidateSelected(at: index) candidatePairSelected(at: index)
} }
func performUserPhraseOperation(with state: IMEStateProtocol, addToFilter: Bool) func performUserPhraseOperation(with state: IMEStateProtocol, addToFilter: Bool)
-> Bool -> Bool
{ {
guard state.type == .ofMarking else { return false } guard state.type == .ofMarking else { return false }
let refInputModeReversed: Shared.InputMode =
(inputMode == .imeModeCHT) ? .imeModeCHS : .imeModeCHT
if !LMMgr.writeUserPhrase( if !LMMgr.writeUserPhrase(
state.data.userPhraseDumped, inputMode: inputMode, state.data.userPhraseDumped, inputMode: inputMode,
areWeDuplicating: state.data.chkIfUserPhraseExists, areWeDuplicating: state.data.doesUserPhraseExist,
areWeDeleting: addToFilter areWeDeleting: addToFilter
) )
|| !LMMgr.writeUserPhrase( || !LMMgr.writeUserPhrase(
state.data.userPhraseDumpedConverted, inputMode: refInputModeReversed, state.data.userPhraseDumpedConverted, inputMode: inputMode.reversed,
areWeDuplicating: false, areWeDuplicating: false,
areWeDeleting: addToFilter areWeDeleting: addToFilter
) )
@ -49,48 +47,27 @@ extension ctlInputMethod: KeyHandlerDelegate {
// MARK: - Candidate Controller Delegate // MARK: - Candidate Controller Delegate
extension ctlInputMethod: ctlCandidateDelegate { extension SessionCtl: CtlCandidateDelegate {
var isAssociatedPhrasesState: Bool { state.type == .ofAssociates } func buzz() {
IMEApp.buzz()
/// handle() IMK
/// handle()
/// IMK commonEventHandler()
/// - Parameter event: IMK
/// - Returns: `true` IMK`false`
@discardableResult func sharedEventHandler(_ event: NSEvent) -> Bool {
commonEventHandler(event)
} }
func candidateCountForController(_ controller: ctlCandidateProtocol) -> Int { func kanjiConversionIfRequired(_ target: String) -> String {
_ = controller // ChineseConverter.kanjiConversionIfRequired(target)
if state.isCandidateContainer {
return state.candidates.count
}
return 0
} }
/// func candidatePairs() -> [(String, String)] {
/// - Parameter controller: state.isCandidateContainer ? state.candidates : []
/// - Returns:
func candidatesForController(_ controller: ctlCandidateProtocol) -> [(String, String)] {
_ = controller //
if state.isCandidateContainer {
return state.candidates
}
return .init()
} }
func ctlCandidate(_ controller: ctlCandidateProtocol, candidateAtIndex index: Int) func candidatePairAt(_ index: Int) -> (String, String) {
-> (String, String) if state.isCandidateContainer, state.candidates.count > index {
{
_ = controller //
if state.isCandidateContainer {
return state.candidates[index] return state.candidates[index]
} }
return ("", "") return ("", "")
} }
func candidateSelected(at index: Int) { func candidatePairSelected(at index: Int) {
if state.type == .ofSymbolTable, (0..<state.node.members.count).contains(index) { if state.type == .ofSymbolTable, (0..<state.node.members.count).contains(index) {
let node = state.node.members[index] let node = state.node.members[index]
if !node.members.isEmpty { if !node.members.isEmpty {

View File

@ -10,17 +10,18 @@
import NSAttributedTextView import NSAttributedTextView
import Shared import Shared
import Voltaire
// MARK: - Tooltip Display and Candidate Display Methods // MARK: - Tooltip Display and Candidate Display Methods
extension ctlInputMethod { extension SessionCtl {
// App 使 // App 使
// App App // App App
// 使 20 // 使 20
var attributedStringSecured: (NSAttributedString, NSRange) { var attributedStringSecured: (NSAttributedString, NSRange) {
PrefMgr.shared.clientsIMKTextInputIncapable.contains(clientBundleIdentifier) PrefMgr.shared.clientsIMKTextInputIncapable.contains(clientBundleIdentifier)
? (state.data.attributedStringPlaceholder, NSRange(location: 0, length: 0)) ? (state.data.attributedStringPlaceholder, NSRange(location: 0, length: 0))
: (state.attributedString, NSRange(state.data.u16MarkedRange)) : (state.attributedString, NSRange(state.u16MarkedRange))
} }
func lineHeightRect(zeroCursor: Bool = false) -> NSRect { func lineHeightRect(zeroCursor: Bool = false) -> NSRect {
@ -28,14 +29,10 @@ extension ctlInputMethod {
guard let client = client() else { guard let client = client() else {
return lineHeightRect return lineHeightRect
} }
var u16Cursor: Int = { var u16Cursor: Int = state.u16MarkedRange.lowerBound
// iMessage cursor == 0 u16Cursor = max(min(state.displayedTextConverted.utf16.count, u16Cursor), 0)
if clientBundleIdentifier == "com.apple.MobileSMS" { return state.data.u16Cursor }
if state.data.marker >= state.data.cursor { return state.data.u16Cursor }
return state.data.u16Marker //
}()
u16Cursor = max(min(state.data.displayedTextConverted.utf16.count, u16Cursor), 0)
if zeroCursor { u16Cursor = 0 } if zeroCursor { u16Cursor = 0 }
// iMessage lineHeightRect
while lineHeightRect.origin.x == 0, lineHeightRect.origin.y == 0, u16Cursor >= 0 { while lineHeightRect.origin.x == 0, lineHeightRect.origin.y == 0, u16Cursor >= 0 {
client.attributes( client.attributes(
forCharacterIndex: u16Cursor, lineHeightRectangle: &lineHeightRect forCharacterIndex: u16Cursor, lineHeightRectangle: &lineHeightRect
@ -49,7 +46,7 @@ extension ctlInputMethod {
guard client() != nil else { return } guard client() != nil else { return }
let lineHeightRect = lineHeightRect() let lineHeightRect = lineHeightRect()
var finalOrigin: NSPoint = lineHeightRect.origin var finalOrigin: NSPoint = lineHeightRect.origin
let delta: CGFloat = lineHeightRect.size.height + 4.0 // bottomOutOfScreenAdjustmentHeight let delta: Double = lineHeightRect.size.height + 4.0 // bottomOutOfScreenAdjustmentHeight
if isVerticalTyping { if isVerticalTyping {
finalOrigin = NSPoint( finalOrigin = NSPoint(
x: lineHeightRect.origin.x + lineHeightRect.size.width + 5, y: lineHeightRect.origin.y x: lineHeightRect.origin.x + lineHeightRect.size.width + 5, y: lineHeightRect.origin.y
@ -61,14 +58,14 @@ extension ctlInputMethod {
}() }()
// NSAttributedTextView // NSAttributedTextView
do { do {
ctlInputMethod.tooltipInstance.hide() Self.tooltipInstance.hide()
ctlInputMethod.tooltipInstance = .init() Self.tooltipInstance = .init()
if state.type == .ofMarking { if state.type == .ofMarking {
ctlInputMethod.tooltipInstance.setColor(state: state.data.tooltipColorState) Self.tooltipInstance.setColor(state: state.data.tooltipColorState)
} }
} }
// //
ctlInputMethod.tooltipInstance.show( Self.tooltipInstance.show(
tooltip: tooltip, at: finalOrigin, tooltip: tooltip, at: finalOrigin,
bottomOutOfScreenAdjustmentHeight: delta, direction: tooltipContentDirection bottomOutOfScreenAdjustmentHeight: delta, direction: tooltipContentDirection
) )
@ -83,7 +80,7 @@ extension ctlInputMethod {
} }
if isVerticalTyping { return true } if isVerticalTyping { return true }
// IMK // IMK
guard ctlInputMethod.ctlCandidateCurrent is ctlCandidateUniversal else { return false } guard Self.ctlCandidateCurrent is CtlCandidateUniversal else { return false }
// 使 // 使
// //
// 使 // 使
@ -96,7 +93,7 @@ extension ctlInputMethod {
state.isVerticalCandidateWindow = (isCandidateWindowVertical || !PrefMgr.shared.useHorizontalCandidateList) state.isVerticalCandidateWindow = (isCandidateWindowVertical || !PrefMgr.shared.useHorizontalCandidateList)
ctlInputMethod.ctlCandidateCurrent.delegate = nil Self.ctlCandidateCurrent.delegate = nil
/// currentLayout /// currentLayout
/// ctlCandidate() SymbolTable /// ctlCandidate() SymbolTable
@ -109,26 +106,26 @@ extension ctlInputMethod {
? CandidateLayout.vertical ? CandidateLayout.vertical
: CandidateLayout.horizontal) : CandidateLayout.horizontal)
ctlInputMethod.ctlCandidateCurrent = Self.ctlCandidateCurrent =
PrefMgr.shared.useIMKCandidateWindow PrefMgr.shared.useIMKCandidateWindow
? ctlCandidateIMK.init(candidateLayout) : ctlCandidateUniversal.init(candidateLayout) ? CtlCandidateIMK(candidateLayout) : CtlCandidateUniversal(candidateLayout)
// set the attributes for the candidate panel (which uses NSAttributedString) // set the attributes for the candidate panel (which uses NSAttributedString)
let textSize = PrefMgr.shared.candidateListTextSize let textSize = PrefMgr.shared.candidateListTextSize
let minimumKeyLabelSize: Double = 10 let minimumKeyLabelSize: Double = 10
let keyLabelSize = max(textSize / 2, minimumKeyLabelSize) let keyLabelSize = max(textSize / 2, minimumKeyLabelSize)
func labelFont(name: String?, size: CGFloat) -> NSFont { func labelFont(name: String?, size: Double) -> NSFont {
if let name = name { if let name = name {
return NSFont(name: name, size: size) ?? NSFont.systemFont(ofSize: size) return NSFont(name: name, size: size) ?? NSFont.systemFont(ofSize: size)
} }
return NSFont.systemFont(ofSize: size) return NSFont.systemFont(ofSize: size)
} }
ctlInputMethod.ctlCandidateCurrent.keyLabelFont = labelFont( Self.ctlCandidateCurrent.keyLabelFont = labelFont(
name: PrefMgr.shared.candidateKeyLabelFontName, size: keyLabelSize name: PrefMgr.shared.candidateKeyLabelFontName, size: keyLabelSize
) )
ctlInputMethod.ctlCandidateCurrent.candidateFont = ctlInputMethod.candidateFont( Self.ctlCandidateCurrent.candidateFont = Self.candidateFont(
name: PrefMgr.shared.candidateTextFontName, size: textSize name: PrefMgr.shared.candidateTextFontName, size: textSize
) )
@ -136,33 +133,46 @@ extension ctlInputMethod {
let keyLabels = let keyLabels =
candidateKeys.count > 4 ? Array(candidateKeys) : Array(CandidateKey.defaultKeys) candidateKeys.count > 4 ? Array(candidateKeys) : Array(CandidateKey.defaultKeys)
let keyLabelSuffix = state.type == .ofAssociates ? "^" : "" let keyLabelSuffix = state.type == .ofAssociates ? "^" : ""
ctlInputMethod.ctlCandidateCurrent.keyLabels = keyLabels.map { Self.ctlCandidateCurrent.keyLabels = keyLabels.map {
CandidateKeyLabel(key: String($0), displayedText: String($0) + keyLabelSuffix) CandidateKeyLabel(key: String($0), displayedText: String($0) + keyLabelSuffix)
} }
ctlInputMethod.ctlCandidateCurrent.delegate = self Self.ctlCandidateCurrent.delegate = self
ctlInputMethod.ctlCandidateCurrent.reloadData() Self.ctlCandidateCurrent.showPageButtons = PrefMgr.shared.showPageButtonsInCandidateWindow
Self.ctlCandidateCurrent.useLangIdentifier = PrefMgr.shared.handleDefaultCandidateFontsByLangIdentifier
Self.ctlCandidateCurrent.locale = {
switch inputMode {
case .imeModeCHS: return "zh-Hans"
case .imeModeCHT:
if !PrefMgr.shared.shiftJISShinjitaiOutputEnabled, !PrefMgr.shared.chineseConversionEnabled {
return "zh-Hant"
}
return "ja"
default: return ""
}
}()
Self.ctlCandidateCurrent.reloadData()
if #available(macOS 10.14, *) { if #available(macOS 10.14, *) {
// Spotlight IMK // Spotlight IMK
if let ctlCandidateCurrent = ctlInputMethod.ctlCandidateCurrent as? ctlCandidateIMK { if let ctlCandidateCurrent = Self.ctlCandidateCurrent as? CtlCandidateIMK {
while ctlCandidateCurrent.windowLevel() <= client.windowLevel() { while ctlCandidateCurrent.windowLevel() <= client.windowLevel() {
ctlCandidateCurrent.setWindowLevel(UInt64(max(0, client.windowLevel() + 1000))) ctlCandidateCurrent.setWindowLevel(UInt64(max(0, client.windowLevel() + 1000)))
} }
} }
} }
ctlInputMethod.ctlCandidateCurrent.visible = true Self.ctlCandidateCurrent.visible = true
if isVerticalTyping { if isVerticalTyping {
ctlInputMethod.ctlCandidateCurrent.set( Self.ctlCandidateCurrent.set(
windowTopLeftPoint: NSPoint( windowTopLeftPoint: NSPoint(
x: lineHeightRect().origin.x + lineHeightRect().size.width + 4.0, y: lineHeightRect().origin.y - 4.0 x: lineHeightRect().origin.x + lineHeightRect().size.width + 4.0, y: lineHeightRect().origin.y - 4.0
), ),
bottomOutOfScreenAdjustmentHeight: lineHeightRect().size.height + 4.0 bottomOutOfScreenAdjustmentHeight: lineHeightRect().size.height + 4.0
) )
} else { } else {
ctlInputMethod.ctlCandidateCurrent.set( Self.ctlCandidateCurrent.set(
windowTopLeftPoint: NSPoint(x: lineHeightRect().origin.x, y: lineHeightRect().origin.y - 4.0), windowTopLeftPoint: NSPoint(x: lineHeightRect().origin.x, y: lineHeightRect().origin.y - 4.0),
bottomOutOfScreenAdjustmentHeight: lineHeightRect().size.height + 4.0 bottomOutOfScreenAdjustmentHeight: lineHeightRect().size.height + 4.0
) )
@ -178,7 +188,7 @@ extension ctlInputMethod {
/// **REASON**: IMKCandidates has bug that it does not respect font attributes attached to the /// **REASON**: IMKCandidates has bug that it does not respect font attributes attached to the
/// results generated from `candidiates() -> [Any]!` function. IMKCandidates is plagued with /// results generated from `candidiates() -> [Any]!` function. IMKCandidates is plagued with
/// bugs which are not dealt in the recent decade, regardless Radar complaints from input method developers. /// bugs which are not dealt in the recent decade, regardless Radar complaints from input method developers.
/// 1) Remove the usage of ".languageIdentifier" from ctlCandidateUniversal.swift (already done). /// 1) Make sure the usage of ".languageIdentifier" is disabled in the Dev Zone of the vChewing Preferences.
/// 2) Run "make update" in the project folder to download the latest git-submodule of dictionary file. /// 2) Run "make update" in the project folder to download the latest git-submodule of dictionary file.
/// 3) Compile the target "vChewingInstaller", run it. It will install the input method into /// 3) Compile the target "vChewingInstaller", run it. It will install the input method into
/// "~/Library/Input Methods/" folder. Remember to ENABLE BOTH "vChewing-CHS" /// "~/Library/Input Methods/" folder. Remember to ENABLE BOTH "vChewing-CHS"
@ -188,7 +198,7 @@ extension ctlInputMethod {
/// 5) Do NOT enable either KangXi conversion mode nor JIS conversion mode. They are disabled by default. /// 5) Do NOT enable either KangXi conversion mode nor JIS conversion mode. They are disabled by default.
/// 6) Expecting the glyph differences of the candidate "" between PingFang SC and PingFang TC when rendering /// 6) Expecting the glyph differences of the candidate "" between PingFang SC and PingFang TC when rendering
/// the candidate window in different "vChewing-CHS" and "vChewing-CHT" input modes. /// the candidate window in different "vChewing-CHS" and "vChewing-CHT" input modes.
static func candidateFont(name: String? = nil, size: CGFloat) -> NSFont { static func candidateFont(name: String? = nil, size: Double) -> NSFont {
let finalReturnFont: NSFont = let finalReturnFont: NSFont =
{ {
switch IMEApp.currentInputMode { switch IMEApp.currentInputMode {

View File

@ -0,0 +1,237 @@
// (c) 2011 and onwards The OpenVanilla Project (MIT License).
// All possible vChewing-specific modifications are of:
// (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 InputMethodKit
import NotifierUI
import Shared
// MARK: - Facade
extension SessionCtl {
/// NSEvent
/// - Parameters:
/// - event: nil
/// - sender: 使
/// - Returns: `true` IMK`false`
@objc(handleEvent:client:) override func handle(_ event: NSEvent!, client sender: Any!) -> Bool {
_ = sender //
// MARK:
//
state.isASCIIMode = isASCIIMode
state.isVerticalTyping = isVerticalTyping
// NSEvent nilApple InputMethodKit
// client()
guard let event = event, sender is IMKTextInput else {
resetKeyHandler()
return false
}
// Shift macOS 10.15 macOS
let shouldUseShiftToggleHandle: Bool = {
switch PrefMgr.shared.shiftKeyAccommodationBehavior {
case 0: return false
case 1: return Shared.arrClientShiftHandlingExceptionList.contains(clientBundleIdentifier)
case 2: return true
default: return false
}
}()
/// event event var Shift
if #available(macOS 10.15, *) {
if Self.theShiftKeyDetector.check(event), !PrefMgr.shared.disableShiftTogglingAlphanumericalMode {
if !shouldUseShiftToggleHandle || (!rencentKeyHandledByKeyHandlerEtc && shouldUseShiftToggleHandle) {
let status = NSLocalizedString("NotificationSwitchShift", comment: "")
Notifier.notify(
message: isASCIIMode.toggled()
? NSLocalizedString("Alphanumerical Input Mode", comment: "") + "\n" + status
: NSLocalizedString("Chinese Input Mode", comment: "") + "\n" + status
)
}
if shouldUseShiftToggleHandle {
rencentKeyHandledByKeyHandlerEtc = false
}
return false
}
}
// MARK:
// Shift
if isASCIIMode { return false }
/// flags使 KeyHandler
/// flags
/// event.type == .flagsChanged return false
/// NSInternalInconsistencyException
if event.type == .flagsChanged { return false }
///
guard client() != nil else { return false }
var eventToDeal = event
//
if event.isUp || event.isDown || event.isLeft || event.isRight {
eventToDeal = event.reinitiate(charactersIgnoringModifiers: isVerticalTyping ? "Vertical" : "Horizontal") ?? event
}
// 使 NSEvent Emacs NSEvent NSEvent
if eventToDeal.isEmacsKey {
let verticalProcessing = (state.isCandidateContainer) ? state.isVerticalCandidateWindow : state.isVerticalTyping
eventToDeal = eventToDeal.convertFromEmacKeyEvent(isVerticalContext: verticalProcessing)
}
//
Self.areWeNerfing = eventToDeal.modifierFlags.contains([.shift, .command])
// IMK IMK
if let result = imkCandidatesEventPreHandler(event: eventToDeal) {
if shouldUseShiftToggleHandle { rencentKeyHandledByKeyHandlerEtc = result }
return result
}
/// NSEvent commonEventHandler
/// IMK 便
let result = commonEventHandler(eventToDeal)
if shouldUseShiftToggleHandle {
rencentKeyHandledByKeyHandlerEtc = result
}
return result
}
}
// MARK: - Private functions
extension SessionCtl {
/// handle() IMK
/// handle()
/// - Parameter event: IMK
/// - Returns: `true` IMK`false`
private func commonEventHandler(_ event: NSEvent) -> Bool {
//
// KeyHandler
if !event.charCode.isPrintable { return false }
/// 調
/// result bool IMK
/// keyHandler.handleCandidate()
let result = keyHandler.handle(input: event, state: state) { newState in
self.handle(state: newState)
} errorCallback: { errorString in
vCLog(errorString)
IMEApp.buzz()
}
return result
}
/// handle() IMK
/// handle()
/// - Parameter event: IMK
/// - Returns: `true` IMK`false`
private func imkCandidatesEventPreHandler(event eventToDeal: NSEvent) -> Bool? {
// IMK IMK
// interpretKeyEvents()
// - imkCandidates.interpretKeyEvents()
// - delegate SessionCtl KeyHandler
if let imkCandidates = Self.ctlCandidateCurrent as? CtlCandidateIMK, imkCandidates.visible {
let event: NSEvent = CtlCandidateIMK.replaceNumPadKeyCodes(target: eventToDeal) ?? eventToDeal
// Shift+Enter delegate keyHandler
// Shift Flags
if event.isShiftHold, event.isEnter {
guard let newEvent = event.reinitiate(modifierFlags: []) else {
NSSound.beep()
return true
}
return imkCandidatesEventSubHandler(event: newEvent)
}
//
if let newChar = CtlCandidateIMK.defaultIMKSelectionKey[event.keyCode],
event.isShiftHold, state.type == .ofAssociates,
let newEvent = event.reinitiate(modifierFlags: [], characters: newChar)
{
if #available(macOS 10.14, *) {
imkCandidates.handleKeyboardEvent(newEvent)
} else {
imkCandidates.interpretKeyEvents([newEvent])
}
return true
}
return imkCandidatesEventSubHandler(event: event)
}
return nil
}
private func imkCandidatesEventSubHandler(event: NSEvent) -> Bool {
let eventArray = [event]
guard let imkC = Self.ctlCandidateCurrent as? CtlCandidateIMK else { return false }
if event.isEsc || event.isBackSpace || event.isDelete || (event.isShiftHold && !event.isSpace) {
return commonEventHandler(event)
} else if event.isSymbolMenuPhysicalKey {
//
switch imkC.currentLayout {
case .horizontal: _ = event.isShiftHold ? imkC.moveUp(self) : imkC.moveDown(self)
case .vertical: _ = event.isShiftHold ? imkC.moveLeft(self) : imkC.moveRight(self)
}
return true
} else if event.isSpace {
switch PrefMgr.shared.specifyShiftSpaceKeyBehavior {
case true: _ = event.isShiftHold ? imkC.highlightNextCandidate() : imkC.showNextPage()
case false: _ = event.isShiftHold ? imkC.showNextPage() : imkC.highlightNextCandidate()
}
return true
} else if event.isTab {
switch PrefMgr.shared.specifyShiftTabKeyBehavior {
case true: _ = event.isShiftHold ? imkC.showPreviousPage() : imkC.showNextPage()
case false: _ = event.isShiftHold ? imkC.highlightPreviousCandidate() : imkC.highlightNextCandidate()
}
return true
} else {
if let newChar = CtlCandidateIMK.defaultIMKSelectionKey[event.keyCode] {
/// KeyCode NSEvent Character
/// IMK
let newEvent = event.reinitiate(characters: newChar)
if let newEvent = newEvent {
if PrefMgr.shared.useSCPCTypingMode, state.type == .ofAssociates {
// input.isShiftHold Self.handle()
return event.isShiftHold ? true : commonEventHandler(event)
} else {
if #available(macOS 10.14, *) {
imkC.handleKeyboardEvent(newEvent)
} else {
imkC.interpretKeyEvents([newEvent])
}
return true
}
}
}
if PrefMgr.shared.useSCPCTypingMode, !event.isReservedKey {
return commonEventHandler(event)
}
if state.type == .ofAssociates,
!event.isPageUp, !event.isPageDown, !event.isCursorForward, !event.isCursorBackward,
!event.isCursorClockLeft, !event.isCursorClockRight, !event.isSpace,
!event.isEnter || !PrefMgr.shared.alsoConfirmAssociatedCandidatesByEnter
{
return commonEventHandler(event)
}
imkC.interpretKeyEvents(eventArray)
return true
}
}
}

View File

@ -8,9 +8,12 @@
// 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 PopupCompositionBuffer
import Shared
// MARK: - 調 (State Handling) // MARK: - 調 (State Handling)
extension ctlInputMethod { extension SessionCtl {
/// 調 /// 調
/// ///
/// ///
@ -21,9 +24,9 @@ extension ctlInputMethod {
state = newState state = newState
switch state.type { switch state.type {
case .ofDeactivated: case .ofDeactivated:
ctlInputMethod.ctlCandidateCurrent.delegate = nil Self.ctlCandidateCurrent.delegate = nil
ctlInputMethod.ctlCandidateCurrent.visible = false Self.ctlCandidateCurrent.visible = false
ctlInputMethod.tooltipInstance.hide() Self.tooltipInstance.hide()
if previous.hasComposition { if previous.hasComposition {
commit(text: previous.displayedText) commit(text: previous.displayedText)
} }
@ -36,29 +39,29 @@ extension ctlInputMethod {
state = IMEState.ofEmpty() state = IMEState.ofEmpty()
previous = state previous = state
} }
ctlInputMethod.ctlCandidateCurrent.visible = false Self.ctlCandidateCurrent.visible = false
ctlInputMethod.tooltipInstance.hide() Self.tooltipInstance.hide()
// .Abortion // .Abortion
if previous.hasComposition, state.type != .ofAbortion { if previous.hasComposition, state.type != .ofAbortion {
commit(text: previous.displayedText) commit(text: previous.displayedText)
} }
// //
ctlInputMethod.ctlCandidateCurrent.visible = false Self.ctlCandidateCurrent.visible = false
ctlInputMethod.tooltipInstance.hide() Self.tooltipInstance.hide()
clearInlineDisplay() clearInlineDisplay()
// //
keyHandler.clear() keyHandler.clear()
case .ofCommitting: case .ofCommitting:
ctlInputMethod.ctlCandidateCurrent.visible = false Self.ctlCandidateCurrent.visible = false
ctlInputMethod.tooltipInstance.hide() Self.tooltipInstance.hide()
let textToCommit = state.textToCommit let textToCommit = state.textToCommit
if !textToCommit.isEmpty { commit(text: textToCommit) } if !textToCommit.isEmpty { commit(text: textToCommit) }
clearInlineDisplay() clearInlineDisplay()
// //
keyHandler.clear() keyHandler.clear()
case .ofInputting: case .ofInputting:
ctlInputMethod.ctlCandidateCurrent.visible = false Self.ctlCandidateCurrent.visible = false
ctlInputMethod.tooltipInstance.hide() Self.tooltipInstance.hide()
let textToCommit = state.textToCommit let textToCommit = state.textToCommit
if !textToCommit.isEmpty { commit(text: textToCommit) } if !textToCommit.isEmpty { commit(text: textToCommit) }
setInlineDisplayWithCursor() setInlineDisplayWithCursor()
@ -66,27 +69,27 @@ extension ctlInputMethod {
show(tooltip: state.tooltip) show(tooltip: state.tooltip)
} }
case .ofMarking: case .ofMarking:
ctlInputMethod.ctlCandidateCurrent.visible = false Self.ctlCandidateCurrent.visible = false
setInlineDisplayWithCursor() setInlineDisplayWithCursor()
if state.tooltip.isEmpty { if state.tooltip.isEmpty {
ctlInputMethod.tooltipInstance.hide() Self.tooltipInstance.hide()
} else { } else {
show(tooltip: state.tooltip) show(tooltip: state.tooltip)
} }
case .ofCandidates, .ofAssociates, .ofSymbolTable: case .ofCandidates, .ofAssociates, .ofSymbolTable:
ctlInputMethod.tooltipInstance.hide() Self.tooltipInstance.hide()
setInlineDisplayWithCursor() setInlineDisplayWithCursor()
showCandidates() showCandidates()
default: break default: break
} }
// //
if state.hasComposition, PrefMgr.shared.clientsIMKTextInputIncapable.contains(clientBundleIdentifier) { if state.hasComposition, PrefMgr.shared.clientsIMKTextInputIncapable.contains(clientBundleIdentifier) {
ctlInputMethod.popupCompositionBuffer.isTypingDirectionVertical = isVerticalTyping Self.popupCompositionBuffer.isTypingDirectionVertical = isVerticalTyping
ctlInputMethod.popupCompositionBuffer.show( Self.popupCompositionBuffer.show(
state: state, at: lineHeightRect(zeroCursor: true).origin state: state, at: lineHeightRect(zeroCursor: true).origin
) )
} else { } else {
ctlInputMethod.popupCompositionBuffer.hide() Self.popupCompositionBuffer.hide()
} }
} }

View File

@ -0,0 +1,129 @@
// (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 Foundation
import Tekkon
// MARK: - IMKCandidates
extension SessionCtl {
/// IMK
/// - Parameter sender: 使
/// - Returns: IMK
override func candidates(_ sender: Any!) -> [Any]! {
_ = sender //
var arrResult = [String]()
// 便 IMEState
func handleIMKCandidatesPrepared(_ candidates: [(String, String)], prefix: String = "") {
for theCandidate in candidates {
let theConverted = ChineseConverter.kanjiConversionIfRequired(theCandidate.1)
var result = (theCandidate.1 == theConverted) ? theCandidate.1 : "\(theConverted)\u{1A}(\(theCandidate.1))"
if arrResult.contains(result) {
let reading: String =
PrefMgr.shared.showHanyuPinyinInCompositionBuffer
? Tekkon.cnvPhonaToHanyuPinyin(target: Tekkon.restoreToneOneInZhuyinKey(target: theCandidate.0))
: theCandidate.0
result = "\(result)\u{17}(\(reading))"
}
arrResult.append(prefix + result)
}
}
if state.type == .ofAssociates {
handleIMKCandidatesPrepared(state.candidates, prefix: "")
} else if state.type == .ofSymbolTable {
// / JIS 使
arrResult = state.candidates.map(\.1)
} else if state.type == .ofCandidates {
guard !state.candidates.isEmpty else { return .init() }
if state.candidates[0].0.contains("_punctuation") {
arrResult = state.candidates.map(\.1) //
} else {
handleIMKCandidatesPrepared(state.candidates)
}
}
return arrResult
}
/// IMK
/// - Parameter _:
override open func candidateSelectionChanged(_: NSAttributedString!) {
//
// IMKServer.commitCompositionWithReply() commitComposition()
// keyHandler
//
//
// ctlCandidateIMK identifier
// NSNotFound NSLog identifier
// console ips
// candidateSelected() identifier NSNotFound
// IMK 西
}
/// IMK
/// - Parameter candidateString:
override open func candidateSelected(_ candidateString: NSAttributedString!) {
let candidateString: String = candidateString?.string ?? ""
if state.type == .ofAssociates {
if !PrefMgr.shared.alsoConfirmAssociatedCandidatesByEnter {
handle(state: IMEState.ofAbortion())
return
}
}
var indexDeducted = 0
// 便 IMEState
func handleIMKCandidatesSelected(_ candidates: [(String, String)], prefix: String = "") {
for (i, neta) in candidates.enumerated() {
let theConverted = ChineseConverter.kanjiConversionIfRequired(neta.1)
let netaShown = (neta.1 == theConverted) ? neta.1 : "\(theConverted)\u{1A}(\(neta.1))"
let reading: String =
PrefMgr.shared.showHanyuPinyinInCompositionBuffer
? Tekkon.cnvPhonaToHanyuPinyin(target: Tekkon.restoreToneOneInZhuyinKey(target: neta.0)) : neta.0
let netaShownWithPronunciation = "\(netaShown)\u{17}(\(reading))"
if candidateString == prefix + netaShownWithPronunciation {
indexDeducted = i
break
}
if candidateString == prefix + netaShown {
indexDeducted = i
break
}
}
}
// / JIS 使
func handleSymbolCandidatesSelected(_ candidates: [(String, String)]) {
for (i, neta) in candidates.enumerated() {
if candidateString == neta.1 {
indexDeducted = i
break
}
}
}
if state.type == .ofAssociates {
handleIMKCandidatesSelected(state.candidates, prefix: "")
} else if state.type == .ofSymbolTable {
handleSymbolCandidatesSelected(state.candidates)
} else if state.type == .ofCandidates {
guard !state.candidates.isEmpty else { return }
if state.candidates[0].0.contains("_punctuation") {
handleSymbolCandidatesSelected(state.candidates) //
} else {
handleIMKCandidatesSelected(state.candidates)
}
}
candidatePairSelected(at: indexDeducted)
}
}

View File

@ -8,6 +8,7 @@
// 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 NotifierUI
import Preferences import Preferences
extension Bool { extension Bool {
@ -20,7 +21,7 @@ extension Bool {
// //
extension ctlInputMethod { extension SessionCtl {
override func menu() -> NSMenu! { override func menu() -> NSMenu! {
let optionKeyPressed = NSEvent.modifierFlags.contains(.option) let optionKeyPressed = NSEvent.modifierFlags.contains(.option)
@ -191,7 +192,7 @@ extension ctlInputMethod {
// MARK: - IME Menu Items // MARK: - IME Menu Items
extension ctlInputMethod { extension SessionCtl {
@objc override func showPreferences(_: Any?) { @objc override func showPreferences(_: Any?) {
if #unavailable(macOS 10.15) { if #unavailable(macOS 10.15) {
showLegacyPreferences() showLegacyPreferences()
@ -223,7 +224,7 @@ extension ctlInputMethod {
@objc func toggleSCPCTypingMode(_: Any? = nil) { @objc func toggleSCPCTypingMode(_: Any? = nil) {
resetKeyHandler() resetKeyHandler()
NotifierController.notify( Notifier.notify(
message: NSLocalizedString("Per-Char Select Mode", comment: "") + "\n" message: NSLocalizedString("Per-Char Select Mode", comment: "") + "\n"
+ (PrefMgr.shared.useSCPCTypingMode.toggled() + (PrefMgr.shared.useSCPCTypingMode.toggled()
? NSLocalizedString("NotificationSwitchON", comment: "") ? NSLocalizedString("NotificationSwitchON", comment: "")
@ -233,7 +234,7 @@ extension ctlInputMethod {
@objc func toggleChineseConverter(_: Any?) { @objc func toggleChineseConverter(_: Any?) {
resetKeyHandler() resetKeyHandler()
NotifierController.notify( Notifier.notify(
message: NSLocalizedString("Force KangXi Writing", comment: "") + "\n" message: NSLocalizedString("Force KangXi Writing", comment: "") + "\n"
+ (PrefMgr.shared.chineseConversionEnabled.toggled() + (PrefMgr.shared.chineseConversionEnabled.toggled()
? NSLocalizedString("NotificationSwitchON", comment: "") ? NSLocalizedString("NotificationSwitchON", comment: "")
@ -243,7 +244,7 @@ extension ctlInputMethod {
@objc func toggleShiftJISShinjitaiOutput(_: Any?) { @objc func toggleShiftJISShinjitaiOutput(_: Any?) {
resetKeyHandler() resetKeyHandler()
NotifierController.notify( Notifier.notify(
message: NSLocalizedString("JIS Shinjitai Output", comment: "") + "\n" message: NSLocalizedString("JIS Shinjitai Output", comment: "") + "\n"
+ (PrefMgr.shared.shiftJISShinjitaiOutputEnabled.toggled() + (PrefMgr.shared.shiftJISShinjitaiOutputEnabled.toggled()
? NSLocalizedString("NotificationSwitchON", comment: "") ? NSLocalizedString("NotificationSwitchON", comment: "")
@ -253,7 +254,7 @@ extension ctlInputMethod {
@objc func toggleCurrencyNumerals(_: Any?) { @objc func toggleCurrencyNumerals(_: Any?) {
resetKeyHandler() resetKeyHandler()
NotifierController.notify( Notifier.notify(
message: NSLocalizedString("Currency Numeral Output", comment: "") + "\n" message: NSLocalizedString("Currency Numeral Output", comment: "") + "\n"
+ (PrefMgr.shared.currencyNumeralsEnabled.toggled() + (PrefMgr.shared.currencyNumeralsEnabled.toggled()
? NSLocalizedString("NotificationSwitchON", comment: "") ? NSLocalizedString("NotificationSwitchON", comment: "")
@ -263,7 +264,7 @@ extension ctlInputMethod {
@objc func toggleHalfWidthPunctuation(_: Any?) { @objc func toggleHalfWidthPunctuation(_: Any?) {
resetKeyHandler() resetKeyHandler()
NotifierController.notify( Notifier.notify(
message: NSLocalizedString("Half-Width Punctuation Mode", comment: "") + "\n" message: NSLocalizedString("Half-Width Punctuation Mode", comment: "") + "\n"
+ (PrefMgr.shared.halfWidthPunctuationEnabled.toggled() + (PrefMgr.shared.halfWidthPunctuationEnabled.toggled()
? NSLocalizedString("NotificationSwitchON", comment: "") ? NSLocalizedString("NotificationSwitchON", comment: "")
@ -273,7 +274,7 @@ extension ctlInputMethod {
@objc func toggleCNS11643Enabled(_: Any?) { @objc func toggleCNS11643Enabled(_: Any?) {
resetKeyHandler() resetKeyHandler()
NotifierController.notify( Notifier.notify(
message: NSLocalizedString("CNS11643 Mode", comment: "") + "\n" message: NSLocalizedString("CNS11643 Mode", comment: "") + "\n"
+ (PrefMgr.shared.cns11643Enabled.toggled() + (PrefMgr.shared.cns11643Enabled.toggled()
? NSLocalizedString("NotificationSwitchON", comment: "") ? NSLocalizedString("NotificationSwitchON", comment: "")
@ -283,7 +284,7 @@ extension ctlInputMethod {
@objc func toggleSymbolEnabled(_: Any?) { @objc func toggleSymbolEnabled(_: Any?) {
resetKeyHandler() resetKeyHandler()
NotifierController.notify( Notifier.notify(
message: NSLocalizedString("Symbol & Emoji Input", comment: "") + "\n" message: NSLocalizedString("Symbol & Emoji Input", comment: "") + "\n"
+ (PrefMgr.shared.symbolInputEnabled.toggled() + (PrefMgr.shared.symbolInputEnabled.toggled()
? NSLocalizedString("NotificationSwitchON", comment: "") ? NSLocalizedString("NotificationSwitchON", comment: "")
@ -293,7 +294,7 @@ extension ctlInputMethod {
@objc func toggleAssociatedPhrasesEnabled(_: Any?) { @objc func toggleAssociatedPhrasesEnabled(_: Any?) {
resetKeyHandler() resetKeyHandler()
NotifierController.notify( Notifier.notify(
message: NSLocalizedString("Per-Char Associated Phrases", comment: "") + "\n" message: NSLocalizedString("Per-Char Associated Phrases", comment: "") + "\n"
+ (PrefMgr.shared.associatedPhrasesEnabled.toggled() + (PrefMgr.shared.associatedPhrasesEnabled.toggled()
? NSLocalizedString("NotificationSwitchON", comment: "") ? NSLocalizedString("NotificationSwitchON", comment: "")
@ -303,7 +304,7 @@ extension ctlInputMethod {
@objc func togglePhraseReplacement(_: Any?) { @objc func togglePhraseReplacement(_: Any?) {
resetKeyHandler() resetKeyHandler()
NotifierController.notify( Notifier.notify(
message: NSLocalizedString("Use Phrase Replacement", comment: "") + "\n" message: NSLocalizedString("Use Phrase Replacement", comment: "") + "\n"
+ (PrefMgr.shared.phraseReplacementEnabled.toggled() + (PrefMgr.shared.phraseReplacementEnabled.toggled()
? NSLocalizedString("NotificationSwitchON", comment: "") ? NSLocalizedString("NotificationSwitchON", comment: "")

View File

@ -6,12 +6,19 @@
// 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.
public class ctlCandidateIMK: IMKCandidates, ctlCandidateProtocol { import CandidateWindow
import Shared
/// IMKCandidates bridging header Swift Package
public class CtlCandidateIMK: IMKCandidates, CtlCandidateProtocol {
public var showPageButtons: Bool = false
public var locale: String = ""
public var useLangIdentifier: Bool = false
public var currentLayout: CandidateLayout = .horizontal public var currentLayout: CandidateLayout = .horizontal
public static let defaultIMKSelectionKey: [UInt16: String] = [ public static let defaultIMKSelectionKey: [UInt16: String] = [
18: "1", 19: "2", 20: "3", 21: "4", 23: "5", 22: "6", 26: "7", 28: "8", 25: "9", 18: "1", 19: "2", 20: "3", 21: "4", 23: "5", 22: "6", 26: "7", 28: "8", 25: "9",
] ]
public weak var delegate: ctlCandidateDelegate? { public weak var delegate: CtlCandidateDelegate? {
didSet { didSet {
reloadData() reloadData()
} }
@ -40,26 +47,15 @@ public class ctlCandidateIMK: IMKCandidates, ctlCandidateProtocol {
ofSize: 14, weight: .medium ofSize: 14, weight: .medium
) )
public var candidateFont = NSFont.systemFont(ofSize: PrefMgr.shared.candidateListTextSize) { public var candidateFont = NSFont.systemFont(ofSize: 16) {
didSet { didSet {
if #available(macOS 10.14, *) { setFontSize(candidateFont.pointSize) } if #available(macOS 10.14, *) { setFontSize(candidateFont.pointSize) }
var attributes = attributes() var attributes = attributes()
// FB11300759: Set "NSAttributedString.Key.font" doesn't work. // FB11300759: Set "NSAttributedString.Key.font" doesn't work.
attributes?[NSAttributedString.Key.font] = candidateFont attributes?[NSAttributedString.Key.font] = candidateFont
if PrefMgr.shared.handleDefaultCandidateFontsByLangIdentifier {
switch IMEApp.currentInputMode {
case .imeModeCHS:
if #available(macOS 12.0, *) { if #available(macOS 12.0, *) {
attributes?[NSAttributedString.Key.languageIdentifier] = "zh-Hans" as AnyObject if useLangIdentifier {
} attributes?[NSAttributedString.Key.languageIdentifier] = locale as AnyObject
case .imeModeCHT:
if #available(macOS 12.0, *) {
attributes?[NSAttributedString.Key.languageIdentifier] =
(PrefMgr.shared.shiftJISShinjitaiOutputEnabled || PrefMgr.shared.chineseConversionEnabled)
? "ja" as AnyObject : "zh-Hant" as AnyObject
}
default:
break
} }
} }
setAttributes(attributes) setAttributes(attributes)
@ -119,7 +115,7 @@ public class ctlCandidateIMK: IMKCandidates, ctlCandidateProtocol {
private var pageCount: Int { private var pageCount: Int {
guard let delegate = delegate else { return 0 } guard let delegate = delegate else { return 0 }
let totalCount = delegate.candidateCountForController(self) let totalCount = delegate.candidatePairs().count
let keyLabelCount = keyLabels.count let keyLabelCount = keyLabels.count
return totalCount / keyLabelCount + ((totalCount % keyLabelCount) != 0 ? 1 : 0) return totalCount / keyLabelCount + ((totalCount % keyLabelCount) != 0 ? 1 : 0)
} }
@ -151,7 +147,7 @@ public class ctlCandidateIMK: IMKCandidates, ctlCandidateProtocol {
public func candidateIndexAtKeyLabelIndex(_ index: Int) -> Int { public func candidateIndexAtKeyLabelIndex(_ index: Int) -> Int {
guard let delegate = delegate else { return Int.max } guard let delegate = delegate else { return Int.max }
let result = currentPageIndex * keyLabels.count + index let result = currentPageIndex * keyLabels.count + index
return result < delegate.candidateCountForController(self) ? result : Int.max return result < delegate.candidatePairs().count ? result : Int.max
} }
public var selectedCandidateIndex: Int { public var selectedCandidateIndex: Int {
@ -159,17 +155,17 @@ public class ctlCandidateIMK: IMKCandidates, ctlCandidateProtocol {
set { selectCandidate(withIdentifier: newValue) } set { selectCandidate(withIdentifier: newValue) }
} }
public func set(windowTopLeftPoint: NSPoint, bottomOutOfScreenAdjustmentHeight height: CGFloat) { public func set(windowTopLeftPoint: NSPoint, bottomOutOfScreenAdjustmentHeight height: Double) {
DispatchQueue.main.async { DispatchQueue.main.async {
self.doSet(windowTopLeftPoint: windowTopLeftPoint, bottomOutOfScreenAdjustmentHeight: height) self.doSet(windowTopLeftPoint: windowTopLeftPoint, bottomOutOfScreenAdjustmentHeight: height)
} }
} }
func doSet(windowTopLeftPoint: NSPoint, bottomOutOfScreenAdjustmentHeight heightDelta: CGFloat) { func doSet(windowTopLeftPoint: NSPoint, bottomOutOfScreenAdjustmentHeight heightDelta: Double) {
guard var screenFrame = NSScreen.main?.visibleFrame else { return }
var adjustedPoint = windowTopLeftPoint var adjustedPoint = windowTopLeftPoint
let windowSize = candidateFrame().size let windowSize = candidateFrame().size
var delta = heightDelta var delta = heightDelta
var screenFrame = NSScreen.main?.visibleFrame ?? NSRect.seniorTheBeast
for frame in NSScreen.screens.map(\.visibleFrame).filter({ $0.contains(windowTopLeftPoint) }) { for frame in NSScreen.screens.map(\.visibleFrame).filter({ $0.contains(windowTopLeftPoint) }) {
screenFrame = frame screenFrame = frame
break break
@ -185,74 +181,6 @@ public class ctlCandidateIMK: IMKCandidates, ctlCandidateProtocol {
setCandidateFrameTopLeft(adjustedPoint) setCandidateFrameTopLeft(adjustedPoint)
} }
override public func interpretKeyEvents(_ eventArray: [NSEvent]) {
//
// Objective-C nil
guard !eventArray.isEmpty else { return }
let event = eventArray[0]
guard let delegate = delegate else { return }
if event.isEsc || event.isBackSpace || event.isDelete || (event.isShiftHold && !event.isSpace) {
_ = delegate.sharedEventHandler(event)
} else if event.isSymbolMenuPhysicalKey {
//
switch currentLayout {
case .horizontal: event.isShiftHold ? moveUp(self) : moveDown(self)
case .vertical: event.isShiftHold ? moveLeft(self) : moveRight(self)
}
} else if event.isSpace {
switch PrefMgr.shared.specifyShiftSpaceKeyBehavior {
case true: _ = event.isShiftHold ? highlightNextCandidate() : showNextPage()
case false: _ = event.isShiftHold ? showNextPage() : highlightNextCandidate()
}
} else if event.isTab {
switch PrefMgr.shared.specifyShiftTabKeyBehavior {
case true: _ = event.isShiftHold ? showPreviousPage() : showNextPage()
case false: _ = event.isShiftHold ? highlightPreviousCandidate() : highlightNextCandidate()
}
} else {
if let newChar = Self.defaultIMKSelectionKey[event.keyCode] {
/// KeyCode NSEvent Character
/// IMK
let newEvent = event.reinitiate(characters: newChar)
if let newEvent = newEvent {
if PrefMgr.shared.useSCPCTypingMode, delegate.isAssociatedPhrasesState {
// input.isShiftHold ctlInputMethod.handle()
if !event.isShiftHold {
_ = delegate.sharedEventHandler(event)
return
}
} else {
if #available(macOS 10.14, *) {
handleKeyboardEvent(newEvent)
} else {
super.interpretKeyEvents([newEvent])
}
return
}
}
}
if PrefMgr.shared.useSCPCTypingMode, !event.isReservedKey {
_ = delegate.sharedEventHandler(event)
return
}
if delegate.isAssociatedPhrasesState,
!event.isPageUp, !event.isPageDown, !event.isCursorForward, !event.isCursorBackward,
!event.isCursorClockLeft, !event.isCursorClockRight, !event.isSpace,
!event.isEnter || !PrefMgr.shared.alsoConfirmAssociatedCandidatesByEnter
{
_ = delegate.sharedEventHandler(event)
return
}
super.interpretKeyEvents(eventArray)
}
}
public func superInterpretKeyEvents(_ eventArray: [NSEvent]) {
super.interpretKeyEvents(eventArray)
}
} }
// MARK: - Generate TISInputSource Object // MARK: - Generate TISInputSource Object
@ -277,7 +205,7 @@ var currentTISInputSource: TISInputSource? {
// MARK: - Translating NumPad KeyCodes to Default IMK Candidate Selection KeyCodes. // MARK: - Translating NumPad KeyCodes to Default IMK Candidate Selection KeyCodes.
extension ctlCandidateIMK { extension CtlCandidateIMK {
public static func replaceNumPadKeyCodes(target event: NSEvent) -> NSEvent? { public static func replaceNumPadKeyCodes(target event: NSEvent) -> NSEvent? {
let mapNumPadKeyCodeTranslation: [UInt16: UInt16] = [ let mapNumPadKeyCodeTranslation: [UInt16: UInt16] = [
83: 18, 84: 19, 85: 20, 86: 21, 87: 23, 88: 22, 89: 26, 91: 28, 92: 25, 83: 18, 84: 19, 85: 20, 86: 21, 87: 23, 88: 22, 89: 26, 91: 28, 92: 25,

View File

@ -1,175 +0,0 @@
// (c) 2011 and onwards The OpenVanilla Project (MIT License).
// All possible vChewing-specific modifications are of:
// (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.
public enum CandidateLayout {
case horizontal
case vertical
}
public class CandidateKeyLabel: NSObject {
public private(set) var key: String
public private(set) var displayedText: String
public init(key: String, displayedText: String) {
self.key = key
self.displayedText = displayedText
super.init()
}
}
public protocol ctlCandidateDelegate: AnyObject {
var isAssociatedPhrasesState: Bool { get }
func sharedEventHandler(_ event: NSEvent) -> Bool
func candidateCountForController(_ controller: ctlCandidateProtocol) -> Int
func candidatesForController(_ controller: ctlCandidateProtocol) -> [(String, String)]
func ctlCandidate(_ controller: ctlCandidateProtocol, candidateAtIndex index: Int)
-> (String, String)
func candidateSelected(at index: Int)
}
public protocol ctlCandidateProtocol {
var currentLayout: CandidateLayout { get set }
var delegate: ctlCandidateDelegate? { get set }
var selectedCandidateIndex: Int { get set }
var visible: Bool { get set }
var windowTopLeftPoint: NSPoint { get set }
var keyLabels: [CandidateKeyLabel] { get set }
var keyLabelFont: NSFont { get set }
var candidateFont: NSFont { get set }
var tooltip: String { get set }
init(_ layout: CandidateLayout)
func reloadData()
func showNextPage() -> Bool
func showPreviousPage() -> Bool
func highlightNextCandidate() -> Bool
func highlightPreviousCandidate() -> Bool
func candidateIndexAtKeyLabelIndex(_: Int) -> Int
func set(windowTopLeftPoint: NSPoint, bottomOutOfScreenAdjustmentHeight height: CGFloat)
}
public class ctlCandidate: NSWindowController, ctlCandidateProtocol {
public var currentLayout: CandidateLayout = .horizontal
public weak var delegate: ctlCandidateDelegate? {
didSet {
reloadData()
}
}
public var selectedCandidateIndex: Int = .max
public var visible = false {
didSet {
NSObject.cancelPreviousPerformRequests(withTarget: self)
if visible {
window?.perform(#selector(NSWindow.orderFront(_:)), with: self, afterDelay: 0.0)
} else {
window?.perform(#selector(NSWindow.orderOut(_:)), with: self, afterDelay: 0.0)
}
}
}
public var windowTopLeftPoint: NSPoint {
get {
guard let frameRect = window?.frame else {
return NSPoint.zero
}
return NSPoint(x: frameRect.minX, y: frameRect.maxY)
}
set {
DispatchQueue.main.async {
self.set(windowTopLeftPoint: newValue, bottomOutOfScreenAdjustmentHeight: 0)
}
}
}
public required init(_: CandidateLayout = .horizontal) {
super.init(window: .init())
visible = false
}
@available(*, unavailable)
required init?(coder _: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
public var keyLabels: [CandidateKeyLabel] = ["1", "2", "3", "4", "5", "6", "7", "8", "9"]
.map {
CandidateKeyLabel(key: $0, displayedText: $0)
}
public var keyLabelFont = NSFont.monospacedDigitSystemFont(
ofSize: 14, weight: .medium
)
public var candidateFont = NSFont.systemFont(ofSize: 18)
public var tooltip: String = ""
public func reloadData() {}
@discardableResult public func showNextPage() -> Bool {
false
}
@discardableResult public func showPreviousPage() -> Bool {
false
}
@discardableResult public func highlightNextCandidate() -> Bool {
false
}
@discardableResult public func highlightPreviousCandidate() -> Bool {
false
}
public func candidateIndexAtKeyLabelIndex(_: Int) -> Int {
Int.max
}
/// Sets the location of the candidate window.
///
/// Please note that the method has side effects that modifies
/// `windowTopLeftPoint` to make the candidate window to stay in at least
/// in a screen.
///
/// - Parameters:
/// - windowTopLeftPoint: The given location.
/// - height: The height that helps the window not to be out of the bottom
/// of a screen.
public func set(windowTopLeftPoint: NSPoint, bottomOutOfScreenAdjustmentHeight height: CGFloat) {
DispatchQueue.main.async {
self.doSet(
windowTopLeftPoint: windowTopLeftPoint, bottomOutOfScreenAdjustmentHeight: height
)
}
}
func doSet(windowTopLeftPoint: NSPoint, bottomOutOfScreenAdjustmentHeight heightDelta: CGFloat) {
guard let window = window else { return }
let windowSize = window.frame.size
var adjustedPoint = windowTopLeftPoint
var delta = heightDelta
var screenFrame = NSScreen.main?.visibleFrame ?? NSRect.seniorTheBeast
for frame in NSScreen.screens.map(\.visibleFrame).filter({ $0.contains(windowTopLeftPoint) }) {
screenFrame = frame
break
}
if delta > screenFrame.size.height / 2.0 { delta = 0.0 }
if adjustedPoint.y < screenFrame.minY + windowSize.height {
adjustedPoint.y = windowTopLeftPoint.y + windowSize.height + delta
}
adjustedPoint.y = min(adjustedPoint.y, screenFrame.maxY - 1.0)
adjustedPoint.x = min(max(adjustedPoint.x, screenFrame.minX), screenFrame.maxX - windowSize.width - 1.0)
window.setFrameTopLeftPoint(adjustedPoint)
}
}

View File

@ -1,226 +0,0 @@
// (c) 2021 and onwards Weizhong Yang (MIT License).
// All possible vChewing-specific modifications are of:
// (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.
private protocol NotifierWindowDelegate: AnyObject {
func windowDidBecomeClicked(_ window: NotifierWindow)
}
private class NotifierWindow: NSWindow {
weak var clickDelegate: NotifierWindowDelegate?
override func mouseDown(with _: NSEvent) {
clickDelegate?.windowDidBecomeClicked(self)
}
}
private let kWindowWidth: CGFloat = 213.0
private let kWindowHeight: CGFloat = 60.0
public class NotifierController: NSWindowController, NotifierWindowDelegate {
static var message: String = "" {
didSet {
if !Self.message.isEmpty {
NotifierController.initiateWithNoStay(message: message)
Self.message = ""
}
}
}
private var messageTextField: NSTextField
private var message: String = "" {
didSet {
let paraStyle = NSMutableParagraphStyle()
paraStyle.setParagraphStyle(NSParagraphStyle.default)
paraStyle.alignment = .center
let attr: [NSAttributedString.Key: AnyObject] = [
.foregroundColor: foregroundColor,
.font: NSFont.boldSystemFont(ofSize: NSFont.systemFontSize(for: .regular)),
.paragraphStyle: paraStyle,
]
let attrString = NSAttributedString(string: message, attributes: attr)
messageTextField.attributedStringValue = attrString
let width = window?.frame.width ?? kWindowWidth
let rect = attrString.boundingRect(
with: NSSize(width: width, height: 1600), options: .usesLineFragmentOrigin
)
let height = rect.height
let x = messageTextField.frame.origin.x
let y = ((window?.frame.height ?? kWindowHeight) - height) / 2
let newFrame = NSRect(x: x, y: y, width: width, height: height)
messageTextField.frame = newFrame
}
}
private var shouldStay = false
private var backgroundColor: NSColor = .textBackgroundColor {
didSet {
window?.backgroundColor = backgroundColor
}
}
private var foregroundColor: NSColor = .controlTextColor {
didSet {
messageTextField.textColor = foregroundColor
}
}
private var waitTimer: Timer?
private var fadeTimer: Timer?
private static var instanceCount = 0
private static var lastLocation = NSPoint.zero
private static func initiateWithNoStay(message: String) {
let controller = NotifierController()
controller.message = message
controller.show()
}
public static func notify(message: String) {
Self.message = message
}
public static func notify(message: String, stay: Bool) {
let controller = NotifierController()
controller.message = message
controller.shouldStay = stay
controller.show()
}
private static func increaseInstanceCount() {
instanceCount += 1
}
private static func decreaseInstanceCount() {
instanceCount -= 1
if instanceCount < 0 {
instanceCount = 0
}
}
private init() {
let screenRect = NSScreen.main?.visibleFrame ?? NSRect.seniorTheBeast
let contentRect = NSRect(x: 0, y: 0, width: kWindowWidth, height: kWindowHeight)
var windowRect = contentRect
windowRect.origin.x = screenRect.maxX - windowRect.width - 10
windowRect.origin.y = screenRect.maxY - windowRect.height - 10
let styleMask: NSWindow.StyleMask = [.fullSizeContentView, .titled]
let transparentVisualEffect = NSVisualEffectView()
transparentVisualEffect.blendingMode = .behindWindow
transparentVisualEffect.state = .active
let panel = NotifierWindow(
contentRect: windowRect, styleMask: styleMask, backing: .buffered, defer: false
)
panel.contentView = transparentVisualEffect
panel.isMovableByWindowBackground = true
panel.level = NSWindow.Level(Int(kCGPopUpMenuWindowLevel))
panel.hasShadow = true
panel.backgroundColor = backgroundColor
panel.title = ""
panel.titlebarAppearsTransparent = true
panel.titleVisibility = .hidden
panel.showsToolbarButton = false
panel.standardWindowButton(NSWindow.ButtonType.zoomButton)?.isHidden = true
panel.standardWindowButton(NSWindow.ButtonType.miniaturizeButton)?.isHidden = true
panel.standardWindowButton(NSWindow.ButtonType.closeButton)?.isHidden = true
panel.standardWindowButton(NSWindow.ButtonType.zoomButton)?.isHidden = true
messageTextField = NSTextField()
messageTextField.frame = contentRect
messageTextField.isEditable = false
messageTextField.isSelectable = false
messageTextField.isBezeled = false
messageTextField.textColor = foregroundColor
messageTextField.drawsBackground = false
messageTextField.font = .boldSystemFont(ofSize: NSFont.systemFontSize(for: .regular))
panel.contentView?.addSubview(messageTextField)
super.init(window: panel)
panel.clickDelegate = self
}
@available(*, unavailable)
required init?(coder _: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
private func show() {
func setStartLocation() {
if Self.instanceCount == 0 {
return
}
let lastLocation = Self.lastLocation
let screenRect = NSScreen.main?.visibleFrame ?? NSRect.seniorTheBeast
var windowRect = window?.frame ?? NSRect.seniorTheBeast
windowRect.origin.x = lastLocation.x
windowRect.origin.y = lastLocation.y - 10 - windowRect.height
if windowRect.origin.y < screenRect.minY {
return
}
window?.setFrame(windowRect, display: true)
}
func moveIn() {
let afterRect = window?.frame ?? NSRect.seniorTheBeast
Self.lastLocation = afterRect.origin
var beforeRect = afterRect
beforeRect.origin.y += 10
window?.setFrame(beforeRect, display: true)
window?.orderFront(self)
window?.setFrame(afterRect, display: true, animate: true)
}
setStartLocation()
moveIn()
Self.increaseInstanceCount()
waitTimer = Timer.scheduledTimer(
timeInterval: shouldStay ? 5 : 1, target: self, selector: #selector(fadeOut),
userInfo: nil,
repeats: false
)
}
@objc private func doFadeOut(_: Timer) {
let opacity = window?.alphaValue ?? 0
if opacity <= 0 {
close()
} else {
window?.alphaValue = opacity - 0.2
}
}
@objc private func fadeOut() {
waitTimer?.invalidate()
waitTimer = nil
Self.decreaseInstanceCount()
fadeTimer = Timer.scheduledTimer(
timeInterval: 0.01, target: self, selector: #selector(doFadeOut(_:)), userInfo: nil,
repeats: true
)
}
override public func close() {
waitTimer?.invalidate()
waitTimer = nil
fadeTimer?.invalidate()
fadeTimer = nil
super.close()
}
fileprivate func windowDidBecomeClicked(_: NotifierWindow) {
fadeOut()
}
}

View File

@ -19,7 +19,7 @@ struct suiPrefPaneDevZone: View {
@State private var selShiftKeyAccommodationBehavior: Int = UserDefaults.standard.integer( @State private var selShiftKeyAccommodationBehavior: Int = UserDefaults.standard.integer(
forKey: UserDef.kShiftKeyAccommodationBehavior.rawValue) forKey: UserDef.kShiftKeyAccommodationBehavior.rawValue)
private let contentMaxHeight: Double = 432 private let contentMaxHeight: Double = 440
private let contentWidth: Double = { private let contentWidth: Double = {
switch PrefMgr.shared.appleLanguages[0] { switch PrefMgr.shared.appleLanguages[0] {
case "ja": case "ja":

View File

@ -37,7 +37,7 @@ struct suiPrefPaneDictionary: View {
private static let dlgOpenPath = NSOpenPanel() private static let dlgOpenPath = NSOpenPanel()
private let contentMaxHeight: Double = 432 private let contentMaxHeight: Double = 440
private let contentWidth: Double = { private let contentWidth: Double = {
switch PrefMgr.shared.appleLanguages[0] { switch PrefMgr.shared.appleLanguages[0] {
case "ja": case "ja":

View File

@ -48,7 +48,7 @@ struct suiPrefPaneExperience: View {
@State private var selAlwaysShowTooltipTextsHorizontally = UserDefaults.standard.bool( @State private var selAlwaysShowTooltipTextsHorizontally = UserDefaults.standard.bool(
forKey: UserDef.kAlwaysShowTooltipTextsHorizontally.rawValue) forKey: UserDef.kAlwaysShowTooltipTextsHorizontally.rawValue)
private let contentMaxHeight: Double = 432 private let contentMaxHeight: Double = 440
private let contentWidth: Double = { private let contentWidth: Double = {
switch PrefMgr.shared.appleLanguages[0] { switch PrefMgr.shared.appleLanguages[0] {
case "ja": case "ja":

View File

@ -39,7 +39,7 @@ struct suiPrefPaneGeneral: View {
forKey: UserDef.kCheckUpdateAutomatically.rawValue) forKey: UserDef.kCheckUpdateAutomatically.rawValue)
@State private var selEnableDebugMode = UserDefaults.standard.bool(forKey: UserDef.kIsDebugModeEnabled.rawValue) @State private var selEnableDebugMode = UserDefaults.standard.bool(forKey: UserDef.kIsDebugModeEnabled.rawValue)
private let contentMaxHeight: Double = 432 private let contentMaxHeight: Double = 440
private let contentWidth: Double = { private let contentWidth: Double = {
switch PrefMgr.shared.appleLanguages[0] { switch PrefMgr.shared.appleLanguages[0] {
case "ja": case "ja":
@ -60,7 +60,7 @@ struct suiPrefPaneGeneral: View {
Picker( Picker(
"", "",
selection: $selCandidateUIFontSize.onChange { selection: $selCandidateUIFontSize.onChange {
PrefMgr.shared.candidateListTextSize = CGFloat(selCandidateUIFontSize) PrefMgr.shared.candidateListTextSize = Double(selCandidateUIFontSize)
} }
) { ) {
Group { Group {

View File

@ -34,7 +34,7 @@ struct suiPrefPaneKeyboard: View {
@State private var selUsingHotKeyCurrencyNumerals = UserDefaults.standard.bool( @State private var selUsingHotKeyCurrencyNumerals = UserDefaults.standard.bool(
forKey: UserDef.kUsingHotKeyCurrencyNumerals.rawValue) forKey: UserDef.kUsingHotKeyCurrencyNumerals.rawValue)
private let contentMaxHeight: Double = 432 private let contentMaxHeight: Double = 440
private let contentWidth: Double = { private let contentWidth: Double = {
switch PrefMgr.shared.appleLanguages[0] { switch PrefMgr.shared.appleLanguages[0] {
case "ja": case "ja":

View File

@ -53,7 +53,7 @@ extension ctlClientListMgr {
alert.addButton(withTitle: NSLocalizedString("Just Select", comment: "") + "") alert.addButton(withTitle: NSLocalizedString("Just Select", comment: "") + "")
alert.addButton(withTitle: NSLocalizedString("Cancel", comment: "")) alert.addButton(withTitle: NSLocalizedString("Cancel", comment: ""))
let maxFloat = CGFloat(Float.greatestFiniteMagnitude) let maxFloat = Double(Float.greatestFiniteMagnitude)
let scrollview = NSScrollView(frame: NSRect(x: 0, y: 0, width: 370, height: 380)) let scrollview = NSScrollView(frame: NSRect(x: 0, y: 0, width: 370, height: 380))
let contentSize = scrollview.contentSize let contentSize = scrollview.contentSize
scrollview.borderType = .noBorder scrollview.borderType = .noBorder

View File

@ -12,7 +12,7 @@ import BookmarkManager
import IMKUtils import IMKUtils
import Shared import Shared
private let kWindowTitleHeight: CGFloat = 78 private let kWindowTitleHeight: Double = 78
extension NSToolbarItem.Identifier { extension NSToolbarItem.Identifier {
fileprivate static let ofGeneral = NSToolbarItem.Identifier(rawValue: "tabGeneral") fileprivate static let ofGeneral = NSToolbarItem.Identifier(rawValue: "tabGeneral")

View File

@ -1,76 +0,0 @@
// (c) 2011 and onwards The OpenVanilla Project (MIT License).
// All possible vChewing-specific modifications are of:
// (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 InputMethodKit
import Shared
extension ctlInputMethod {
/// handle() IMK
/// handle()
/// - Parameter event: IMK
/// - Returns: `true` IMK`false`
func commonEventHandler(_ event: NSEvent) -> Bool {
//
// KeyHandler
if !event.charCode.isPrintable { return false }
/// 調
/// result bool IMK
/// keyHandler.handleCandidate()
let result = keyHandler.handle(input: event, state: state) { newState in
self.handle(state: newState)
} errorCallback: { errorString in
vCLog(errorString)
IMEApp.buzz()
}
return result
}
/// handle() IMK
/// handle()
/// - Parameter event: IMK
/// - Returns: `true` IMK`false`
func imkCandidatesEventHandler(event eventToDeal: NSEvent) -> Bool? {
// IMK IMK
// interpretKeyEvents()
// - super.interpretKeyEvents()
// - delegate ctlInputMethod KeyHandler
if let imkCandidates = ctlInputMethod.ctlCandidateCurrent as? ctlCandidateIMK, imkCandidates.visible {
let event: NSEvent = ctlCandidateIMK.replaceNumPadKeyCodes(target: eventToDeal) ?? eventToDeal
// Shift+Enter delegate keyHandler
// Shift Flags
if event.isShiftHold, event.isEnter {
guard let newEvent = event.reinitiate(modifierFlags: []) else {
NSSound.beep()
return true
}
imkCandidates.interpretKeyEvents([newEvent])
return true
}
//
if let newChar = ctlCandidateIMK.defaultIMKSelectionKey[event.keyCode],
event.isShiftHold, isAssociatedPhrasesState,
let newEvent = event.reinitiate(modifierFlags: [], characters: newChar)
{
if #available(macOS 10.14, *) {
imkCandidates.handleKeyboardEvent(newEvent)
} else {
imkCandidates.superInterpretKeyEvents([newEvent])
}
}
imkCandidates.interpretKeyEvents([event])
return true
}
return nil
}
}

View File

@ -38,6 +38,7 @@
"Force KangXi Writing" = "Force KangXi Writing"; "Force KangXi Writing" = "Force KangXi Writing";
"NotificationSwitchON" = "✔ ON"; "NotificationSwitchON" = "✔ ON";
"NotificationSwitchOFF" = "✘ OFF"; "NotificationSwitchOFF" = "✘ OFF";
"NotificationSwitchShift" = "↺ Switched";
"Edit User Phrases…" = "Edit User Phrases…"; "Edit User Phrases…" = "Edit User Phrases…";
"Reload User Phrases" = "Reload User Phrases"; "Reload User Phrases" = "Reload User Phrases";
"Unable to create the user phrase file." = "Unable to create the user phrase file."; "Unable to create the user phrase file." = "Unable to create the user phrase file.";

View File

@ -92,13 +92,13 @@
<key>InputMethodConnectionName</key> <key>InputMethodConnectionName</key>
<string>org_atelierInmu_inputmethod_vChewing_Connection</string> <string>org_atelierInmu_inputmethod_vChewing_Connection</string>
<key>InputMethodServerControllerClass</key> <key>InputMethodServerControllerClass</key>
<string>ctlInputMethod</string> <string>SessionCtl</string>
<key>InputMethodServerDelegateClass</key> <key>InputMethodServerDelegateClass</key>
<string>ctlInputMethod</string> <string>SessionCtl</string>
<key>InputMethodServerPreferencesWindowControllerClass</key> <key>InputMethodServerPreferencesWindowControllerClass</key>
<string>ctlPrefWindow</string> <string>ctlPrefWindow</string>
<key>InputMethodSessionController</key> <key>InputMethodSessionController</key>
<string>ctlInputMethod</string> <string>SessionCtl</string>
<key>LSApplicationCategoryType</key> <key>LSApplicationCategoryType</key>
<string>public.app-category.utilities</string> <string>public.app-category.utilities</string>
<key>LSHasLocalizedDisplayName</key> <key>LSHasLocalizedDisplayName</key>

Binary file not shown.

Before

Width:  |  Height:  |  Size: 12 KiB

After

Width:  |  Height:  |  Size: 32 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 39 KiB

After

Width:  |  Height:  |  Size: 127 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 82 KiB

After

Width:  |  Height:  |  Size: 135 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 11 KiB

After

Width:  |  Height:  |  Size: 5.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 17 KiB

After

Width:  |  Height:  |  Size: 9.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.8 KiB

After

Width:  |  Height:  |  Size: 2.7 KiB

View File

@ -0,0 +1,74 @@
{
"images" : [
{
"filename" : "icon_1024.png",
"idiom" : "ios-marketing",
"scale" : "1x",
"size" : "1024x1024"
},
{
"filename" : "icon_16.png",
"idiom" : "mac",
"scale" : "1x",
"size" : "16x16"
},
{
"filename" : "icon_32.png",
"idiom" : "mac",
"scale" : "2x",
"size" : "16x16"
},
{
"filename" : "icon_32.png",
"idiom" : "mac",
"scale" : "1x",
"size" : "32x32"
},
{
"filename" : "icon_64.png",
"idiom" : "mac",
"scale" : "2x",
"size" : "32x32"
},
{
"filename" : "icon_128.png",
"idiom" : "mac",
"scale" : "1x",
"size" : "128x128"
},
{
"filename" : "icon_256.png",
"idiom" : "mac",
"scale" : "2x",
"size" : "128x128"
},
{
"filename" : "icon_256.png",
"idiom" : "mac",
"scale" : "1x",
"size" : "256x256"
},
{
"filename" : "icon_512.png",
"idiom" : "mac",
"scale" : "2x",
"size" : "256x256"
},
{
"filename" : "icon_512.png",
"idiom" : "mac",
"scale" : "1x",
"size" : "512x512"
},
{
"filename" : "icon_1024.png",
"idiom" : "mac",
"scale" : "2x",
"size" : "512x512"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 74 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 957 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 30 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 161 KiB

After

Width:  |  Height:  |  Size: 81 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 11 KiB

After

Width:  |  Height:  |  Size: 5.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 24 KiB

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.2 KiB

After

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 63 KiB

After

Width:  |  Height:  |  Size: 29 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.8 KiB

After

Width:  |  Height:  |  Size: 2.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.6 KiB

After

Width:  |  Height:  |  Size: 809 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.2 KiB

After

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

Binary file not shown.

Before

Width:  |  Height:  |  Size: 402 KiB

View File

@ -1,31 +1,21 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?> <?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"> <!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg width="100%" height="100%" viewBox="0 0 16 16" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xml:space="preserve" xmlns:serif="http://www.serif.com/" style="fill-rule:evenodd;clip-rule:evenodd;stroke-linejoin:round;stroke-miterlimit:2;"> <svg width="100%" height="100%" viewBox="0 0 16 16" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xml:space="preserve" xmlns:serif="http://www.serif.com/" style="fill-rule:evenodd;clip-rule:evenodd;stroke-linejoin:round;stroke-miterlimit:2;">
<g transform="matrix(1,0,0,1,0.176229,0.510845)"> <g id="CHS">
<g id="v" transform="matrix(-0.0111111,-1.36072e-18,1.36072e-18,-0.0111111,13.8235,12.9891)"> <path d="M16,3.774C16,1.691 14.309,0 12.226,0L3.774,0C1.691,0 0,1.691 0,3.774L0,12.226C0,14.309 1.691,16 3.774,16L12.226,16C14.309,16 16,14.309 16,12.226L16,3.774Z" style="fill:white;"/>
<g id="Shadow" transform="matrix(-1.02102,-1.25039e-16,1.28682e-16,-1.05077,1169.98,1160.72)"> <path d="M16,8.465L6.413,8.465L5,16L12.226,16C14.309,16 16,14.309 16,12.226L16,8.465Z" style="fill:rgb(64,134,191);"/>
<path d="M1322.21,34L452.612,34C202.809,34 0,231.067 0,473.799L0,1318.78L1322.21,1318.78L1322.21,34Z" style="fill-opacity:0.63;"/> <path d="M16,3.774C16,1.691 14.309,0 12.226,0L8,0L6.413,8.465L16,8.465L16,3.774Z" style="fill:rgb(83,191,64);"/>
<path d="M0,8.465L6.413,8.465L8,0L3.774,0C1.691,0 0,1.691 0,3.774L0,8.465Z" style="fill:rgb(255,200,0);"/>
<path d="M5,16L6.413,8.465L0,8.465L0,12.226C0,14.309 1.691,16 3.774,16L5,16Z" style="fill:rgb(255,81,0);"/>
</g> </g>
<g transform="matrix(-1.01166,-1.23893e-16,1.27502e-16,-1.04113,1259.98,1250.4)"> <g transform="matrix(0.750892,0,0,0.696534,-206.162,-625.152)">
<g id="Outline"> <g id="TextElement">
<path d="M1334.45,34L452.612,34C202.809,34 0,231.067 0,473.799L0,1330.67L1334.45,1330.67L1334.45,34Z" style="fill:rgb(11,46,99);"/> <g id="Text">
</g> <path d="M279.547,902.926C280.327,903.628 280.535,903.602 281.653,903.29C282.849,902.952 285.241,902.718 286.905,902.666C287.763,902.614 287.841,902.718 287.581,903.082C286.723,904.304 285.033,906.124 284.149,906.462C283.109,906.826 283.057,906.878 282.979,907.71C282.875,908.828 283.629,909.01 284.383,908.698C285.683,908.126 288.543,907.918 289.635,908.126C290.233,908.23 290.285,908.49 290.129,909.036C289.531,911.22 288.283,913.508 287.139,914.99C286.411,915.926 286.359,915.9 285.475,915.406C284.981,915.146 284.045,914.574 283.551,914.366C282.667,913.95 282.251,914.288 283.213,915.458C283.785,916.134 284.981,917.304 285.397,917.928C286.281,919.254 286.385,919.28 287.633,918.058C290.675,915.094 292.079,909.972 292.573,909.53C293.223,908.958 293.405,908.776 293.041,908.152C292.703,907.58 291.663,906.93 291.195,906.618C290.857,906.384 290.441,906.046 289.661,906.306C288.881,906.54 288.413,906.254 286.931,906.462C288.023,905.266 289.895,903.472 290.571,903.186C291.611,902.718 291.897,902.432 291.481,902.042C290.935,901.496 290.571,900.95 290.103,900.612C289.583,900.196 289.167,900.456 288.179,900.742C287.347,900.976 281.393,901.678 280.405,901.496C278.065,901.08 277.987,901.47 279.547,902.926Z" style="fill-rule:nonzero;"/>
</g>
<g id="Core" transform="matrix(-0.861782,-1.05538e-16,1.08613e-16,-0.886889,1169.98,1155.15)">
<path d="M1357.66,34L452.612,34C202.809,34 0,231.067 0,473.799L0,1353.23L1357.66,1353.23L1357.66,34Z" style="fill:url(#_Radial1);"/>
</g>
</g>
<g id="TextElement" transform="matrix(0.0115939,0,0,0.0115939,0.253417,-0.559324)">
<g id="TextShadow" transform="matrix(76.3556,0,0,67.9081,-21039.4,-60964.1)">
<path d="M279.547,902.926C280.327,903.628 280.535,903.602 281.653,903.29C282.849,902.952 285.241,902.718 286.905,902.666C287.763,902.614 287.841,902.718 287.581,903.082C286.723,904.304 285.033,906.124 284.149,906.462C283.109,906.826 283.057,906.878 282.979,907.71C282.875,908.828 283.629,909.01 284.383,908.698C285.683,908.126 288.543,907.918 289.635,908.126C290.233,908.23 290.285,908.49 290.129,909.036C289.531,911.22 288.283,913.508 287.139,914.99C286.411,915.926 286.359,915.9 285.475,915.406C284.981,915.146 284.045,914.574 283.551,914.366C282.667,913.95 282.251,914.288 283.213,915.458C283.785,916.134 284.981,917.304 285.397,917.928C286.281,919.254 286.385,919.28 287.633,918.058C290.675,915.094 292.079,909.972 292.573,909.53C293.223,908.958 293.405,908.776 293.041,908.152C292.703,907.58 291.663,906.93 291.195,906.618C290.857,906.384 290.441,906.046 289.661,906.306C288.881,906.54 288.413,906.254 286.931,906.462C288.023,905.266 289.895,903.472 290.571,903.186C291.611,902.718 291.897,902.432 291.481,902.042C290.935,901.496 290.571,900.95 290.103,900.612C289.583,900.196 289.167,900.456 288.179,900.742C287.347,900.976 281.393,901.678 280.405,901.496C278.065,901.08 277.987,901.47 279.547,902.926Z" style="fill-opacity:0.8;fill-rule:nonzero;"/>
</g>
<g id="Text" transform="matrix(64.7661,0,0,60.0776,-17811.9,-53913.5)">
<path d="M279.547,902.926C280.327,903.628 280.535,903.602 281.653,903.29C282.849,902.952 285.241,902.718 286.905,902.666C287.763,902.614 287.841,902.718 287.581,903.082C286.723,904.304 285.033,906.124 284.149,906.462C283.109,906.826 283.057,906.878 282.979,907.71C282.875,908.828 283.629,909.01 284.383,908.698C285.683,908.126 288.543,907.918 289.635,908.126C290.233,908.23 290.285,908.49 290.129,909.036C289.531,911.22 288.283,913.508 287.139,914.99C286.411,915.926 286.359,915.9 285.475,915.406C284.981,915.146 284.045,914.574 283.551,914.366C282.667,913.95 282.251,914.288 283.213,915.458C283.785,916.134 284.981,917.304 285.397,917.928C286.281,919.254 286.385,919.28 287.633,918.058C290.675,915.094 292.079,909.972 292.573,909.53C293.223,908.958 293.405,908.776 293.041,908.152C292.703,907.58 291.663,906.93 291.195,906.618C290.857,906.384 290.441,906.046 289.661,906.306C288.881,906.54 288.413,906.254 286.931,906.462C288.023,905.266 289.895,903.472 290.571,903.186C291.611,902.718 291.897,902.432 291.481,902.042C290.935,901.496 290.571,900.95 290.103,900.612C289.583,900.196 289.167,900.456 288.179,900.742C287.347,900.976 281.393,901.678 280.405,901.496C278.065,901.08 277.987,901.47 279.547,902.926Z" style="fill:rgb(16,42,103);fill-rule:nonzero;"/>
<path d="M284.778,904.241C284.724,904.294 284.67,904.346 284.617,904.396C284.276,904.716 283.97,904.996 283.728,905.099C282.618,905.49 282.228,905.851 281.992,906.261C281.825,906.553 281.713,906.932 281.654,907.566C281.654,907.566 281.654,907.566 281.654,907.567C281.556,908.615 281.894,909.276 282.311,909.689C282.896,910.267 283.87,910.448 284.86,910.038C284.869,910.035 284.878,910.031 284.886,910.027C285.757,909.644 287.442,909.454 288.588,909.474C287.986,911.198 287.016,912.905 286.117,914.07L286.074,914.124L286.059,914.116C285.548,913.847 284.584,913.265 284.059,913.039C283.4,912.733 282.843,912.726 282.507,912.818C282.043,912.945 281.729,913.235 281.532,913.608C281.373,913.91 281.272,914.304 281.364,914.809C281.428,915.161 281.649,915.72 282.216,916.41C282.221,916.415 282.225,916.42 282.229,916.426C282.773,917.069 283.92,918.172 284.316,918.766C284.662,919.286 284.931,919.641 285.162,919.857C285.543,920.213 285.918,920.356 286.296,920.381C286.638,920.404 287.015,920.329 287.445,920.055C287.718,919.881 288.063,919.577 288.527,919.122C291.374,916.347 292.893,911.795 293.545,910.525C294.21,909.912 294.469,909.418 294.535,908.97C294.599,908.546 294.551,908.044 294.168,907.388C294.167,907.385 294.166,907.383 294.164,907.381C293.743,906.668 292.496,905.798 291.905,905.404C291.562,905.166 291.169,904.89 290.628,904.796C290.799,904.665 290.946,904.57 291.058,904.522C291.066,904.519 291.075,904.515 291.084,904.511C291.842,904.17 292.303,903.842 292.532,903.581C292.868,903.197 292.985,902.795 292.996,902.416C293.008,901.978 292.881,901.462 292.375,900.978C291.787,900.388 291.376,899.813 290.872,899.44C290.291,898.984 289.768,898.886 289.113,898.995C288.786,899.049 288.391,899.194 287.839,899.354C287.054,899.572 281.545,900.25 280.629,900.081C280.627,900.08 280.624,900.08 280.622,900.079C279.567,899.892 278.866,899.878 278.491,899.959C277.855,900.096 277.527,900.466 277.349,900.813C277.141,901.216 277.043,901.752 277.342,902.409C277.502,902.763 277.932,903.318 278.675,904.011C278.681,904.017 278.687,904.023 278.694,904.028C279.185,904.47 279.55,904.697 279.903,904.816C280.419,904.992 280.955,904.968 281.987,904.68C281.988,904.679 281.989,904.679 281.991,904.679C282.653,904.492 283.705,904.342 284.778,904.241ZM279.547,902.926C280.327,903.628 280.535,903.602 281.653,903.29C282.849,902.952 285.241,902.718 286.905,902.666C287.763,902.614 287.841,902.718 287.581,903.082C286.723,904.304 285.033,906.124 284.149,906.462C283.109,906.826 283.057,906.878 282.979,907.71C282.875,908.828 283.629,909.01 284.383,908.698C285.683,908.126 288.543,907.918 289.635,908.126C290.233,908.23 290.285,908.49 290.129,909.036C289.531,911.22 288.283,913.508 287.139,914.99C286.411,915.926 286.359,915.9 285.475,915.406C284.981,915.146 284.045,914.574 283.551,914.366C282.667,913.95 282.251,914.288 283.213,915.458C283.785,916.134 284.981,917.304 285.397,917.928C286.281,919.254 286.385,919.28 287.633,918.058C290.675,915.094 292.079,909.972 292.573,909.53C293.223,908.958 293.405,908.776 293.041,908.152C292.703,907.58 291.663,906.93 291.195,906.618C290.857,906.384 290.441,906.046 289.661,906.306C288.881,906.54 288.413,906.254 286.931,906.462C288.023,905.266 289.895,903.472 290.571,903.186C291.611,902.718 291.897,902.432 291.481,902.042C290.935,901.496 290.571,900.95 290.103,900.612C289.583,900.196 289.167,900.456 288.179,900.742C287.347,900.976 281.393,901.678 280.405,901.496C278.065,901.08 277.987,901.47 279.547,902.926Z" style="fill:white;"/> <path d="M284.778,904.241C284.724,904.294 284.67,904.346 284.617,904.396C284.276,904.716 283.97,904.996 283.728,905.099C282.618,905.49 282.228,905.851 281.992,906.261C281.825,906.553 281.713,906.932 281.654,907.566C281.654,907.566 281.654,907.566 281.654,907.567C281.556,908.615 281.894,909.276 282.311,909.689C282.896,910.267 283.87,910.448 284.86,910.038C284.869,910.035 284.878,910.031 284.886,910.027C285.757,909.644 287.442,909.454 288.588,909.474C287.986,911.198 287.016,912.905 286.117,914.07L286.074,914.124L286.059,914.116C285.548,913.847 284.584,913.265 284.059,913.039C283.4,912.733 282.843,912.726 282.507,912.818C282.043,912.945 281.729,913.235 281.532,913.608C281.373,913.91 281.272,914.304 281.364,914.809C281.428,915.161 281.649,915.72 282.216,916.41C282.221,916.415 282.225,916.42 282.229,916.426C282.773,917.069 283.92,918.172 284.316,918.766C284.662,919.286 284.931,919.641 285.162,919.857C285.543,920.213 285.918,920.356 286.296,920.381C286.638,920.404 287.015,920.329 287.445,920.055C287.718,919.881 288.063,919.577 288.527,919.122C291.374,916.347 292.893,911.795 293.545,910.525C294.21,909.912 294.469,909.418 294.535,908.97C294.599,908.546 294.551,908.044 294.168,907.388C294.167,907.385 294.166,907.383 294.164,907.381C293.743,906.668 292.496,905.798 291.905,905.404C291.562,905.166 291.169,904.89 290.628,904.796C290.799,904.665 290.946,904.57 291.058,904.522C291.066,904.519 291.075,904.515 291.084,904.511C291.842,904.17 292.303,903.842 292.532,903.581C292.868,903.197 292.985,902.795 292.996,902.416C293.008,901.978 292.881,901.462 292.375,900.978C291.787,900.388 291.376,899.813 290.872,899.44C290.291,898.984 289.768,898.886 289.113,898.995C288.786,899.049 288.391,899.194 287.839,899.354C287.054,899.572 281.545,900.25 280.629,900.081C280.627,900.08 280.624,900.08 280.622,900.079C279.567,899.892 278.866,899.878 278.491,899.959C277.855,900.096 277.527,900.466 277.349,900.813C277.141,901.216 277.043,901.752 277.342,902.409C277.502,902.763 277.932,903.318 278.675,904.011C278.681,904.017 278.687,904.023 278.694,904.028C279.185,904.47 279.55,904.697 279.903,904.816C280.419,904.992 280.955,904.968 281.987,904.68C281.988,904.679 281.989,904.679 281.991,904.679C282.653,904.492 283.705,904.342 284.778,904.241ZM279.547,902.926C280.327,903.628 280.535,903.602 281.653,903.29C282.849,902.952 285.241,902.718 286.905,902.666C287.763,902.614 287.841,902.718 287.581,903.082C286.723,904.304 285.033,906.124 284.149,906.462C283.109,906.826 283.057,906.878 282.979,907.71C282.875,908.828 283.629,909.01 284.383,908.698C285.683,908.126 288.543,907.918 289.635,908.126C290.233,908.23 290.285,908.49 290.129,909.036C289.531,911.22 288.283,913.508 287.139,914.99C286.411,915.926 286.359,915.9 285.475,915.406C284.981,915.146 284.045,914.574 283.551,914.366C282.667,913.95 282.251,914.288 283.213,915.458C283.785,916.134 284.981,917.304 285.397,917.928C286.281,919.254 286.385,919.28 287.633,918.058C290.675,915.094 292.079,909.972 292.573,909.53C293.223,908.958 293.405,908.776 293.041,908.152C292.703,907.58 291.663,906.93 291.195,906.618C290.857,906.384 290.441,906.046 289.661,906.306C288.881,906.54 288.413,906.254 286.931,906.462C288.023,905.266 289.895,903.472 290.571,903.186C291.611,902.718 291.897,902.432 291.481,902.042C290.935,901.496 290.571,900.95 290.103,900.612C289.583,900.196 289.167,900.456 288.179,900.742C287.347,900.976 281.393,901.678 280.405,901.496C278.065,901.08 277.987,901.47 279.547,902.926Z" style="fill:white;"/>
<path d="M279.547,902.926C280.327,903.628 280.535,903.602 281.653,903.29C282.849,902.952 285.241,902.718 286.905,902.666C287.763,902.614 287.841,902.718 287.581,903.082C286.723,904.304 285.033,906.124 284.149,906.462C283.109,906.826 283.057,906.878 282.979,907.71C282.875,908.828 283.629,909.01 284.383,908.698C285.683,908.126 288.543,907.918 289.635,908.126C290.233,908.23 290.285,908.49 290.129,909.036C289.531,911.22 288.283,913.508 287.139,914.99C286.411,915.926 286.359,915.9 285.475,915.406C284.981,915.146 284.045,914.574 283.551,914.366C282.667,913.95 282.251,914.288 283.213,915.458C283.785,916.134 284.981,917.304 285.397,917.928C286.281,919.254 286.385,919.28 287.633,918.058C290.675,915.094 292.079,909.972 292.573,909.53C293.223,908.958 293.405,908.776 293.041,908.152C292.703,907.58 291.663,906.93 291.195,906.618C290.857,906.384 290.441,906.046 289.661,906.306C288.881,906.54 288.413,906.254 286.931,906.462C288.023,905.266 289.895,903.472 290.571,903.186C291.611,902.718 291.897,902.432 291.481,902.042C290.935,901.496 290.571,900.95 290.103,900.612C289.583,900.196 289.167,900.456 288.179,900.742C287.347,900.976 281.393,901.678 280.405,901.496C278.065,901.08 277.987,901.47 279.547,902.926Z" style="fill-rule:nonzero;"/>
<path d="M287.346,902.94C286.511,904.121 284.91,905.864 284.062,906.19C283.738,906.304 283.507,906.389 283.338,906.475C283.119,906.588 282.988,906.709 282.898,906.865C282.795,907.046 282.751,907.288 282.714,907.681C282.714,907.681 282.714,907.681 282.714,907.681C282.661,908.249 282.805,908.619 283.031,908.842C283.362,909.169 283.919,909.198 284.478,908.966C284.48,908.965 284.482,908.965 284.484,908.964C285.747,908.408 288.527,908.207 289.589,908.409C289.59,908.409 289.591,908.409 289.593,908.409C289.689,908.426 289.768,908.447 289.831,908.474C289.876,908.494 289.911,908.511 289.927,908.544C289.941,908.575 289.939,908.612 289.936,908.655C289.93,908.74 289.907,908.838 289.874,908.951C289.874,908.953 289.874,908.954 289.874,908.955C289.286,911.101 288.059,913.349 286.935,914.806C286.762,915.028 286.63,915.194 286.515,915.309C286.438,915.386 286.378,915.438 286.311,915.453C286.247,915.468 286.183,915.446 286.1,915.412C285.967,915.358 285.807,915.268 285.598,915.151C285.596,915.15 285.594,915.149 285.592,915.148C285.094,914.886 284.153,914.312 283.653,914.101C283.338,913.953 283.072,913.896 282.886,913.911C282.675,913.929 282.535,914.031 282.458,914.175C282.392,914.301 282.367,914.483 282.443,914.721C282.515,914.947 282.693,915.258 283.014,915.648C283.015,915.649 283.015,915.65 283.016,915.652C283.583,916.321 284.769,917.478 285.181,918.096C285.462,918.518 285.672,918.813 285.859,918.989C286.03,919.148 286.193,919.224 286.362,919.235C286.524,919.246 286.699,919.196 286.902,919.067C287.133,918.919 287.419,918.655 287.812,918.271C289.971,916.167 291.321,912.995 292.106,911.125C292.302,910.658 292.462,910.274 292.59,910.014C292.654,909.884 292.699,909.79 292.743,909.751C292.994,909.53 293.178,909.361 293.296,909.207C293.402,909.066 293.462,908.93 293.484,908.788C293.516,908.574 293.459,908.33 293.266,907.999C293.266,907.999 293.266,907.998 293.266,907.998C292.911,907.398 291.83,906.703 291.337,906.375C290.952,906.108 290.475,905.736 289.588,906.03C289.228,906.138 288.939,906.122 288.569,906.107C288.312,906.096 288.018,906.085 287.647,906.104C288.707,905 290.107,903.691 290.668,903.453C290.67,903.453 290.672,903.452 290.674,903.451C291.118,903.251 291.432,903.079 291.623,902.921C291.84,902.741 291.926,902.554 291.931,902.381C291.935,902.209 291.861,902.02 291.661,901.83C291.106,901.275 290.732,900.723 290.257,900.377C289.933,900.12 289.641,900.069 289.276,900.13C288.976,900.18 288.617,900.318 288.111,900.464C287.288,900.695 281.423,901.392 280.45,901.213C280.449,901.213 280.449,901.213 280.448,901.213C279.582,901.059 279.009,901.018 278.7,901.085C278.473,901.134 278.344,901.246 278.281,901.37C278.211,901.505 278.198,901.684 278.299,901.904C278.425,902.182 278.787,902.597 279.373,903.143C279.374,903.144 279.375,903.145 279.376,903.146C279.724,903.459 279.974,903.636 280.223,903.721C280.595,903.848 280.977,903.775 281.72,903.568C281.72,903.568 281.72,903.568 281.721,903.568C282.903,903.234 285.268,903.004 286.913,902.953L287.346,902.94ZM279.547,902.926C280.327,903.628 280.535,903.602 281.653,903.29C282.849,902.952 285.241,902.718 286.905,902.666C287.763,902.614 287.841,902.718 287.581,903.082C286.723,904.304 285.033,906.124 284.149,906.462C283.109,906.826 283.057,906.878 282.979,907.71C282.875,908.828 283.629,909.01 284.383,908.698C285.683,908.126 288.543,907.918 289.635,908.126C290.233,908.23 290.285,908.49 290.129,909.036C289.531,911.22 288.283,913.508 287.139,914.99C286.411,915.926 286.359,915.9 285.475,915.406C284.981,915.146 284.045,914.574 283.551,914.366C282.667,913.95 282.251,914.288 283.213,915.458C283.785,916.134 284.981,917.304 285.397,917.928C286.281,919.254 286.385,919.28 287.633,918.058C290.675,915.094 292.079,909.972 292.573,909.53C293.223,908.958 293.405,908.776 293.041,908.152C292.703,907.58 291.663,906.93 291.195,906.618C290.857,906.384 290.441,906.046 289.661,906.306C288.881,906.54 288.413,906.254 286.931,906.462C288.023,905.266 289.895,903.472 290.571,903.186C291.611,902.718 291.897,902.432 291.481,902.042C290.935,901.496 290.571,900.95 290.103,900.612C289.583,900.196 289.167,900.456 288.179,900.742C287.347,900.976 281.393,901.678 280.405,901.496C278.065,901.08 277.987,901.47 279.547,902.926Z"/>
</g> </g>
</g> </g>
</g> </g>
<defs>
<radialGradient id="_Radial1" cx="0" cy="0" r="1" gradientUnits="userSpaceOnUse" gradientTransform="matrix(-1087.57,-3794.91,3905.47,-1056.78,1725.88,3633.33)"><stop offset="0" style="stop-color:rgb(218,240,255);stop-opacity:1"/><stop offset="0.28" style="stop-color:rgb(200,225,246);stop-opacity:1"/><stop offset="0.51" style="stop-color:rgb(193,219,243);stop-opacity:1"/><stop offset="0.73" style="stop-color:rgb(127,167,220);stop-opacity:1"/><stop offset="0.87" style="stop-color:rgb(14,87,170);stop-opacity:1"/><stop offset="1" style="stop-color:rgb(9,53,104);stop-opacity:1"/></radialGradient>
</defs>
</svg> </svg>

Before

Width:  |  Height:  |  Size: 8.3 KiB

After

Width:  |  Height:  |  Size: 11 KiB

View File

@ -0,0 +1,21 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg width="100%" height="100%" viewBox="0 0 16 16" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xml:space="preserve" xmlns:serif="http://www.serif.com/" style="fill-rule:evenodd;clip-rule:evenodd;stroke-linejoin:round;stroke-miterlimit:2;">
<g id="CHT">
<path d="M16,3.774C16,1.691 14.309,0 12.226,0L3.774,0C1.691,0 0,1.691 0,3.774L0,12.226C0,14.309 1.691,16 3.774,16L12.226,16C14.309,16 16,14.309 16,12.226L16,3.774Z" style="fill:white;"/>
<path d="M16,8.465L6.413,8.465L5,16L12.226,16C14.309,16 16,14.309 16,12.226L16,8.465Z" style="fill:rgb(255,81,0);"/>
<path d="M16,3.774C16,1.691 14.309,0 12.226,0L8,0L6.413,8.465L16,8.465L16,3.774Z" style="fill:rgb(255,200,0);"/>
<path d="M0,8.465L6.413,8.465L8,0L3.774,0C1.691,0 0,1.691 0,3.774L0,8.465Z" style="fill:rgb(83,191,64);"/>
<path d="M5,16L6.413,8.465L0,8.465L0,12.226C0,14.309 1.691,16 3.774,16L5,16Z" style="fill:rgb(64,134,191);"/>
</g>
<g transform="matrix(0.750892,0,0,0.696534,-206.162,-625.152)">
<g id="TextElement">
<g id="Text">
<path d="M279.547,902.926C280.327,903.628 280.535,903.602 281.653,903.29C282.849,902.952 285.241,902.718 286.905,902.666C287.763,902.614 287.841,902.718 287.581,903.082C286.723,904.304 285.033,906.124 284.149,906.462C283.109,906.826 283.057,906.878 282.979,907.71C282.875,908.828 283.629,909.01 284.383,908.698C285.683,908.126 288.543,907.918 289.635,908.126C290.233,908.23 290.285,908.49 290.129,909.036C289.531,911.22 288.283,913.508 287.139,914.99C286.411,915.926 286.359,915.9 285.475,915.406C284.981,915.146 284.045,914.574 283.551,914.366C282.667,913.95 282.251,914.288 283.213,915.458C283.785,916.134 284.981,917.304 285.397,917.928C286.281,919.254 286.385,919.28 287.633,918.058C290.675,915.094 292.079,909.972 292.573,909.53C293.223,908.958 293.405,908.776 293.041,908.152C292.703,907.58 291.663,906.93 291.195,906.618C290.857,906.384 290.441,906.046 289.661,906.306C288.881,906.54 288.413,906.254 286.931,906.462C288.023,905.266 289.895,903.472 290.571,903.186C291.611,902.718 291.897,902.432 291.481,902.042C290.935,901.496 290.571,900.95 290.103,900.612C289.583,900.196 289.167,900.456 288.179,900.742C287.347,900.976 281.393,901.678 280.405,901.496C278.065,901.08 277.987,901.47 279.547,902.926Z" style="fill-rule:nonzero;"/>
<path d="M284.778,904.241C284.724,904.294 284.67,904.346 284.617,904.396C284.276,904.716 283.97,904.996 283.728,905.099C282.618,905.49 282.228,905.851 281.992,906.261C281.825,906.553 281.713,906.932 281.654,907.566C281.654,907.566 281.654,907.566 281.654,907.567C281.556,908.615 281.894,909.276 282.311,909.689C282.896,910.267 283.87,910.448 284.86,910.038C284.869,910.035 284.878,910.031 284.886,910.027C285.757,909.644 287.442,909.454 288.588,909.474C287.986,911.198 287.016,912.905 286.117,914.07L286.074,914.124L286.059,914.116C285.548,913.847 284.584,913.265 284.059,913.039C283.4,912.733 282.843,912.726 282.507,912.818C282.043,912.945 281.729,913.235 281.532,913.608C281.373,913.91 281.272,914.304 281.364,914.809C281.428,915.161 281.649,915.72 282.216,916.41C282.221,916.415 282.225,916.42 282.229,916.426C282.773,917.069 283.92,918.172 284.316,918.766C284.662,919.286 284.931,919.641 285.162,919.857C285.543,920.213 285.918,920.356 286.296,920.381C286.638,920.404 287.015,920.329 287.445,920.055C287.718,919.881 288.063,919.577 288.527,919.122C291.374,916.347 292.893,911.795 293.545,910.525C294.21,909.912 294.469,909.418 294.535,908.97C294.599,908.546 294.551,908.044 294.168,907.388C294.167,907.385 294.166,907.383 294.164,907.381C293.743,906.668 292.496,905.798 291.905,905.404C291.562,905.166 291.169,904.89 290.628,904.796C290.799,904.665 290.946,904.57 291.058,904.522C291.066,904.519 291.075,904.515 291.084,904.511C291.842,904.17 292.303,903.842 292.532,903.581C292.868,903.197 292.985,902.795 292.996,902.416C293.008,901.978 292.881,901.462 292.375,900.978C291.787,900.388 291.376,899.813 290.872,899.44C290.291,898.984 289.768,898.886 289.113,898.995C288.786,899.049 288.391,899.194 287.839,899.354C287.054,899.572 281.545,900.25 280.629,900.081C280.627,900.08 280.624,900.08 280.622,900.079C279.567,899.892 278.866,899.878 278.491,899.959C277.855,900.096 277.527,900.466 277.349,900.813C277.141,901.216 277.043,901.752 277.342,902.409C277.502,902.763 277.932,903.318 278.675,904.011C278.681,904.017 278.687,904.023 278.694,904.028C279.185,904.47 279.55,904.697 279.903,904.816C280.419,904.992 280.955,904.968 281.987,904.68C281.988,904.679 281.989,904.679 281.991,904.679C282.653,904.492 283.705,904.342 284.778,904.241ZM279.547,902.926C280.327,903.628 280.535,903.602 281.653,903.29C282.849,902.952 285.241,902.718 286.905,902.666C287.763,902.614 287.841,902.718 287.581,903.082C286.723,904.304 285.033,906.124 284.149,906.462C283.109,906.826 283.057,906.878 282.979,907.71C282.875,908.828 283.629,909.01 284.383,908.698C285.683,908.126 288.543,907.918 289.635,908.126C290.233,908.23 290.285,908.49 290.129,909.036C289.531,911.22 288.283,913.508 287.139,914.99C286.411,915.926 286.359,915.9 285.475,915.406C284.981,915.146 284.045,914.574 283.551,914.366C282.667,913.95 282.251,914.288 283.213,915.458C283.785,916.134 284.981,917.304 285.397,917.928C286.281,919.254 286.385,919.28 287.633,918.058C290.675,915.094 292.079,909.972 292.573,909.53C293.223,908.958 293.405,908.776 293.041,908.152C292.703,907.58 291.663,906.93 291.195,906.618C290.857,906.384 290.441,906.046 289.661,906.306C288.881,906.54 288.413,906.254 286.931,906.462C288.023,905.266 289.895,903.472 290.571,903.186C291.611,902.718 291.897,902.432 291.481,902.042C290.935,901.496 290.571,900.95 290.103,900.612C289.583,900.196 289.167,900.456 288.179,900.742C287.347,900.976 281.393,901.678 280.405,901.496C278.065,901.08 277.987,901.47 279.547,902.926Z" style="fill:white;"/>
<path d="M279.547,902.926C280.327,903.628 280.535,903.602 281.653,903.29C282.849,902.952 285.241,902.718 286.905,902.666C287.763,902.614 287.841,902.718 287.581,903.082C286.723,904.304 285.033,906.124 284.149,906.462C283.109,906.826 283.057,906.878 282.979,907.71C282.875,908.828 283.629,909.01 284.383,908.698C285.683,908.126 288.543,907.918 289.635,908.126C290.233,908.23 290.285,908.49 290.129,909.036C289.531,911.22 288.283,913.508 287.139,914.99C286.411,915.926 286.359,915.9 285.475,915.406C284.981,915.146 284.045,914.574 283.551,914.366C282.667,913.95 282.251,914.288 283.213,915.458C283.785,916.134 284.981,917.304 285.397,917.928C286.281,919.254 286.385,919.28 287.633,918.058C290.675,915.094 292.079,909.972 292.573,909.53C293.223,908.958 293.405,908.776 293.041,908.152C292.703,907.58 291.663,906.93 291.195,906.618C290.857,906.384 290.441,906.046 289.661,906.306C288.881,906.54 288.413,906.254 286.931,906.462C288.023,905.266 289.895,903.472 290.571,903.186C291.611,902.718 291.897,902.432 291.481,902.042C290.935,901.496 290.571,900.95 290.103,900.612C289.583,900.196 289.167,900.456 288.179,900.742C287.347,900.976 281.393,901.678 280.405,901.496C278.065,901.08 277.987,901.47 279.547,902.926Z" style="fill-rule:nonzero;"/>
<path d="M287.346,902.94C286.511,904.121 284.91,905.864 284.062,906.19C283.738,906.304 283.507,906.389 283.338,906.475C283.119,906.588 282.988,906.709 282.898,906.865C282.795,907.046 282.751,907.288 282.714,907.681C282.714,907.681 282.714,907.681 282.714,907.681C282.661,908.249 282.805,908.619 283.031,908.842C283.362,909.169 283.919,909.198 284.478,908.966C284.48,908.965 284.482,908.965 284.484,908.964C285.747,908.408 288.527,908.207 289.589,908.409C289.59,908.409 289.591,908.409 289.593,908.409C289.689,908.426 289.768,908.447 289.831,908.474C289.876,908.494 289.911,908.511 289.927,908.544C289.941,908.575 289.939,908.612 289.936,908.655C289.93,908.74 289.907,908.838 289.874,908.951C289.874,908.953 289.874,908.954 289.874,908.955C289.286,911.101 288.059,913.349 286.935,914.806C286.762,915.028 286.63,915.194 286.515,915.309C286.438,915.386 286.378,915.438 286.311,915.453C286.247,915.468 286.183,915.446 286.1,915.412C285.967,915.358 285.807,915.268 285.598,915.151C285.596,915.15 285.594,915.149 285.592,915.148C285.094,914.886 284.153,914.312 283.653,914.101C283.338,913.953 283.072,913.896 282.886,913.911C282.675,913.929 282.535,914.031 282.458,914.175C282.392,914.301 282.367,914.483 282.443,914.721C282.515,914.947 282.693,915.258 283.014,915.648C283.015,915.649 283.015,915.65 283.016,915.652C283.583,916.321 284.769,917.478 285.181,918.096C285.462,918.518 285.672,918.813 285.859,918.989C286.03,919.148 286.193,919.224 286.362,919.235C286.524,919.246 286.699,919.196 286.902,919.067C287.133,918.919 287.419,918.655 287.812,918.271C289.971,916.167 291.321,912.995 292.106,911.125C292.302,910.658 292.462,910.274 292.59,910.014C292.654,909.884 292.699,909.79 292.743,909.751C292.994,909.53 293.178,909.361 293.296,909.207C293.402,909.066 293.462,908.93 293.484,908.788C293.516,908.574 293.459,908.33 293.266,907.999C293.266,907.999 293.266,907.998 293.266,907.998C292.911,907.398 291.83,906.703 291.337,906.375C290.952,906.108 290.475,905.736 289.588,906.03C289.228,906.138 288.939,906.122 288.569,906.107C288.312,906.096 288.018,906.085 287.647,906.104C288.707,905 290.107,903.691 290.668,903.453C290.67,903.453 290.672,903.452 290.674,903.451C291.118,903.251 291.432,903.079 291.623,902.921C291.84,902.741 291.926,902.554 291.931,902.381C291.935,902.209 291.861,902.02 291.661,901.83C291.106,901.275 290.732,900.723 290.257,900.377C289.933,900.12 289.641,900.069 289.276,900.13C288.976,900.18 288.617,900.318 288.111,900.464C287.288,900.695 281.423,901.392 280.45,901.213C280.449,901.213 280.449,901.213 280.448,901.213C279.582,901.059 279.009,901.018 278.7,901.085C278.473,901.134 278.344,901.246 278.281,901.37C278.211,901.505 278.198,901.684 278.299,901.904C278.425,902.182 278.787,902.597 279.373,903.143C279.374,903.144 279.375,903.145 279.376,903.146C279.724,903.459 279.974,903.636 280.223,903.721C280.595,903.848 280.977,903.775 281.72,903.568C281.72,903.568 281.72,903.568 281.721,903.568C282.903,903.234 285.268,903.004 286.913,902.953L287.346,902.94ZM279.547,902.926C280.327,903.628 280.535,903.602 281.653,903.29C282.849,902.952 285.241,902.718 286.905,902.666C287.763,902.614 287.841,902.718 287.581,903.082C286.723,904.304 285.033,906.124 284.149,906.462C283.109,906.826 283.057,906.878 282.979,907.71C282.875,908.828 283.629,909.01 284.383,908.698C285.683,908.126 288.543,907.918 289.635,908.126C290.233,908.23 290.285,908.49 290.129,909.036C289.531,911.22 288.283,913.508 287.139,914.99C286.411,915.926 286.359,915.9 285.475,915.406C284.981,915.146 284.045,914.574 283.551,914.366C282.667,913.95 282.251,914.288 283.213,915.458C283.785,916.134 284.981,917.304 285.397,917.928C286.281,919.254 286.385,919.28 287.633,918.058C290.675,915.094 292.079,909.972 292.573,909.53C293.223,908.958 293.405,908.776 293.041,908.152C292.703,907.58 291.663,906.93 291.195,906.618C290.857,906.384 290.441,906.046 289.661,906.306C288.881,906.54 288.413,906.254 286.931,906.462C288.023,905.266 289.895,903.472 290.571,903.186C291.611,902.718 291.897,902.432 291.481,902.042C290.935,901.496 290.571,900.95 290.103,900.612C289.583,900.196 289.167,900.456 288.179,900.742C287.347,900.976 281.393,901.678 280.405,901.496C278.065,901.08 277.987,901.47 279.547,902.926Z"/>
</g>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 19 KiB

View File

@ -0,0 +1,23 @@
<?xml version="1.0" encoding="UTF-8"?>
<!-- Generated by Pixelmator Pro 3.0 -->
<svg width="1024" height="1024" viewBox="0 0 1024 1024" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<g id="NewIMELogo-CHT-">
<g id="CHT">
<path id="-" fill="#ffffff" fill-rule="evenodd" stroke="none" d="M -122 1178.28125 L 1254 1178.28125 L 1254 -191 L -122 -191 Z"/>
<path id="path1" fill="#ff8346" fill-rule="evenodd" stroke="none" d="M 1024 536.989563 L 429 537 L 338 1024 L 1024 1024 Z"/>
<path id="path2" fill="#f9ce29" fill-rule="evenodd" stroke="none" d="M 1024 0 L 530 0 L 429 537 L 1024 537 Z"/>
<path id="path3" fill="#4ec03b" fill-rule="evenodd" stroke="none" d="M 0 537 L 429.517975 536.989624 L 530 0 C 530 0 -3e-06 0 -3e-06 0 Z"/>
<path id="path4" fill="#3d7db3" fill-rule="evenodd" stroke="none" d="M 338 1024 L 429.518005 536.989563 L 0 536.989563 L 0 1024 Z"/>
</g>
</g>
<g id="NewIMELogo-CHT--">
<g id="g1">
<g id="TextElement">
<g id="Text">
<path id="path5" fill="#002833" stroke="none" d="M 290.875397 291.867126 C 321.331543 317.292175 329.453491 316.350464 373.107788 305.049438 C 419.806641 292.80896 513.205505 284.333191 578.178711 282.449646 C 611.680603 280.566162 614.726379 284.333191 604.573914 297.515442 C 571.072021 341.77771 505.083557 407.697876 470.566437 419.938477 C 429.959076 433.122925 427.928589 435.00647 424.882843 465.142395 C 420.821869 505.635437 450.262756 512.227661 479.703644 500.926636 C 530.464661 480.208191 642.13678 472.676392 684.775818 480.208191 C 708.125244 483.97522 710.155701 493.3927 704.06427 513.169434 C 680.714844 592.271973 631.984314 675.143677 587.315918 728.821167 C 558.890259 762.724121 556.859802 761.78241 522.342712 743.88916 C 503.05307 734.47168 466.506683 713.753174 447.217041 706.221436 C 412.699921 691.153381 396.457214 703.396118 434.02005 745.772705 C 456.354248 770.25592 503.05307 812.634644 519.296997 835.234375 C 553.814087 883.263672 557.875061 884.205383 606.60437 839.943176 C 725.38324 732.588196 780.2052 547.07019 799.493652 531.062622 C 824.873535 510.344177 831.980225 503.751892 817.766846 481.149963 C 804.569885 460.433655 763.961304 436.889893 745.688049 425.588989 C 732.489929 417.11322 716.247192 404.87262 685.791016 414.290161 C 655.334961 422.763733 637.060547 412.406677 579.194031 419.938477 C 621.833069 376.620178 694.927063 311.641663 721.323364 301.282471 C 761.930786 284.333191 773.098511 273.973877 756.854614 259.847717 C 735.535645 240.070984 721.323364 220.296448 703.049011 208.053711 C 682.7453 192.985718 666.501404 202.403198 627.92334 212.76239 C 595.436707 221.238159 362.955353 246.663208 324.377258 240.070984 C 233.008865 225.005127 229.963135 239.129211 290.875397 291.867126 Z"/>
<path id="path6" fill="#ffffff" fill-rule="evenodd" stroke="none" d="M 495.127747 339.496216 C 493.018585 341.4151 490.910645 343.298584 488.840851 345.109131 C 475.525909 356.699707 463.577728 366.840088 454.128326 370.571716 C 410.787384 384.733337 395.558746 397.809509 386.344086 412.658691 C 379.823639 423.234558 375.45047 436.962891 373.145905 459.925232 C 373.145905 459.925232 373.145905 459.925232 373.145905 459.96283 C 369.319702 497.920166 382.517853 521.861816 398.799896 536.821472 C 421.641693 557.756592 459.672852 564.311279 498.328369 549.462158 C 498.679901 549.351563 499.031403 549.207886 499.343628 549.062012 C 533.353149 535.189941 599.146179 528.308105 643.894409 529.033203 C 620.387695 591.476135 582.512573 653.304382 547.4104 695.499634 L 545.731445 697.456055 L 545.145203 697.166504 C 525.192993 687.421753 487.552734 666.342957 467.052429 658.15686 C 441.320984 647.07251 419.571869 646.820435 406.452362 650.151917 C 388.335266 654.752319 376.07486 665.255371 368.383087 678.764771 C 362.173645 689.703247 358.230652 703.975342 361.823334 722.266479 C 364.322113 735.015503 372.9505 755.260864 395.090424 780.252686 C 395.285858 780.433899 395.441956 780.615173 395.598083 780.834045 C 416.839539 804.121338 461.625854 844.072754 477.088104 865.587036 C 490.59726 884.422058 501.101227 897.279297 510.120453 905.102966 C 524.99762 917.997803 539.639954 923.17749 554.39917 924.081604 C 567.753479 924.915039 582.474487 922.19812 599.26416 912.274353 C 609.923035 905.971741 623.394104 894.962524 641.51239 878.481934 C 752.676819 777.971191 811.98877 613.098755 837.447327 567.101135 C 863.412292 544.897095 873.525391 527.006104 876.102844 510.777466 C 878.601624 495.422119 876.727234 477.239258 861.772644 453.478882 C 861.733337 453.370544 861.694031 453.297546 861.616577 453.224609 C 845.178406 427.401733 796.487244 395.888489 773.410645 381.61853 C 760.01825 372.999084 744.672852 363.00238 723.548157 359.597961 C 730.225891 354.851624 735.96582 351.411804 740.338989 349.671997 C 740.651184 349.56366 741.002686 349.419983 741.354187 349.274048 C 770.951172 336.923035 788.951538 325.042847 797.893311 315.589966 C 811.012817 301.682556 815.580261 287.12085 816.010437 273.394714 C 816.478699 257.530884 811.520447 238.8396 791.762512 221.311096 C 768.802795 199.940491 752.755432 179.113708 733.076172 165.604248 C 710.389282 149.088257 689.968811 145.537903 664.393494 149.486145 C 651.625488 151.442627 636.201355 156.692993 614.647705 162.48938 C 583.996155 170.385925 368.890717 194.942139 333.123627 188.820801 C 333.046143 188.7854 332.928192 188.7854 332.850739 188.747864 C 291.655884 181.976501 264.284821 181.468079 249.64241 184.401611 C 224.809448 189.364624 212.002136 202.765747 205.051514 215.333435 C 196.929565 229.930542 193.103333 249.344727 204.778641 273.140503 C 211.026199 285.962463 227.815857 306.064148 256.826599 331.164185 C 257.06134 331.383057 257.296082 331.599731 257.568939 331.780945 C 276.740631 347.788513 290.992157 356.012268 304.776611 360.320801 C 324.924194 366.696472 345.852295 365.827637 386.148651 355.395447 C 386.187988 355.360107 386.227325 355.360107 386.304779 355.360107 C 412.154175 348.586548 453.229858 343.15271 495.127747 339.496216 Z M 290.875397 291.867126 C 321.331543 317.292175 329.453491 316.350464 373.107788 305.049438 C 419.806641 292.80896 513.205505 284.333191 578.178711 282.449646 C 611.680603 280.566162 614.726379 284.333191 604.573914 297.515442 C 571.072021 341.77771 505.083557 407.697876 470.566437 419.938477 C 429.959076 433.122925 427.928589 435.00647 424.882843 465.142395 C 420.821869 505.635437 450.262756 512.227661 479.703644 500.926636 C 530.464661 480.208191 642.13678 472.676392 684.775818 480.208191 C 708.125244 483.97522 710.155701 493.3927 704.06427 513.169434 C 680.714844 592.271973 631.984314 675.143677 587.315918 728.821167 C 558.890259 762.724121 556.859802 761.78241 522.342712 743.88916 C 503.05307 734.47168 466.506683 713.753174 447.217041 706.221436 C 412.699921 691.153381 396.457214 703.396118 434.02005 745.772705 C 456.354248 770.25592 503.05307 812.634644 519.296997 835.234375 C 553.814087 883.263672 557.875061 884.205383 606.60437 839.943176 C 725.38324 732.588196 780.2052 547.07019 799.493652 531.062622 C 824.873535 510.344177 831.980225 503.751892 817.766846 481.149963 C 804.569885 460.433655 763.961304 436.889893 745.688049 425.588989 C 732.489929 417.11322 716.247192 404.87262 685.791016 414.290161 C 655.334961 422.763733 637.060547 412.406677 579.194031 419.938477 C 621.833069 376.620178 694.927063 311.641663 721.323364 301.282471 C 761.930786 284.333191 773.098511 273.973877 756.854614 259.847717 C 735.535645 240.070984 721.323364 220.296448 703.049011 208.053711 C 682.7453 192.985718 666.501404 202.403198 627.92334 212.76239 C 595.436707 221.238159 362.955353 246.663208 324.377258 240.070984 C 233.008865 225.005127 229.963135 239.129211 290.875397 291.867126 Z"/>
</g>
</g>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 7.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 22 KiB

View File

@ -0,0 +1,21 @@
<?xml version="1.0" encoding="UTF-8"?>
<!-- Generated by Pixelmator Pro 3.0 -->
<svg width="1024" height="1024" viewBox="0 0 1024 1024" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<g id="NewIMELogo-CHT-">
<g id="CHT">
<path id="-" fill="#ffffff" fill-rule="evenodd" stroke="none" d="M 0 1019 L 1024 1019 L 1024 0 L 0 0 Z"/>
<path id="path1" fill="#ff8346" fill-rule="evenodd" stroke="none" d="M 1024 541.759705 L 410.431976 541.759705 L 320 1024 L 1024 1024 Z"/>
<path id="path2" fill="#f9ce29" fill-rule="evenodd" stroke="none" d="M 1024 0 L 508.359161 0 L 406.06897 541.759705 L 1024 541.759705 Z"/>
<path id="path3" fill="#4ec03b" fill-rule="evenodd" stroke="none" d="M 0 541.759705 L 410.431976 541.759705 L 512 0 C 512 0 0 0 0 0 Z"/>
<path id="path4" fill="#3d7db3" fill-rule="evenodd" stroke="none" d="M 320 1024 L 410.431976 541.759705 L -0 541.759705 L -0 1024 Z"/>
</g>
<g id="g1">
<g id="TextElement">
<g id="Text">
<path id="path5" fill="#002833" stroke="none" d="M 239.846634 241.067261 C 277.331116 272.359619 287.327362 271.200562 341.055725 257.291626 C 398.53125 242.226379 513.483704 231.794678 593.450745 229.476501 C 634.683838 227.158386 638.432434 231.794678 625.937134 248.018982 C 584.704041 302.495605 503.487457 383.628174 461.004852 398.693481 C 411.02655 414.920532 408.527496 417.238708 404.7789 454.329102 C 399.780762 504.166687 436.015717 512.280212 472.250641 498.371277 C 534.725769 472.871643 672.168335 463.601746 724.647156 472.871643 C 753.384888 477.507935 755.883972 489.098694 748.38678 513.43927 C 719.649048 610.796265 659.672974 712.792236 604.696533 778.856812 C 569.711121 820.583557 567.212097 819.4245 524.729492 797.402039 C 500.988403 785.811279 456.008209 760.311646 432.26712 751.041748 C 389.784515 732.49646 369.793488 747.564453 416.024689 799.720215 C 443.512909 829.853455 500.988403 882.011841 520.980896 909.826965 C 563.463501 968.93988 568.461609 970.098938 628.436157 915.622375 C 774.625488 783.493164 842.098694 555.16333 865.838318 535.461731 C 897.075134 509.962036 905.821838 501.848511 888.32843 474.030701 C 872.085999 448.533752 822.106201 419.556824 799.616089 405.647949 C 783.372192 395.216248 763.381165 380.15094 725.896667 391.741699 C 688.412231 402.170715 665.920654 389.423584 594.700317 398.693481 C 647.179138 345.378662 737.140991 265.405151 769.628784 252.655334 C 819.607117 231.794678 833.35199 219.0448 813.359497 201.658691 C 787.120789 177.318115 769.628784 152.980225 747.137268 137.912231 C 722.148071 119.367004 702.155579 130.957764 654.674866 143.707581 C 614.691345 154.139282 328.560425 185.431641 281.079712 177.318115 C 168.626297 158.775574 164.877701 176.158997 239.846634 241.067261 Z"/>
<path id="path6" fill="#ffffff" fill-rule="evenodd" stroke="none" d="M 491.234131 299.687683 C 488.638275 302.049377 486.043884 304.367493 483.496429 306.595886 C 467.108795 320.861206 452.403351 333.341675 440.773315 337.934448 C 387.430634 355.364136 368.687683 371.457886 357.346558 389.733765 C 349.321411 402.750244 343.939056 419.646606 341.102661 447.907959 C 341.102661 447.907959 341.102661 447.907959 341.102661 447.954224 C 336.393463 494.670959 352.63736 524.137573 372.676788 542.5495 C 400.789764 568.315796 447.597351 576.383057 495.17337 558.107239 C 495.606018 557.971191 496.038666 557.794312 496.422913 557.614746 C 538.280762 540.541504 619.256836 532.071533 674.331543 532.963989 C 645.400208 609.816772 598.784729 685.913086 555.582031 737.845703 L 553.515625 740.253601 L 552.794067 739.897217 C 528.237549 727.903687 481.911041 701.960571 456.679901 691.885315 C 425.010437 678.243042 398.24231 677.932861 382.095215 682.033142 C 359.797241 687.69519 344.70752 700.621948 335.240723 717.248901 C 327.598328 730.71167 322.745422 748.277344 327.167175 770.789551 C 330.242584 786.480591 340.862152 811.39801 368.111298 842.157104 C 368.351837 842.380188 368.543945 842.603271 368.736084 842.872681 C 394.879425 871.533936 450.001068 920.704895 469.031494 947.184082 C 485.658173 970.365601 498.586121 986.189941 509.686707 995.819031 C 527.99707 1011.689636 546.018433 1018.064575 564.183594 1019.177368 C 580.619629 1020.203125 598.737793 1016.859253 619.402039 1004.645386 C 632.52063 996.888306 649.100403 983.338501 671.399841 963.054688 C 808.21759 839.349182 881.216919 636.429199 912.550537 579.816772 C 944.507446 552.488708 956.954346 530.468994 960.126587 510.495361 C 963.202026 491.596436 960.895081 469.217529 942.489441 439.973999 C 942.44104 439.840637 942.392639 439.750854 942.297302 439.661072 C 922.065735 407.879028 862.138123 369.093506 833.736206 351.530518 C 817.253235 340.921936 798.366577 328.618347 772.366943 324.428223 C 780.585693 318.586609 787.650208 314.352966 793.032593 312.21167 C 793.416809 312.078369 793.849487 311.901489 794.282104 311.721924 C 830.709167 296.52063 852.863403 281.898865 863.868713 270.264587 C 880.015808 253.147766 885.637207 235.225647 886.166687 218.33197 C 886.743042 198.807251 880.640564 175.802612 856.32312 154.229065 C 828.064941 127.926758 808.314392 102.293762 784.09375 85.666748 C 756.171387 65.339355 731.038513 60.969727 699.561218 65.829102 C 683.846741 68.237061 664.86322 74.699036 638.335632 81.833069 C 600.610657 91.55188 335.865479 121.774963 291.844452 114.240967 C 291.749115 114.197388 291.603912 114.197388 291.508606 114.151184 C 240.807251 105.817261 207.119766 105.191467 189.098358 108.802002 C 158.534714 114.910278 142.771851 131.403992 134.217255 146.871948 C 124.221001 164.837585 119.511795 188.731995 133.881409 218.019104 C 141.570709 233.799927 162.234909 258.540466 197.940414 289.432861 C 198.229324 289.702209 198.51825 289.968872 198.854095 290.191956 C 222.449997 309.893555 239.990356 320.015076 256.955841 325.317932 C 281.752869 333.164856 307.510529 332.095581 357.106049 319.25592 C 357.154449 319.212402 357.20285 319.212402 357.298187 319.212402 C 389.112823 310.875732 439.667511 304.187927 491.234131 299.687683 Z M 239.846634 241.067261 C 277.331116 272.359619 287.327362 271.200562 341.055725 257.291626 C 398.53125 242.226379 513.483704 231.794678 593.450745 229.476501 C 634.683838 227.158386 638.432434 231.794678 625.937134 248.018982 C 584.704041 302.495605 503.487457 383.628174 461.004852 398.693481 C 411.02655 414.920532 408.527496 417.238708 404.7789 454.329102 C 399.780762 504.166687 436.015717 512.280212 472.250641 498.371277 C 534.725769 472.871643 672.168335 463.601746 724.647156 472.871643 C 753.384888 477.507935 755.883972 489.098694 748.38678 513.43927 C 719.649048 610.796265 659.672974 712.792236 604.696533 778.856812 C 569.711121 820.583557 567.212097 819.4245 524.729492 797.402039 C 500.988403 785.811279 456.008209 760.311646 432.26712 751.041748 C 389.784515 732.49646 369.793488 747.564453 416.024689 799.720215 C 443.512909 829.853455 500.988403 882.011841 520.980896 909.826965 C 563.463501 968.93988 568.461609 970.098938 628.436157 915.622375 C 774.625488 783.493164 842.098694 555.16333 865.838318 535.461731 C 897.075134 509.962036 905.821838 501.848511 888.32843 474.030701 C 872.085999 448.533752 822.106201 419.556824 799.616089 405.647949 C 783.372192 395.216248 763.381165 380.15094 725.896667 391.741699 C 688.412231 402.170715 665.920654 389.423584 594.700317 398.693481 C 647.179138 345.378662 737.140991 265.405151 769.628784 252.655334 C 819.607117 231.794678 833.35199 219.0448 813.359497 201.658691 C 787.120789 177.318115 769.628784 152.980225 747.137268 137.912231 C 722.148071 119.367004 702.155579 130.957764 654.674866 143.707581 C 614.691345 154.139282 328.560425 185.431641 281.079712 177.318115 C 168.626297 158.775574 164.877701 176.158997 239.846634 241.067261 Z"/>
</g>
</g>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 7.7 KiB

View File

@ -1,32 +0,0 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg width="100%" height="100%" viewBox="0 0 16 16" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xml:space="preserve" xmlns:serif="http://www.serif.com/" style="fill-rule:evenodd;clip-rule:evenodd;stroke-linejoin:round;stroke-miterlimit:2;">
<g transform="matrix(1,0,0,1,0.176229,0.510845)">
<g id="v" transform="matrix(-0.0111111,-1.36072e-18,1.36072e-18,-0.0111111,13.8235,12.9891)">
<g id="Shadow" transform="matrix(-1.02102,-1.25039e-16,1.28682e-16,-1.05077,1169.98,1160.72)">
<path d="M1322.21,34L452.612,34C202.809,34 0,231.067 0,473.799L0,1318.78L1322.21,1318.78L1322.21,34Z" style="fill-opacity:0.63;"/>
</g>
<g transform="matrix(-1.01166,-1.23893e-16,1.27502e-16,-1.04113,1259.98,1250.4)">
<g id="Outline">
<path d="M1334.45,34L452.612,34C202.809,34 0,231.067 0,473.799L0,1330.67L1334.45,1330.67L1334.45,34Z" style="fill:rgb(11,46,99);"/>
</g>
</g>
<g id="Core" transform="matrix(-0.861782,-1.05538e-16,1.08613e-16,-0.886889,1169.98,1155.15)">
<path d="M1357.66,34L452.612,34C202.809,34 0,231.067 0,473.799L0,1353.23L1357.66,1353.23L1357.66,34Z" style="fill:url(#_Radial1);"/>
<path d="M1409.88,1403.97L1409.88,-16.739L452.612,-16.739C173.989,-16.739 -52.217,203.063 -52.217,473.799C-52.217,473.799 -52.217,1403.97 -52.217,1403.97L1409.88,1403.97ZM1357.66,34L452.612,34C202.809,34 0,231.067 0,473.799L0,1353.23L1357.66,1353.23L1357.66,34Z" style="fill:white;"/>
</g>
</g>
<g id="TextElement" transform="matrix(0.0115939,0,0,0.0115939,0.253417,-0.559324)">
<g id="TextShadow" transform="matrix(76.3556,0,0,67.9081,-21039.4,-60964.1)">
<path d="M279.547,902.926C280.327,903.628 280.535,903.602 281.653,903.29C282.849,902.952 285.241,902.718 286.905,902.666C287.763,902.614 287.841,902.718 287.581,903.082C286.723,904.304 285.033,906.124 284.149,906.462C283.109,906.826 283.057,906.878 282.979,907.71C282.875,908.828 283.629,909.01 284.383,908.698C285.683,908.126 288.543,907.918 289.635,908.126C290.233,908.23 290.285,908.49 290.129,909.036C289.531,911.22 288.283,913.508 287.139,914.99C286.411,915.926 286.359,915.9 285.475,915.406C284.981,915.146 284.045,914.574 283.551,914.366C282.667,913.95 282.251,914.288 283.213,915.458C283.785,916.134 284.981,917.304 285.397,917.928C286.281,919.254 286.385,919.28 287.633,918.058C290.675,915.094 292.079,909.972 292.573,909.53C293.223,908.958 293.405,908.776 293.041,908.152C292.703,907.58 291.663,906.93 291.195,906.618C290.857,906.384 290.441,906.046 289.661,906.306C288.881,906.54 288.413,906.254 286.931,906.462C288.023,905.266 289.895,903.472 290.571,903.186C291.611,902.718 291.897,902.432 291.481,902.042C290.935,901.496 290.571,900.95 290.103,900.612C289.583,900.196 289.167,900.456 288.179,900.742C287.347,900.976 281.393,901.678 280.405,901.496C278.065,901.08 277.987,901.47 279.547,902.926Z" style="fill-opacity:0.8;fill-rule:nonzero;"/>
</g>
<g id="Text" transform="matrix(64.7661,0,0,60.0776,-17811.9,-53913.5)">
<path d="M279.547,902.926C280.327,903.628 280.535,903.602 281.653,903.29C282.849,902.952 285.241,902.718 286.905,902.666C287.763,902.614 287.841,902.718 287.581,903.082C286.723,904.304 285.033,906.124 284.149,906.462C283.109,906.826 283.057,906.878 282.979,907.71C282.875,908.828 283.629,909.01 284.383,908.698C285.683,908.126 288.543,907.918 289.635,908.126C290.233,908.23 290.285,908.49 290.129,909.036C289.531,911.22 288.283,913.508 287.139,914.99C286.411,915.926 286.359,915.9 285.475,915.406C284.981,915.146 284.045,914.574 283.551,914.366C282.667,913.95 282.251,914.288 283.213,915.458C283.785,916.134 284.981,917.304 285.397,917.928C286.281,919.254 286.385,919.28 287.633,918.058C290.675,915.094 292.079,909.972 292.573,909.53C293.223,908.958 293.405,908.776 293.041,908.152C292.703,907.58 291.663,906.93 291.195,906.618C290.857,906.384 290.441,906.046 289.661,906.306C288.881,906.54 288.413,906.254 286.931,906.462C288.023,905.266 289.895,903.472 290.571,903.186C291.611,902.718 291.897,902.432 291.481,902.042C290.935,901.496 290.571,900.95 290.103,900.612C289.583,900.196 289.167,900.456 288.179,900.742C287.347,900.976 281.393,901.678 280.405,901.496C278.065,901.08 277.987,901.47 279.547,902.926Z" style="fill:rgb(16,42,103);fill-rule:nonzero;"/>
<path d="M284.778,904.241C284.724,904.294 284.67,904.346 284.617,904.396C284.276,904.716 283.97,904.996 283.728,905.099C282.618,905.49 282.228,905.851 281.992,906.261C281.825,906.553 281.713,906.932 281.654,907.566L281.654,907.567C281.556,908.615 281.894,909.276 282.311,909.689C282.896,910.267 283.87,910.448 284.86,910.038C284.869,910.035 284.878,910.031 284.886,910.027C285.757,909.644 287.442,909.454 288.588,909.474C287.986,911.198 287.016,912.905 286.117,914.07L286.074,914.124L286.059,914.116C285.548,913.847 284.584,913.265 284.059,913.039C283.4,912.733 282.843,912.726 282.507,912.818C282.043,912.945 281.729,913.235 281.532,913.608C281.373,913.91 281.272,914.304 281.364,914.809C281.428,915.161 281.649,915.72 282.216,916.41C282.221,916.415 282.225,916.42 282.229,916.426C282.773,917.069 283.92,918.172 284.316,918.766C284.662,919.286 284.931,919.641 285.162,919.857C285.543,920.213 285.918,920.356 286.296,920.381C286.638,920.404 287.015,920.329 287.445,920.055C287.718,919.881 288.063,919.577 288.527,919.122C291.374,916.347 292.893,911.795 293.545,910.525C294.21,909.912 294.469,909.418 294.535,908.97C294.599,908.546 294.551,908.044 294.168,907.388C294.167,907.385 294.166,907.383 294.164,907.381C293.743,906.668 292.496,905.798 291.905,905.404C291.562,905.166 291.169,904.89 290.628,904.796C290.799,904.665 290.946,904.57 291.058,904.522C291.066,904.519 291.075,904.515 291.084,904.511C291.842,904.17 292.303,903.842 292.532,903.581C292.868,903.197 292.985,902.795 292.996,902.416C293.008,901.978 292.881,901.462 292.375,900.978C291.787,900.388 291.376,899.813 290.872,899.44C290.291,898.984 289.768,898.886 289.113,898.995C288.786,899.049 288.391,899.194 287.839,899.354C287.054,899.572 281.545,900.25 280.629,900.081C280.627,900.08 280.624,900.08 280.622,900.079C279.567,899.892 278.866,899.878 278.491,899.959C277.855,900.096 277.527,900.466 277.349,900.813C277.141,901.216 277.043,901.752 277.342,902.409C277.502,902.763 277.932,903.318 278.675,904.011C278.681,904.017 278.687,904.023 278.694,904.028C279.185,904.47 279.55,904.697 279.903,904.816C280.419,904.992 280.955,904.968 281.987,904.68C281.988,904.679 281.989,904.679 281.991,904.679C282.653,904.492 283.705,904.342 284.778,904.241ZM279.547,902.926C280.327,903.628 280.535,903.602 281.653,903.29C282.849,902.952 285.241,902.718 286.905,902.666C287.763,902.614 287.841,902.718 287.581,903.082C286.723,904.304 285.033,906.124 284.149,906.462C283.109,906.826 283.057,906.878 282.979,907.71C282.875,908.828 283.629,909.01 284.383,908.698C285.683,908.126 288.543,907.918 289.635,908.126C290.233,908.23 290.285,908.49 290.129,909.036C289.531,911.22 288.283,913.508 287.139,914.99C286.411,915.926 286.359,915.9 285.475,915.406C284.981,915.146 284.045,914.574 283.551,914.366C282.667,913.95 282.251,914.288 283.213,915.458C283.785,916.134 284.981,917.304 285.397,917.928C286.281,919.254 286.385,919.28 287.633,918.058C290.675,915.094 292.079,909.972 292.573,909.53C293.223,908.958 293.405,908.776 293.041,908.152C292.703,907.58 291.663,906.93 291.195,906.618C290.857,906.384 290.441,906.046 289.661,906.306C288.881,906.54 288.413,906.254 286.931,906.462C288.023,905.266 289.895,903.472 290.571,903.186C291.611,902.718 291.897,902.432 291.481,902.042C290.935,901.496 290.571,900.95 290.103,900.612C289.583,900.196 289.167,900.456 288.179,900.742C287.347,900.976 281.393,901.678 280.405,901.496C278.065,901.08 277.987,901.47 279.547,902.926Z" style="fill:white;"/>
</g>
</g>
</g>
<defs>
<radialGradient id="_Radial1" cx="0" cy="0" r="1" gradientUnits="userSpaceOnUse" gradientTransform="matrix(-1087.57,-3794.91,3905.47,-1056.78,1725.88,3633.33)"><stop offset="0" style="stop-color:rgb(218,240,255);stop-opacity:1"/><stop offset="0.28" style="stop-color:rgb(200,225,246);stop-opacity:1"/><stop offset="0.51" style="stop-color:rgb(193,219,243);stop-opacity:1"/><stop offset="0.73" style="stop-color:rgb(127,167,220);stop-opacity:1"/><stop offset="0.87" style="stop-color:rgb(14,87,170);stop-opacity:1"/><stop offset="1" style="stop-color:rgb(9,53,104);stop-opacity:1"/></radialGradient>
</defs>
</svg>

Before

Width:  |  Height:  |  Size: 8.5 KiB

Some files were not shown because too many files have changed in this diff Show More