Adds a tiny tooltop for shift-left/right selections.
This commit is contained in:
parent
4c1781d970
commit
366453820d
|
@ -42,6 +42,7 @@
|
||||||
D427A9C125ED28CC005D43E0 /* OpenCCBridge.swift in Sources */ = {isa = PBXBuildFile; fileRef = D427A9C025ED28CC005D43E0 /* OpenCCBridge.swift */; };
|
D427A9C125ED28CC005D43E0 /* OpenCCBridge.swift in Sources */ = {isa = PBXBuildFile; fileRef = D427A9C025ED28CC005D43E0 /* OpenCCBridge.swift */; };
|
||||||
D427F76A278C9E29004A2160 /* CandidateUI in Frameworks */ = {isa = PBXBuildFile; productRef = D427F769278C9E29004A2160 /* CandidateUI */; };
|
D427F76A278C9E29004A2160 /* CandidateUI in Frameworks */ = {isa = PBXBuildFile; productRef = D427F769278C9E29004A2160 /* CandidateUI */; };
|
||||||
D427F76C278CA2B0004A2160 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = D427F76B278CA1BA004A2160 /* AppDelegate.swift */; };
|
D427F76C278CA2B0004A2160 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = D427F76B278CA1BA004A2160 /* AppDelegate.swift */; };
|
||||||
|
D427F7A927905E90004A2160 /* TooltipUI in Frameworks */ = {isa = PBXBuildFile; productRef = D427F7A827905E90004A2160 /* TooltipUI */; };
|
||||||
D47F7DCE278BFB57002F9DD7 /* PreferencesWindowController.swift in Sources */ = {isa = PBXBuildFile; fileRef = D47F7DCD278BFB57002F9DD7 /* PreferencesWindowController.swift */; };
|
D47F7DCE278BFB57002F9DD7 /* PreferencesWindowController.swift in Sources */ = {isa = PBXBuildFile; fileRef = D47F7DCD278BFB57002F9DD7 /* PreferencesWindowController.swift */; };
|
||||||
D47F7DD0278C0897002F9DD7 /* NonModalAlertWindowController.swift in Sources */ = {isa = PBXBuildFile; fileRef = D47F7DCF278C0897002F9DD7 /* NonModalAlertWindowController.swift */; };
|
D47F7DD0278C0897002F9DD7 /* NonModalAlertWindowController.swift in Sources */ = {isa = PBXBuildFile; fileRef = D47F7DCF278C0897002F9DD7 /* NonModalAlertWindowController.swift */; };
|
||||||
D47F7DD3278C1263002F9DD7 /* UserOverrideModel.cpp in Sources */ = {isa = PBXBuildFile; fileRef = D47F7DD2278C1263002F9DD7 /* UserOverrideModel.cpp */; };
|
D47F7DD3278C1263002F9DD7 /* UserOverrideModel.cpp in Sources */ = {isa = PBXBuildFile; fileRef = D47F7DD2278C1263002F9DD7 /* UserOverrideModel.cpp */; };
|
||||||
|
@ -168,6 +169,7 @@
|
||||||
D427A9C025ED28CC005D43E0 /* OpenCCBridge.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OpenCCBridge.swift; sourceTree = "<group>"; };
|
D427A9C025ED28CC005D43E0 /* OpenCCBridge.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OpenCCBridge.swift; sourceTree = "<group>"; };
|
||||||
D427F768278C9D0D004A2160 /* CandidateUI */ = {isa = PBXFileReference; lastKnownFileType = wrapper; name = CandidateUI; path = Packages/CandidateUI; sourceTree = "<group>"; };
|
D427F768278C9D0D004A2160 /* CandidateUI */ = {isa = PBXFileReference; lastKnownFileType = wrapper; name = CandidateUI; path = Packages/CandidateUI; sourceTree = "<group>"; };
|
||||||
D427F76B278CA1BA004A2160 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = "<group>"; };
|
D427F76B278CA1BA004A2160 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = "<group>"; };
|
||||||
|
D427F7A727905E43004A2160 /* TooltipUI */ = {isa = PBXFileReference; lastKnownFileType = wrapper; name = TooltipUI; path = Packages/TooltipUI; sourceTree = "<group>"; };
|
||||||
D47F7DCD278BFB57002F9DD7 /* PreferencesWindowController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PreferencesWindowController.swift; sourceTree = "<group>"; };
|
D47F7DCD278BFB57002F9DD7 /* PreferencesWindowController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PreferencesWindowController.swift; sourceTree = "<group>"; };
|
||||||
D47F7DCF278C0897002F9DD7 /* NonModalAlertWindowController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NonModalAlertWindowController.swift; sourceTree = "<group>"; };
|
D47F7DCF278C0897002F9DD7 /* NonModalAlertWindowController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NonModalAlertWindowController.swift; sourceTree = "<group>"; };
|
||||||
D47F7DD1278C1263002F9DD7 /* UserOverrideModel.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = UserOverrideModel.h; sourceTree = "<group>"; };
|
D47F7DD1278C1263002F9DD7 /* UserOverrideModel.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = UserOverrideModel.h; sourceTree = "<group>"; };
|
||||||
|
@ -182,6 +184,7 @@
|
||||||
files = (
|
files = (
|
||||||
6A38BC2815FC158A00A8A51F /* InputMethodKit.framework in Frameworks */,
|
6A38BC2815FC158A00A8A51F /* InputMethodKit.framework in Frameworks */,
|
||||||
D48550A325EBE689006A204C /* OpenCC in Frameworks */,
|
D48550A325EBE689006A204C /* OpenCC in Frameworks */,
|
||||||
|
D427F7A927905E90004A2160 /* TooltipUI in Frameworks */,
|
||||||
D427F76A278C9E29004A2160 /* CandidateUI in Frameworks */,
|
D427F76A278C9E29004A2160 /* CandidateUI in Frameworks */,
|
||||||
6A0D4EA715FC0D2D00ABF4B3 /* Cocoa.framework in Frameworks */,
|
6A0D4EA715FC0D2D00ABF4B3 /* Cocoa.framework in Frameworks */,
|
||||||
);
|
);
|
||||||
|
@ -393,6 +396,7 @@
|
||||||
isa = PBXGroup;
|
isa = PBXGroup;
|
||||||
children = (
|
children = (
|
||||||
D427F768278C9D0D004A2160 /* CandidateUI */,
|
D427F768278C9D0D004A2160 /* CandidateUI */,
|
||||||
|
D427F7A727905E43004A2160 /* TooltipUI */,
|
||||||
);
|
);
|
||||||
name = Packages;
|
name = Packages;
|
||||||
sourceTree = "<group>";
|
sourceTree = "<group>";
|
||||||
|
@ -434,6 +438,7 @@
|
||||||
packageProductDependencies = (
|
packageProductDependencies = (
|
||||||
D48550A225EBE689006A204C /* OpenCC */,
|
D48550A225EBE689006A204C /* OpenCC */,
|
||||||
D427F769278C9E29004A2160 /* CandidateUI */,
|
D427F769278C9E29004A2160 /* CandidateUI */,
|
||||||
|
D427F7A827905E90004A2160 /* TooltipUI */,
|
||||||
);
|
);
|
||||||
productName = McBopomofo;
|
productName = McBopomofo;
|
||||||
productReference = 6A0D4EA215FC0D2D00ABF4B3 /* McBopomofo.app */;
|
productReference = 6A0D4EA215FC0D2D00ABF4B3 /* McBopomofo.app */;
|
||||||
|
@ -1059,6 +1064,10 @@
|
||||||
isa = XCSwiftPackageProductDependency;
|
isa = XCSwiftPackageProductDependency;
|
||||||
productName = CandidateUI;
|
productName = CandidateUI;
|
||||||
};
|
};
|
||||||
|
D427F7A827905E90004A2160 /* TooltipUI */ = {
|
||||||
|
isa = XCSwiftPackageProductDependency;
|
||||||
|
productName = TooltipUI;
|
||||||
|
};
|
||||||
D48550A225EBE689006A204C /* OpenCC */ = {
|
D48550A225EBE689006A204C /* OpenCC */ = {
|
||||||
isa = XCSwiftPackageProductDependency;
|
isa = XCSwiftPackageProductDependency;
|
||||||
package = D48550A125EBE689006A204C /* XCRemoteSwiftPackageReference "SwiftyOpenCC" */;
|
package = D48550A125EBE689006A204C /* XCRemoteSwiftPackageReference "SwiftyOpenCC" */;
|
||||||
|
|
|
@ -203,7 +203,7 @@ public class HorizontalCandidateController: CandidateController {
|
||||||
var contentRect = NSRect(x: 128.0, y: 128.0, width: 0.0, height: 0.0)
|
var contentRect = NSRect(x: 128.0, y: 128.0, width: 0.0, height: 0.0)
|
||||||
let styleMask: NSWindow.StyleMask = [.borderless, .nonactivatingPanel]
|
let styleMask: NSWindow.StyleMask = [.borderless, .nonactivatingPanel]
|
||||||
let panel = NSPanel(contentRect: contentRect, styleMask: styleMask, backing: .buffered, defer: false)
|
let panel = NSPanel(contentRect: contentRect, styleMask: styleMask, backing: .buffered, defer: false)
|
||||||
panel.level = NSWindow.Level(Int(kCGPopUpMenuWindowLevel))
|
panel.level = NSWindow.Level(Int(kCGPopUpMenuWindowLevel) + 1)
|
||||||
panel.hasShadow = true
|
panel.hasShadow = true
|
||||||
|
|
||||||
contentRect.origin = NSPoint.zero
|
contentRect.origin = NSPoint.zero
|
||||||
|
|
|
@ -0,0 +1,7 @@
|
||||||
|
.DS_Store
|
||||||
|
/.build
|
||||||
|
/Packages
|
||||||
|
/*.xcodeproj
|
||||||
|
xcuserdata/
|
||||||
|
DerivedData/
|
||||||
|
.swiftpm/xcode/package.xcworkspace/contents.xcworkspacedata
|
|
@ -0,0 +1,25 @@
|
||||||
|
// swift-tools-version:5.5
|
||||||
|
// The swift-tools-version declares the minimum version of Swift required to build this package.
|
||||||
|
|
||||||
|
import PackageDescription
|
||||||
|
|
||||||
|
let package = Package(
|
||||||
|
name: "TooltipUI",
|
||||||
|
products: [
|
||||||
|
// Products define the executables and libraries a package produces, and make them visible to other packages.
|
||||||
|
.library(
|
||||||
|
name: "TooltipUI",
|
||||||
|
targets: ["TooltipUI"]),
|
||||||
|
],
|
||||||
|
dependencies: [
|
||||||
|
// Dependencies declare other packages that this package depends on.
|
||||||
|
// .package(url: /* package url */, from: "1.0.0"),
|
||||||
|
],
|
||||||
|
targets: [
|
||||||
|
// Targets are the basic building blocks of a package. A target can define a module or a test suite.
|
||||||
|
// Targets can depend on other targets in this package, and on products in packages this package depends on.
|
||||||
|
.target(
|
||||||
|
name: "TooltipUI",
|
||||||
|
dependencies: []),
|
||||||
|
]
|
||||||
|
)
|
|
@ -0,0 +1,3 @@
|
||||||
|
# TooltipUI
|
||||||
|
|
||||||
|
A description of this package.
|
|
@ -0,0 +1,65 @@
|
||||||
|
import Cocoa
|
||||||
|
|
||||||
|
public class TooltipController: NSWindowController {
|
||||||
|
let backgroundColor = NSColor(calibratedHue: 0.16, saturation: 0.22, brightness: 0.97, alpha: 1.0)
|
||||||
|
var messageTextField: NSTextField
|
||||||
|
var tooltip: String = "" {
|
||||||
|
didSet {
|
||||||
|
messageTextField.stringValue = tooltip
|
||||||
|
adjustSize()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public init() {
|
||||||
|
let contentRect = NSRect(x: 128.0, y: 128.0, width: 300.0, height: 20.0)
|
||||||
|
let styleMask: NSWindow.StyleMask = [.borderless, .nonactivatingPanel]
|
||||||
|
let panel = NSPanel(contentRect: contentRect, styleMask: styleMask, backing: .buffered, defer: false)
|
||||||
|
panel.level = NSWindow.Level(Int(kCGPopUpMenuWindowLevel))
|
||||||
|
panel.hasShadow = true
|
||||||
|
|
||||||
|
messageTextField = NSTextField()
|
||||||
|
messageTextField.isEditable = false
|
||||||
|
messageTextField.isSelectable = false
|
||||||
|
messageTextField.isBezeled = false
|
||||||
|
messageTextField.textColor = .black
|
||||||
|
messageTextField.drawsBackground = true
|
||||||
|
messageTextField.backgroundColor = backgroundColor
|
||||||
|
messageTextField.font = .systemFont(ofSize: NSFont.systemFontSize(for: .small))
|
||||||
|
panel.contentView?.addSubview(messageTextField)
|
||||||
|
|
||||||
|
super.init(window: panel)
|
||||||
|
}
|
||||||
|
|
||||||
|
public required init?(coder: NSCoder) {
|
||||||
|
fatalError("init(coder:) has not been implemented")
|
||||||
|
}
|
||||||
|
|
||||||
|
@objc(showTooltip:atPoint:)
|
||||||
|
public func show(tooltip: String, at point: NSPoint) {
|
||||||
|
self.tooltip = tooltip
|
||||||
|
window?.orderFront(nil)
|
||||||
|
set(windowLocation: point)
|
||||||
|
}
|
||||||
|
|
||||||
|
@objc
|
||||||
|
public func hide() {
|
||||||
|
window?.orderOut(nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
private func set(windowLocation location: NSPoint) {
|
||||||
|
var newPoint = location
|
||||||
|
if location.y > 5 {
|
||||||
|
newPoint.y -= 5
|
||||||
|
}
|
||||||
|
window?.setFrameTopLeftPoint(newPoint)
|
||||||
|
}
|
||||||
|
|
||||||
|
private func adjustSize() {
|
||||||
|
let attrString = messageTextField.attributedStringValue;
|
||||||
|
var rect = attrString.boundingRect(with: NSSize(width: 1600.0, height: 1600.0), options: .usesLineFragmentOrigin)
|
||||||
|
rect.size.width += 10
|
||||||
|
messageTextField.frame = rect
|
||||||
|
window?.setFrame(rect, display: true)
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -42,6 +42,7 @@
|
||||||
#import "McBopomofo-Swift.h"
|
#import "McBopomofo-Swift.h"
|
||||||
|
|
||||||
@import CandidateUI;
|
@import CandidateUI;
|
||||||
|
@import TooltipUI;
|
||||||
@import OpenCC;
|
@import OpenCC;
|
||||||
|
|
||||||
// C++ namespace usages
|
// C++ namespace usages
|
||||||
|
@ -489,6 +490,7 @@ NS_INLINE size_t max(size_t a, size_t b) { return a > b ? a : b; }
|
||||||
// i.e. the client app needs to take care of where to put ths composing buffer
|
// i.e. the client app needs to take care of where to put ths composing buffer
|
||||||
[client setMarkedText:attrString selectionRange:NSMakeRange((NSInteger)_builder->markerCursorIndex(), 0) replacementRange:NSMakeRange(NSNotFound, NSNotFound)];
|
[client setMarkedText:attrString selectionRange:NSMakeRange((NSInteger)_builder->markerCursorIndex(), 0) replacementRange:NSMakeRange(NSNotFound, NSNotFound)];
|
||||||
_latestReadingCursor = (NSInteger)_builder->markerCursorIndex();
|
_latestReadingCursor = (NSInteger)_builder->markerCursorIndex();
|
||||||
|
[self _showCurrentMarkedTextTooltipWithClient:client];
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
// we must use NSAttributedString so that the cursor is visible --
|
// we must use NSAttributedString so that the cursor is visible --
|
||||||
|
@ -501,6 +503,7 @@ NS_INLINE size_t max(size_t a, size_t b) { return a > b ? a : b; }
|
||||||
// i.e. the client app needs to take care of where to put ths composing buffer
|
// i.e. the client app needs to take care of where to put ths composing buffer
|
||||||
[client setMarkedText:attrString selectionRange:NSMakeRange(cursorIndex, 0) replacementRange:NSMakeRange(NSNotFound, NSNotFound)];
|
[client setMarkedText:attrString selectionRange:NSMakeRange(cursorIndex, 0) replacementRange:NSMakeRange(NSNotFound, NSNotFound)];
|
||||||
_latestReadingCursor = cursorIndex;
|
_latestReadingCursor = cursorIndex;
|
||||||
|
[self _hideTooltip];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -606,47 +609,7 @@ NS_INLINE size_t max(size_t a, size_t b) { return a > b ? a : b; }
|
||||||
return layout;
|
return layout;
|
||||||
}
|
}
|
||||||
|
|
||||||
- (NSString *)_currentMarkedText
|
- (McBpomofoEmacsKey)_detectEmacsKeyFromCharCode:(UniChar)charCode modifiers:(NSUInteger)flags
|
||||||
{
|
|
||||||
if (_builder->markerCursorIndex() < 0) {
|
|
||||||
return @"";
|
|
||||||
}
|
|
||||||
if (!_bpmfReadingBuffer->isEmpty()) {
|
|
||||||
return @"";
|
|
||||||
}
|
|
||||||
|
|
||||||
size_t begin = min(_builder->markerCursorIndex(), _builder->cursorIndex());
|
|
||||||
size_t end = max(_builder->markerCursorIndex(), _builder->cursorIndex());
|
|
||||||
// A phrase should contian at least two characters.
|
|
||||||
if (end - begin < 2) {
|
|
||||||
return @"";
|
|
||||||
}
|
|
||||||
|
|
||||||
NSRange range = NSMakeRange((NSInteger)begin, (NSInteger)(end - begin));
|
|
||||||
NSString *reading = [_composingBuffer substringWithRange:range];
|
|
||||||
NSMutableString *string = [[NSMutableString alloc] init];
|
|
||||||
[string appendString:reading];
|
|
||||||
[string appendString:@" "];
|
|
||||||
NSMutableArray *readingsArray = [[NSMutableArray alloc] init];
|
|
||||||
vector<std::string> v = _builder->readingsAtRange(begin, end);
|
|
||||||
for(vector<std::string>::iterator it_i=v.begin(); it_i!=v.end(); ++it_i) {
|
|
||||||
[readingsArray addObject:[NSString stringWithUTF8String:it_i->c_str()]];
|
|
||||||
}
|
|
||||||
[string appendString:[readingsArray componentsJoinedByString:@"-"]];
|
|
||||||
return string;
|
|
||||||
}
|
|
||||||
|
|
||||||
- (BOOL)_writeUserPhrase
|
|
||||||
{
|
|
||||||
NSString *currentMarkedPhrase = [self _currentMarkedText];
|
|
||||||
if (![currentMarkedPhrase length]) {
|
|
||||||
return NO;
|
|
||||||
}
|
|
||||||
|
|
||||||
return [LanguageModelManager writeUserPhrase:currentMarkedPhrase];
|
|
||||||
}
|
|
||||||
|
|
||||||
- (McBpomofoEmacsKey)detectEmacsKeyFromCharCode:(UniChar)charCode modifiers:(NSUInteger)flags
|
|
||||||
{
|
{
|
||||||
if (flags & NSControlKeyMask) {
|
if (flags & NSControlKeyMask) {
|
||||||
char c = charCode + 'a' - 1;
|
char c = charCode + 'a' - 1;
|
||||||
|
@ -698,7 +661,7 @@ NS_INLINE size_t max(size_t a, size_t b) { return a > b ? a : b; }
|
||||||
// get the unicode character code
|
// get the unicode character code
|
||||||
UniChar charCode = [inputText length] ? [inputText characterAtIndex:0] : 0;
|
UniChar charCode = [inputText length] ? [inputText characterAtIndex:0] : 0;
|
||||||
|
|
||||||
McBpomofoEmacsKey emacsKey = [self detectEmacsKeyFromCharCode:charCode modifiers:flags];
|
McBpomofoEmacsKey emacsKey = [self _detectEmacsKeyFromCharCode:charCode modifiers:flags];
|
||||||
|
|
||||||
if ([[client bundleIdentifier] isEqualToString:@"com.apple.Terminal"] && [NSStringFromClass([client class]) isEqualToString:@"IPMDServerClientWrapper"]) {
|
if ([[client bundleIdentifier] isEqualToString:@"com.apple.Terminal"] && [NSStringFromClass([client class]) isEqualToString:@"IPMDServerClientWrapper"]) {
|
||||||
// special handling for com.apple.Terminal
|
// special handling for com.apple.Terminal
|
||||||
|
@ -1400,24 +1363,30 @@ NS_INLINE size_t max(size_t a, size_t b) { return a > b ? a : b; }
|
||||||
+ (VTHorizontalCandidateController *)horizontalCandidateController
|
+ (VTHorizontalCandidateController *)horizontalCandidateController
|
||||||
{
|
{
|
||||||
static VTHorizontalCandidateController *instance = nil;
|
static VTHorizontalCandidateController *instance = nil;
|
||||||
@synchronized(self) {
|
static dispatch_once_t onceToken;
|
||||||
if (!instance) {
|
dispatch_once(&onceToken, ^{
|
||||||
instance = [[VTHorizontalCandidateController alloc] init];
|
instance = [[VTHorizontalCandidateController alloc] init];
|
||||||
}
|
});
|
||||||
}
|
|
||||||
|
|
||||||
return instance;
|
return instance;
|
||||||
}
|
}
|
||||||
|
|
||||||
+ (VTVerticalCandidateController *)verticalCandidateController
|
+ (VTVerticalCandidateController *)verticalCandidateController
|
||||||
{
|
{
|
||||||
static VTVerticalCandidateController *instance = nil;
|
static VTVerticalCandidateController *instance = nil;
|
||||||
@synchronized(self) {
|
static dispatch_once_t onceToken;
|
||||||
if (!instance) {
|
dispatch_once(&onceToken, ^{
|
||||||
instance = [[VTVerticalCandidateController alloc] init];
|
instance = [[VTVerticalCandidateController alloc] init];
|
||||||
}
|
});
|
||||||
}
|
return instance;
|
||||||
|
}
|
||||||
|
|
||||||
|
+ (TooltipController *)tooltipController
|
||||||
|
{
|
||||||
|
static TooltipController *instance = nil;
|
||||||
|
static dispatch_once_t onceToken;
|
||||||
|
dispatch_once(&onceToken, ^{
|
||||||
|
instance = [[TooltipController alloc] init];
|
||||||
|
});
|
||||||
return instance;
|
return instance;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1541,6 +1510,113 @@ NS_INLINE size_t max(size_t a, size_t b) { return a > b ? a : b; }
|
||||||
gCurrentCandidateController.visible = YES;
|
gCurrentCandidateController.visible = YES;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#pragma mark - User phrases
|
||||||
|
|
||||||
|
- (NSString *)_currentMarkedText
|
||||||
|
{
|
||||||
|
if (_builder->markerCursorIndex() < 0) {
|
||||||
|
return @"";
|
||||||
|
}
|
||||||
|
if (!_bpmfReadingBuffer->isEmpty()) {
|
||||||
|
return @"";
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t begin = min(_builder->markerCursorIndex(), _builder->cursorIndex());
|
||||||
|
size_t end = max(_builder->markerCursorIndex(), _builder->cursorIndex());
|
||||||
|
// A phrase should contian at least two characters.
|
||||||
|
if (end - begin < 1) {
|
||||||
|
return @"";
|
||||||
|
}
|
||||||
|
|
||||||
|
NSRange range = NSMakeRange((NSInteger)begin, (NSInteger)(end - begin));
|
||||||
|
NSString *selectedText = [_composingBuffer substringWithRange:range];
|
||||||
|
return selectedText;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (NSString *)_currentMarkedTextAndReadings
|
||||||
|
{
|
||||||
|
if (_builder->markerCursorIndex() < 0) {
|
||||||
|
return @"";
|
||||||
|
}
|
||||||
|
if (!_bpmfReadingBuffer->isEmpty()) {
|
||||||
|
return @"";
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t begin = min(_builder->markerCursorIndex(), _builder->cursorIndex());
|
||||||
|
size_t end = max(_builder->markerCursorIndex(), _builder->cursorIndex());
|
||||||
|
// A phrase should contian at least two characters.
|
||||||
|
if (end - begin < 2) {
|
||||||
|
return @"";
|
||||||
|
}
|
||||||
|
|
||||||
|
NSRange range = NSMakeRange((NSInteger)begin, (NSInteger)(end - begin));
|
||||||
|
NSString *selectedText = [_composingBuffer substringWithRange:range];
|
||||||
|
NSMutableString *string = [[NSMutableString alloc] init];
|
||||||
|
[string appendString:selectedText];
|
||||||
|
[string appendString:@" "];
|
||||||
|
NSMutableArray *readingsArray = [[NSMutableArray alloc] init];
|
||||||
|
vector<std::string> v = _builder->readingsAtRange(begin, end);
|
||||||
|
for(vector<std::string>::iterator it_i=v.begin(); it_i!=v.end(); ++it_i) {
|
||||||
|
[readingsArray addObject:[NSString stringWithUTF8String:it_i->c_str()]];
|
||||||
|
}
|
||||||
|
[string appendString:[readingsArray componentsJoinedByString:@"-"]];
|
||||||
|
return string;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (BOOL)_writeUserPhrase
|
||||||
|
{
|
||||||
|
NSString *currentMarkedPhrase = [self _currentMarkedTextAndReadings];
|
||||||
|
if (![currentMarkedPhrase length]) {
|
||||||
|
return NO;
|
||||||
|
}
|
||||||
|
|
||||||
|
return [LanguageModelManager writeUserPhrase:currentMarkedPhrase];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)_showCurrentMarkedTextTooltipWithClient:(id)client
|
||||||
|
{
|
||||||
|
NSString *text = [self _currentMarkedText];
|
||||||
|
NSInteger length = text.length;
|
||||||
|
if (!length) {
|
||||||
|
[self _hideTooltip];
|
||||||
|
}
|
||||||
|
else if (length == 1) {
|
||||||
|
NSString *messsage = [NSString stringWithFormat:NSLocalizedString(@"You are now selecting \"%@\". You can add a phrase with two or more characters.", @""), text];
|
||||||
|
[self _showTooltip:messsage client:client];
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
NSString *messsage = [NSString stringWithFormat:NSLocalizedString(@"You are now selecting \"%@\". Press enter to add a new phrase.", @""), text];
|
||||||
|
[self _showTooltip:messsage client:client];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)_showTooltip:(NSString *)tooltip client:(id)client
|
||||||
|
{
|
||||||
|
NSRect lineHeightRect = NSMakeRect(0.0, 0.0, 16.0, 16.0);
|
||||||
|
|
||||||
|
NSInteger cursor = _latestReadingCursor;
|
||||||
|
if (cursor == [_composingBuffer length] && cursor != 0) {
|
||||||
|
cursor--;
|
||||||
|
}
|
||||||
|
|
||||||
|
// some apps (e.g. Twitter for Mac's search bar) handle this call incorrectly, hence the try-catch
|
||||||
|
@try {
|
||||||
|
[client attributesForCharacterIndex:cursor lineHeightRectangle:&lineHeightRect];
|
||||||
|
}
|
||||||
|
@catch (NSException *exception) {
|
||||||
|
NSLog(@"%@", exception);
|
||||||
|
}
|
||||||
|
|
||||||
|
[[McBopomofoInputMethodController tooltipController] showTooltip:tooltip atPoint:lineHeightRect.origin];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)_hideTooltip
|
||||||
|
{
|
||||||
|
if ([McBopomofoInputMethodController tooltipController].window.isVisible) {
|
||||||
|
[[McBopomofoInputMethodController tooltipController] hide];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#pragma mark - Misc menu items
|
#pragma mark - Misc menu items
|
||||||
|
|
||||||
- (void)showPreferences:(id)sender
|
- (void)showPreferences:(id)sender
|
||||||
|
|
Loading…
Reference in New Issue