From 59530ed13642b1fc447de64c9d639ef224a30630 Mon Sep 17 00:00:00 2001 From: LEOYoon-Tsaw Date: Sun, 16 Aug 2020 01:03:35 -0400 Subject: [PATCH 1/8] Fix a bug when using multiple screens. --- SquirrelPanel.m | 31 ++++++++++++++++++------------- 1 file changed, 18 insertions(+), 13 deletions(-) diff --git a/SquirrelPanel.m b/SquirrelPanel.m index b473fe41f..7b4e1a10a 100644 --- a/SquirrelPanel.m +++ b/SquirrelPanel.m @@ -129,6 +129,7 @@ @implementation SquirrelPanel { NSParagraphStyle *_paragraphStyle; NSParagraphStyle *_preeditParagraphStyle; NSSize preeditSize; + NSRect screenRect; NSString *_statusMessage; NSTimer *_statusTimer; @@ -213,7 +214,23 @@ - (instancetype)init { return self; } +- (void)getCurrentScreen { + // get current screen + screenRect = [NSScreen mainScreen].frame; + NSArray *screens = [NSScreen screens]; + + NSUInteger i; + for (i = 0; i < screens.count; ++i) { + NSRect rect = [screens[i] frame]; + if (NSPointInRect(_position.origin, rect)) { + screenRect = rect; + break; + } + } +} + - (void)show { + [self getCurrentScreen]; NSRect windowRect; // in vertical mode, the width and height are interchanged if (_vertical) { @@ -225,18 +242,6 @@ - (void)show { } windowRect.origin = NSMakePoint(NSMinX(_position), NSMinY(_position) - kOffsetHeight - NSHeight(windowRect)); - // fit in current screen - NSRect screenRect = [NSScreen mainScreen].frame; - NSArray *screens = [NSScreen screens]; - - NSUInteger i; - for (i = 0; i < screens.count; ++i) { - NSRect rect = [screens[i] frame]; - if (NSPointInRect(_position.origin, rect)) { - screenRect = rect; - break; - } - } if (_vertical) { // if the height is too large, it's hard to read, so need to put limit on the height. @@ -297,6 +302,7 @@ - (void)showPreedit:(NSString *)preedit comments:(NSArray *)comments labels:(NSString *)labels highlighted:(NSUInteger)index { + [self getCurrentScreen]; NSUInteger numCandidates = candidates.count; if (numCandidates || (preedit && preedit.length)) { _statusMessage = nil; @@ -367,7 +373,6 @@ - (void)showPreedit:(NSString *)preedit NSUInteger candidateStartPos = 0; // needed to calculate line-broken candidate box size. - NSRect screenRect = [NSScreen mainScreen].frame; CGFloat height = 0.0; // preedit From a028f3ce185335991faad07d0066e45881e90736 Mon Sep 17 00:00:00 2001 From: LEOYoon-Tsaw Date: Sun, 16 Aug 2020 01:49:37 -0400 Subject: [PATCH 2/8] Optimize window height calculation in vertical mode --- SquirrelPanel.m | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/SquirrelPanel.m b/SquirrelPanel.m index 7b4e1a10a..cfefdddef 100644 --- a/SquirrelPanel.m +++ b/SquirrelPanel.m @@ -246,12 +246,11 @@ - (void)show { if (_vertical) { // if the height is too large, it's hard to read, so need to put limit on the height. if (windowRect.size.height > NSHeight(screenRect) / 3) { - windowRect.origin.y += windowRect.size.height - NSHeight(screenRect) / 3; windowRect.size.height = NSHeight(screenRect) / 3; NSSize innerSize = NSMakeSize(windowRect.size.height - _view.edgeInset.height * 2, windowRect.size.width - _view.edgeInset.width * 2); - NSRect newTextBoundingRect = [_view.text boundingRectWithSize:innerSize - options:NSStringDrawingUsesLineFragmentOrigin]; - windowRect.size.width = newTextBoundingRect.size.height + _view.edgeInset.height * 2; + NSRect newTextBoundingRect = [_view.text boundingRectWithSize:innerSize options:NSStringDrawingUsesLineFragmentOrigin]; + windowRect.size = NSMakeSize(newTextBoundingRect.size.height + _view.edgeInset.height * 2, newTextBoundingRect.size.width + _view.edgeInset.width * 2); + windowRect.origin.y = NSMinY(_position) - kOffsetHeight - NSHeight(windowRect); } windowRect.origin.x -= windowRect.size.width; if (!_inlinePreedit) { @@ -558,10 +557,8 @@ - (void)showPreedit:(NSString *)preedit height = NSHeight(screenRect) / 3 - _view.edgeInset.width * 2; } fullSize = [text boundingRectWithSize:NSMakeSize(height, 0.0) options:NSStringDrawingUsesLineFragmentOrigin].size; - highlightedRect.size.width = height + _view.edgeInset.width * 2; - } else { - highlightedRect.size.width = fullSize.width + _view.edgeInset.width * 2; } + highlightedRect.size.width = fullSize.width + _view.edgeInset.width * 2; highlightedRect.origin.y += fullSize.height + _view.edgeInset.width; if (index == 0) { From bae106b72c6d08e192bfdab90a454afd2c176a99 Mon Sep 17 00:00:00 2001 From: Chen Gong Date: Sun, 16 Aug 2020 16:08:37 +0800 Subject: [PATCH 3/8] set rime context option "_vertical" to change arrrow key behaviour --- SquirrelInputController.m | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/SquirrelInputController.m b/SquirrelInputController.m index da06d0d6a..cdddea6f0 100644 --- a/SquirrelInputController.m +++ b/SquirrelInputController.m @@ -153,6 +153,11 @@ -(BOOL)processKey:(int)rime_keycode modifiers:(int)rime_modifiers if (is_horizontal_mode != rime_get_api()->get_option(_session, "_horizontal")) { rime_get_api()->set_option(_session, "_horizontal", is_horizontal_mode); } + // in vertical mode, arrow keys may behave differently. + Bool is_vertical_mode = NSApp.squirrelAppDelegate.panel.vertical; + if (is_vertical_mode != rime_get_api()->get_option(_session, "_vertical")) { + rime_get_api()->set_option(_session, "_vertical", is_vertical_mode); + } BOOL handled = (BOOL)rime_get_api()->process_key(_session, rime_keycode, rime_modifiers); //NSLog(@"rime_keycode: 0x%x, rime_modifiers: 0x%x, handled = %d", rime_keycode, rime_modifiers, handled); From 8bf4e56f284ff04ee8bdde15957cfe472d5cb155 Mon Sep 17 00:00:00 2001 From: Chen Gong Date: Sun, 16 Aug 2020 22:34:53 +0800 Subject: [PATCH 4/8] feat: support select_labels --- SquirrelInputController.m | 15 ++++++++++++--- SquirrelPanel.h | 2 +- SquirrelPanel.m | 39 ++++++++++++++++++++++++++++++--------- 3 files changed, 43 insertions(+), 13 deletions(-) diff --git a/SquirrelInputController.m b/SquirrelInputController.m index cdddea6f0..1ef7efd32 100644 --- a/SquirrelInputController.m +++ b/SquirrelInputController.m @@ -401,7 +401,7 @@ -(void)showPanelWithPreedit:(NSString*)preedit caretPos:(NSUInteger)caretPos candidates:(NSArray*)candidates comments:(NSArray*)comments - labels:(NSString*)labels + labels:(NSArray*)labels highlighted:(NSUInteger)index { //NSLog(@"showPanelWithPreedit:...:"); @@ -526,9 +526,18 @@ -(void)rimeUpdate [comments addObject:@""]; } } - NSString* labels = @""; + NSArray* labels; if (ctx.menu.select_keys) { - labels = @(ctx.menu.select_keys); + labels = @[@(ctx.menu.select_keys)]; + } else if (ctx.select_labels) { + NSMutableArray *selectLabels = [NSMutableArray array]; + for (i = 0; i < ctx.menu.page_size; ++i) { + char* label_str = ctx.select_labels[i]; + [selectLabels addObject:@(label_str)]; + } + labels = selectLabels; + } else { + labels = @[]; } [self showPanelWithPreedit:(_inlinePreedit ? nil : preeditText) selRange:selRange diff --git a/SquirrelPanel.h b/SquirrelPanel.h index 500961653..447641eda 100644 --- a/SquirrelPanel.h +++ b/SquirrelPanel.h @@ -16,7 +16,7 @@ caretPos:(NSUInteger)caretPos candidates:(NSArray*)candidates comments:(NSArray*)comments - labels:(NSString*)labels + labels:(NSArray*)labels highlighted:(NSUInteger)index; -(void)hide; diff --git a/SquirrelPanel.m b/SquirrelPanel.m index cfefdddef..8dbaa33e3 100644 --- a/SquirrelPanel.m +++ b/SquirrelPanel.m @@ -299,7 +299,7 @@ - (void)showPreedit:(NSString *)preedit caretPos:(NSUInteger)caretPos candidates:(NSArray *)candidates comments:(NSArray *)comments - labels:(NSString *)labels + labels:(NSArray *)labels highlighted:(NSUInteger)index { [self getCurrentScreen]; NSUInteger numCandidates = candidates.count; @@ -428,10 +428,20 @@ - (void)showPreedit:(NSString *)preedit for (i = 0; i < candidates.count; ++i) { NSMutableAttributedString *line = [[NSMutableAttributedString alloc] init]; - // default: 1. 2. 3... custom: A. B. C... - char label_character = (i < labels.length) ? [labels characterAtIndex:i] - : ((i + 1) % 10 + '0'); - + NSString *labelString; + if (labels.count > 1 && i < labels.count) { + labelFormat = [labelFormat stringByReplacingOccurrencesOfString:@"%c" withString:@"%@"]; + labelString = [NSString stringWithFormat:labelFormat, labels[i]]; + } else if (labels.count == 1 && i < [labels[0] length]) { + // custom: A. B. C... + char labelCharacter = [labels[0] characterAtIndex:i]; + labelString = [NSString stringWithFormat:labelFormat, labelCharacter]; + } else { + // default: 1. 2. 3... + char labelDigit = (i + 1) % 10 + '0'; + labelString = [NSString stringWithFormat:labelFormat, labelDigit]; + } + NSDictionary *attrs = (i == index) ? _highlightedAttrs : _attrs; NSDictionary *labelAttrs = (i == index) ? _labelHighlightedAttrs : _labelAttrs; @@ -442,8 +452,7 @@ - (void)showPreedit:(NSString *)preedit if (labelRange.location != NSNotFound) { [line appendAttributedString: [[NSAttributedString alloc] - initWithString:[NSString stringWithFormat:labelFormat, - label_character] + initWithString:labelString attributes:labelAttrs]]; // get the label size for indent if (_vertical) { @@ -461,10 +470,22 @@ - (void)showPreedit:(NSString *)preedit [line addAttribute:NSWritingDirectionAttributeName value:@[@0] range:NSMakeRange(candidateStart, line.length-candidateStart)]; if (labelRange2.location != NSNotFound) { + NSString *labelString2; + if (labels.count > 1 && i < labels.count) { + labelFormat2 = [labelFormat2 stringByReplacingOccurrencesOfString:@"%c" withString:@"%@"]; + labelString2 = [NSString stringWithFormat:labelFormat2, labels[i]]; + } else if (labels.count == 1 && i < [labels[0] length]) { + // custom: A. B. C... + char labelCharacter = [labels[0] characterAtIndex:i]; + labelString2 = [NSString stringWithFormat:labelFormat2, labelCharacter]; + } else { + // default: 1. 2. 3... + char labelDigit = (i + 1) % 10 + '0'; + labelString2 = [NSString stringWithFormat:labelFormat2, labelDigit]; + } [line appendAttributedString: [[NSAttributedString alloc] - initWithString:[NSString stringWithFormat:labelFormat2, - label_character] + initWithString:labelString2 attributes:labelAttrs]]; } From b5b59673d09385c466cc4d2001042e7a67480e57 Mon Sep 17 00:00:00 2001 From: LEOYoon-Tsaw Date: Sun, 16 Aug 2020 10:58:52 -0400 Subject: [PATCH 5/8] Fix bug where label is not properly aligned --- SquirrelPanel.m | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/SquirrelPanel.m b/SquirrelPanel.m index 8dbaa33e3..e99a882df 100644 --- a/SquirrelPanel.m +++ b/SquirrelPanel.m @@ -135,15 +135,16 @@ @implementation SquirrelPanel { NSTimer *_statusTimer; } -- (void)convertToVerticalGlyph:(NSMutableAttributedString *)originalText { +- (void)convertToVerticalGlyph:(NSMutableAttributedString *)originalText inRange:(NSRange)stringRange { // Use the width of the character to determin if they should be upright in vertical writing mode. // Adjust font base line for better alignment. const NSAttributedString *cjkChar = [[NSAttributedString alloc] initWithString:@"漢" attributes:_attrs]; const NSRect cjkRect = [cjkChar boundingRectWithSize:NSMakeSize(0, 0) options:NULL]; const NSAttributedString *hangulChar = [[NSAttributedString alloc] initWithString:@"한" attributes:_attrs]; const NSSize hangulSize = [hangulChar boundingRectWithSize:NSMakeSize(0, 0) options:NULL].size; - NSUInteger i = 0; - while (i < originalText.length) { + stringRange = [originalText.string rangeOfComposedCharacterSequencesForRange:stringRange]; + NSUInteger i = stringRange.location; + while (i < stringRange.location+stringRange.length) { NSRange range = [originalText.string rangeOfComposedCharacterSequenceAtIndex:i]; i = range.location + range.length; NSRect charRect = [[originalText attributedSubstringFromRange:range] boundingRectWithSize:NSMakeSize(0, 0) options:NULL]; @@ -400,7 +401,7 @@ - (void)showPreedit:(NSString *)preedit [text appendAttributedString:line]; if (_vertical) { - [self convertToVerticalGlyph:text]; + [self convertToVerticalGlyph:text inRange:NSMakeRange(0, line.length)]; } [text addAttribute:NSParagraphStyleAttributeName value:_preeditParagraphStyle @@ -456,7 +457,7 @@ - (void)showPreedit:(NSString *)preedit attributes:labelAttrs]]; // get the label size for indent if (_vertical) { - [self convertToVerticalGlyph:line]; + [self convertToVerticalGlyph:line inRange:NSMakeRange(0, line.length)]; labelWidth = [line boundingRectWithSize:NSMakeSize(0.0, 0.0) options:NSStringDrawingUsesLineFragmentOrigin].size.width; } } @@ -509,7 +510,7 @@ - (void)showPreedit:(NSString *)preedit } if (_vertical) { - [self convertToVerticalGlyph:line]; + [self convertToVerticalGlyph:line inRange:NSMakeRange(candidateStart, line.length-candidateStart)]; } NSMutableParagraphStyle *paragraphStyleCandidate = [_paragraphStyle mutableCopy]; paragraphStyleCandidate.headIndent = labelWidth; From dd572d8eec62ccdc81890505dbaceca143b9dbb9 Mon Sep 17 00:00:00 2001 From: LEOYoon-Tsaw Date: Sun, 16 Aug 2020 11:16:31 -0400 Subject: [PATCH 6/8] Improve edge detection when hilighted corner radius is 0 --- SquirrelPanel.m | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/SquirrelPanel.m b/SquirrelPanel.m index e99a882df..b96753249 100644 --- a/SquirrelPanel.m +++ b/SquirrelPanel.m @@ -64,7 +64,7 @@ - (void)drawRect:(NSRect)dirtyRect { // setFrame rounds up floating point numbers in window bounds. // Add extra width and height to overcome rounding errors and ensure // highlighted area fully covers paddings near right and top edges. - const CGFloat ROUND_UP = 1; + const CGFloat ROUND_UP = 1.1; CGFloat corner = self.hilitedCornerRadius / 2; NSRect stripRect = self.highlightedRect; if (!_horizontal) { @@ -73,19 +73,19 @@ - (void)drawRect:(NSRect)dirtyRect { if (corner == 0) { // fill in small gaps between highlighted rect and the bounding rect. - if (NSMinX(stripRect) < FLT_EPSILON) { - stripRect.origin.x -= edgeWidth; - stripRect.size.width += edgeWidth; + if (NSMinX(stripRect) - ROUND_UP < NSMinX(dirtyRect)) { + stripRect.origin.x -= ROUND_UP; + stripRect.size.width += ROUND_UP; } - if (NSMaxX(stripRect) + edgeWidth + ROUND_UP > NSWidth(self.bounds)) { - stripRect.size.width += edgeWidth + ROUND_UP; + if (NSMaxX(stripRect) + ROUND_UP > NSMaxX(dirtyRect)) { + stripRect.size.width += ROUND_UP; } - if (NSMinY(stripRect) < FLT_EPSILON) { - stripRect.origin.y -= edgeHeight; - stripRect.size.height += edgeHeight; + if (NSMinY(stripRect) - ROUND_UP < NSMinY(dirtyRect)) { + stripRect.origin.y -= ROUND_UP; + stripRect.size.height += ROUND_UP; } - if (NSMaxY(stripRect) + edgeHeight + ROUND_UP > NSHeight(self.bounds)) { - stripRect.size.height += edgeHeight + ROUND_UP; + if (NSMaxY(stripRect) + ROUND_UP > NSMaxY(dirtyRect)) { + stripRect.size.height += ROUND_UP; } } else { // leave a small gap between highlighted rect and the bounding rect From 19bc95a0e90218054c8a7e7d7b2fd4928abe2a6e Mon Sep 17 00:00:00 2001 From: LEOYoon-Tsaw Date: Sun, 16 Aug 2020 23:28:02 -0400 Subject: [PATCH 7/8] Optimize Emoji alignment in vertical mode --- SquirrelPanel.m | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/SquirrelPanel.m b/SquirrelPanel.m index b96753249..77045896d 100644 --- a/SquirrelPanel.m +++ b/SquirrelPanel.m @@ -150,8 +150,8 @@ - (void)convertToVerticalGlyph:(NSMutableAttributedString *)originalText inRange NSRect charRect = [[originalText attributedSubstringFromRange:range] boundingRectWithSize:NSMakeSize(0, 0) options:NULL]; if ((charRect.size.width >= cjkRect.size.width) || (charRect.size.width >= hangulSize.width)) { [originalText addAttribute:NSVerticalGlyphFormAttributeName value:@(1) range:range]; - charRect = [[originalText attributedSubstringFromRange:range] boundingRectWithSize:NSMakeSize(0, 0) options:NULL]; - [originalText addAttribute:NSBaselineOffsetAttributeName value:@((cjkRect.size.height-charRect.size.height)/2+(cjkRect.origin.y-charRect.origin.y)+_view.baseOffset) range:range]; + NSRect uprightCharRect = [[originalText attributedSubstringFromRange:range] boundingRectWithSize:NSMakeSize(0, 0) options:NULL]; + [originalText addAttribute:NSBaselineOffsetAttributeName value:@((cjkRect.size.height - uprightCharRect.size.height)/2+(cjkRect.origin.y-uprightCharRect.origin.y)-(charRect.size.width-cjkChar.size.width)/2+_view.baseOffset) range:range]; } else { [originalText addAttribute:NSBaselineOffsetAttributeName value:@(_view.baseOffset) range:range]; } From 8f58be6075dada644098d630a3b4d61781d39866 Mon Sep 17 00:00:00 2001 From: LEOYoon-Tsaw Date: Mon, 17 Aug 2020 01:18:44 -0400 Subject: [PATCH 8/8] Avoid jumping window in vertical mode --- SquirrelPanel.m | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/SquirrelPanel.m b/SquirrelPanel.m index 77045896d..8ab5e27f5 100644 --- a/SquirrelPanel.m +++ b/SquirrelPanel.m @@ -251,7 +251,11 @@ - (void)show { NSSize innerSize = NSMakeSize(windowRect.size.height - _view.edgeInset.height * 2, windowRect.size.width - _view.edgeInset.width * 2); NSRect newTextBoundingRect = [_view.text boundingRectWithSize:innerSize options:NSStringDrawingUsesLineFragmentOrigin]; windowRect.size = NSMakeSize(newTextBoundingRect.size.height + _view.edgeInset.height * 2, newTextBoundingRect.size.width + _view.edgeInset.width * 2); + } + if (NSMidY(_position) / NSHeight(screenRect) >= 0.5) { windowRect.origin.y = NSMinY(_position) - kOffsetHeight - NSHeight(windowRect); + } else { + windowRect.origin.y = NSMaxY(_position) + kOffsetHeight; } windowRect.origin.x -= windowRect.size.width; if (!_inlinePreedit) { @@ -266,7 +270,11 @@ - (void)show { windowRect.origin.x = NSMinX(screenRect); } if (NSMinY(windowRect) < NSMinY(screenRect)) { - windowRect.origin.y = NSMaxY(_position) + kOffsetHeight; + if (_vertical) { + windowRect.origin.y = NSMinY(screenRect); + } else { + windowRect.origin.y = NSMaxY(_position) + kOffsetHeight; + } } if (NSMaxY(windowRect) > NSMaxY(screenRect)) { windowRect.origin.y = NSMaxY(screenRect) - NSHeight(windowRect); @@ -610,8 +618,9 @@ - (void)updateStatus:(NSString *)message { } - (void)showStatus:(NSString *)message { - NSAttributedString *text = [[NSAttributedString alloc] initWithString:message + NSMutableAttributedString *text = [[NSMutableAttributedString alloc] initWithString:message attributes:_commentAttrs]; + [self convertToVerticalGlyph:text inRange:NSMakeRange(0, text.length)]; [_view setText:text hilightedRect:NSZeroRect]; [self show];