候選窗格:美化 Voltaire 選字窗的美術風格。
- 之前的設計的審美是 macOS 10.5 Leopard 時代的,從 macOS 10.7 開始掉渣。由於威注音的最低系統需求早已至 macOS 10.12 Sierra,故盡量利用現代 macOS 系統的 Cocoa 桌面美術特性。
This commit is contained in:
parent
2935819d42
commit
317dcc3848
|
@ -55,10 +55,12 @@
|
|||
NSRect contentRect = NSMakeRect(128.0, 128.0, 0.0, 0.0);
|
||||
NSUInteger styleMask = NSBorderlessWindowMask | NSNonactivatingPanelMask;
|
||||
|
||||
NSPanel *panel = [[NSPanel alloc] initWithContentRect:contentRect styleMask:styleMask backing:NSBackingStoreBuffered defer:NO];
|
||||
NSWindow *panel = [[NSWindow alloc] initWithContentRect:contentRect styleMask:styleMask backing:NSBackingStoreBuffered defer:NO];
|
||||
[panel setLevel:kCGPopUpMenuWindowLevel];
|
||||
[panel setHasShadow:YES];
|
||||
|
||||
[panel setOpaque:NO];
|
||||
[panel setBackgroundColor:[NSColor clearColor]];
|
||||
|
||||
self = [self initWithWindow:panel];
|
||||
if (self) {
|
||||
contentRect.origin = NSMakePoint(0.0, 0.0);
|
||||
|
@ -67,20 +69,30 @@
|
|||
_candidateView.action = @selector(candidateViewMouseDidClick:);
|
||||
[[panel contentView] addSubview:_candidateView];
|
||||
|
||||
contentRect.size = NSMakeSize(36.0, 20.0);
|
||||
contentRect.size = NSMakeSize(16.0, 20.0);
|
||||
_nextPageButton = [[NSButton alloc] initWithFrame:contentRect];
|
||||
_prevPageButton = [[NSButton alloc] initWithFrame:contentRect];
|
||||
[_nextPageButton setButtonType:NSMomentaryLightButton];
|
||||
[_nextPageButton setBezelStyle:NSSmallSquareBezelStyle];
|
||||
[_nextPageButton setTitle:@"»"];
|
||||
[_nextPageButton setBezelStyle:NSBezelStyleSmallSquare];
|
||||
[_nextPageButton setTitle:@"↓"];
|
||||
[_nextPageButton setTarget:self];
|
||||
[_nextPageButton setAction:@selector(pageButtonAction:)];
|
||||
|
||||
[_nextPageButton setWantsLayer: YES];
|
||||
[_nextPageButton.layer setCornerRadius: 3];
|
||||
[_nextPageButton.layer setBorderColor: [NSColor clearColor].CGColor];
|
||||
[_nextPageButton.layer setBorderWidth: 3];
|
||||
[_nextPageButton.layer setBackgroundColor: [NSColor windowBackgroundColor].CGColor];
|
||||
|
||||
[_prevPageButton setButtonType:NSMomentaryLightButton];
|
||||
[_prevPageButton setBezelStyle:NSSmallSquareBezelStyle];
|
||||
[_prevPageButton setTitle:@"«"];
|
||||
[_prevPageButton setBezelStyle:NSBezelStyleSmallSquare];
|
||||
[_prevPageButton setTitle:@"↑"];
|
||||
[_prevPageButton setTarget:self];
|
||||
[_prevPageButton setAction:@selector(pageButtonAction:)];
|
||||
[_prevPageButton setWantsLayer: YES];
|
||||
[_prevPageButton.layer setCornerRadius: 3];
|
||||
[_prevPageButton.layer setBorderColor: [NSColor clearColor].CGColor];
|
||||
[_prevPageButton.layer setBorderWidth: 3];
|
||||
[_prevPageButton.layer setBackgroundColor: [NSColor windowBackgroundColor].CGColor];
|
||||
|
||||
[[panel contentView] addSubview:_nextPageButton];
|
||||
[[panel contentView] addSubview:_prevPageButton];
|
||||
|
|
|
@ -42,6 +42,11 @@ NS_INLINE CGFloat max(CGFloat a, CGFloat b) { return a > b ? a : b; }
|
|||
@synthesize action = _action;
|
||||
@synthesize target = _target;
|
||||
|
||||
static NSColor *colorFromRGBA(unsigned char r, unsigned char g, unsigned char b, unsigned char a)
|
||||
{
|
||||
return [NSColor colorWithDeviceRed:(r/255.0f) green:(g/255.0f) blue:(b/255.0f) alpha:(a/255.0f)];
|
||||
}
|
||||
|
||||
- (void)dealloc
|
||||
{
|
||||
_keyLabels = nil;
|
||||
|
@ -74,18 +79,20 @@ NS_INLINE CGFloat max(CGFloat a, CGFloat b) { return a > b ? a : b; }
|
|||
|
||||
- (void)setKeyLabelFont:(NSFont *)labelFont candidateFont:(NSFont *)candidateFont
|
||||
{
|
||||
NSColor *clrCandidateText = colorFromRGBA(233,233,233,255);
|
||||
NSColor *clrCandidateTextIndex = colorFromRGBA(233,233,233,213);
|
||||
NSMutableParagraphStyle *paraStyle = [[NSParagraphStyle defaultParagraphStyle] mutableCopy];
|
||||
[paraStyle setAlignment:NSCenterTextAlignment];
|
||||
|
||||
_keyLabelAttrDict = [NSDictionary dictionaryWithObjectsAndKeys:
|
||||
labelFont, NSFontAttributeName,
|
||||
paraStyle, NSParagraphStyleAttributeName,
|
||||
[NSColor blackColor], NSForegroundColorAttributeName,
|
||||
clrCandidateTextIndex, NSForegroundColorAttributeName,
|
||||
nil];
|
||||
_candidateAttrDict = [NSDictionary dictionaryWithObjectsAndKeys:
|
||||
candidateFont, NSFontAttributeName,
|
||||
paraStyle, NSParagraphStyleAttributeName,
|
||||
[NSColor textColor], NSForegroundColorAttributeName,
|
||||
clrCandidateText, NSForegroundColorAttributeName,
|
||||
nil];
|
||||
|
||||
CGFloat labelFontSize = [labelFont pointSize];
|
||||
|
@ -120,17 +127,21 @@ NS_INLINE CGFloat max(CGFloat a, CGFloat b) { return a > b ? a : b; }
|
|||
|
||||
- (void)drawRect:(NSRect)dirtyRect
|
||||
{
|
||||
NSColor *backgroundColor = [NSColor controlBackgroundColor];
|
||||
NSColor *darkGray = [NSColor colorWithDeviceWhite:0.7 alpha:1.0];
|
||||
NSColor *lightGray = [NSColor colorWithDeviceWhite:0.8 alpha:1.0];
|
||||
NSColor *clrCandidateSelectedBG = [NSColor alternateSelectedControlColor];
|
||||
NSColor *clrCandidateSelectedText = colorFromRGBA(233,233,233,255);
|
||||
NSColor *clrCandidateWindowBorder = colorFromRGBA(255,255,255,75);
|
||||
NSColor *clrCandidateWindowBG = colorFromRGBA(28,28,28,255);
|
||||
NSColor *clrCandidateBG = colorFromRGBA(28,28,28,255);
|
||||
|
||||
[self setWantsLayer: YES];
|
||||
[self.layer setBorderColor: [clrCandidateWindowBorder CGColor]];
|
||||
[self.layer setBorderWidth: 1];
|
||||
[self.layer setCornerRadius: 6];
|
||||
|
||||
NSRect bounds = [self bounds];
|
||||
|
||||
[backgroundColor setFill];
|
||||
[clrCandidateWindowBG setFill];
|
||||
[NSBezierPath fillRect:bounds];
|
||||
|
||||
[[NSColor darkGrayColor] setStroke];
|
||||
[NSBezierPath strokeLineFromPoint:NSMakePoint(bounds.size.width, 0.0) toPoint:NSMakePoint(bounds.size.width, bounds.size.height)];
|
||||
|
||||
NSUInteger count = [_elementWidths count];
|
||||
CGFloat accuWidth = 0.0;
|
||||
|
@ -138,27 +149,26 @@ NS_INLINE CGFloat max(CGFloat a, CGFloat b) { return a > b ? a : b; }
|
|||
for (NSUInteger index = 0; index < count; index++) {
|
||||
NSDictionary *activeCandidateAttr = _candidateAttrDict;
|
||||
CGFloat currentWidth = [[_elementWidths objectAtIndex:index] doubleValue];
|
||||
NSRect labelRect = NSMakeRect(accuWidth, 0.0, currentWidth, _keyLabelHeight);
|
||||
NSRect candidateRect = NSMakeRect(accuWidth, _keyLabelHeight + 1.0, currentWidth, _candidateTextHeight);
|
||||
NSRect labelRect = NSMakeRect(accuWidth, 0.0, currentWidth + 1.0, _keyLabelHeight + 1.0);
|
||||
NSRect candidateRect = NSMakeRect(accuWidth, _keyLabelHeight + 1.0, currentWidth + 1.0, _candidateTextHeight);
|
||||
|
||||
if (index == _highlightedIndex) {
|
||||
[darkGray setFill];
|
||||
[clrCandidateSelectedBG setFill];
|
||||
}
|
||||
else {
|
||||
[lightGray setFill];
|
||||
[clrCandidateBG setFill];
|
||||
}
|
||||
|
||||
[NSBezierPath fillRect:labelRect];
|
||||
[[_keyLabels objectAtIndex:index] drawInRect:labelRect withAttributes:_keyLabelAttrDict];
|
||||
|
||||
if (index == _highlightedIndex) {
|
||||
[[NSColor selectedTextBackgroundColor] setFill];
|
||||
|
||||
[clrCandidateSelectedBG setFill];
|
||||
activeCandidateAttr = [_candidateAttrDict mutableCopy];
|
||||
[(NSMutableDictionary *)activeCandidateAttr setObject:[NSColor selectedTextColor] forKey:NSForegroundColorAttributeName];
|
||||
[(NSMutableDictionary *)activeCandidateAttr setObject:clrCandidateSelectedText forKey:NSForegroundColorAttributeName];
|
||||
}
|
||||
else {
|
||||
[backgroundColor setFill];
|
||||
[clrCandidateBG setFill];
|
||||
}
|
||||
|
||||
[NSBezierPath fillRect:candidateRect];
|
||||
|
@ -186,8 +196,7 @@ NS_INLINE CGFloat max(CGFloat a, CGFloat b) { return a > b ? a : b; }
|
|||
result = index;
|
||||
break;
|
||||
}
|
||||
|
||||
accuWidth += currentWidth + 1.0;
|
||||
accuWidth += currentWidth;
|
||||
}
|
||||
|
||||
return result;
|
||||
|
|
|
@ -1,7 +1,12 @@
|
|||
//
|
||||
// VTVerticalCandidateController.m
|
||||
//
|
||||
// Copyright (c) 2012 Lukhnos D. Liu (http://lukhnos.org)
|
||||
// Copyright (c) 2021-2022 The vChewing Project.
|
||||
// Copyright (c) 2011-2022 The OpenVanilla Project.
|
||||
//
|
||||
// Contributors:
|
||||
// Lukhnos Liu (@lukhnos) @ OpenVanilla
|
||||
// Shiki Suen (ShikiSuen) @ vChewing
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person
|
||||
// obtaining a copy of this software and associated documentation
|
||||
|
@ -36,7 +41,12 @@ NS_INLINE CGFloat max(CGFloat a, CGFloat b) { return a > b ? a : b; }
|
|||
static const CGFloat kCandidateTextPadding = 24.0;
|
||||
static const CGFloat kCandidateTextLeftMargin = 8.0;
|
||||
|
||||
#if defined(__MAC_10_16)
|
||||
static NSColor *colorFromRGBA(unsigned char r, unsigned char g, unsigned char b, unsigned char a)
|
||||
{
|
||||
return [NSColor colorWithDeviceRed:(r/255.0f) green:(g/255.0f) blue:(b/255.0f) alpha:(a/255.0f)];
|
||||
}
|
||||
|
||||
#if defined(__MAC_11_0)
|
||||
static const CGFloat kCandidateTextPaddingWithMandatedTableViewPadding = 18.0;
|
||||
static const CGFloat kCandidateTextLeftMarginWithMandatedTableViewPadding = 0.0;
|
||||
#endif
|
||||
|
@ -60,29 +70,50 @@ static const CGFloat kCandidateTextLeftMarginWithMandatedTableViewPadding = 0.0;
|
|||
|
||||
- (id)init
|
||||
{
|
||||
NSRect contentRect = NSMakeRect(128.0, 128.0, 0.0, 0.0);
|
||||
NSUInteger styleMask = NSBorderlessWindowMask | NSNonactivatingPanelMask;
|
||||
|
||||
NSPanel *panel = [[NSPanel alloc] initWithContentRect:contentRect styleMask:styleMask backing:NSBackingStoreBuffered defer:NO];
|
||||
[panel setLevel:kCGPopUpMenuWindowLevel];
|
||||
[panel setHasShadow:YES];
|
||||
// NSColor *clrCandidateSelectedBG = [NSColor systemBlueColor];
|
||||
NSColor *clrCandidateSelectedText = [[NSColor whiteColor] colorWithAlphaComponent: 0.8];
|
||||
NSColor *clrCandidateWindowBorder = colorFromRGBA(255,255,255,75);
|
||||
NSColor *clrCandidateWindowBG = colorFromRGBA(28,28,28,255);
|
||||
// NSColor *clrCandidateBG = colorFromRGBA(28,28,28,255);
|
||||
|
||||
self = [self initWithWindow:panel];
|
||||
NSRect contentRect = NSMakeRect(128.0, 128.0, 0.0, 0.0);
|
||||
NSUInteger styleMask = NSBorderlessWindowMask | NSNonactivatingPanelMask;
|
||||
NSView *panelView = [[NSView alloc] initWithFrame:contentRect];
|
||||
NSWindow *panel = [[NSWindow alloc] initWithContentRect:contentRect styleMask:styleMask backing:NSBackingStoreBuffered defer:NO];
|
||||
[panel setLevel:kCGPopUpMenuWindowLevel];
|
||||
[panel setContentView: panelView];
|
||||
[panel setHasShadow:YES];
|
||||
[panel setOpaque:NO];
|
||||
[panel setBackgroundColor: [NSColor clearColor]];
|
||||
[panel setOpaque:false];
|
||||
[panelView setWantsLayer: YES];
|
||||
[panelView.layer setBorderColor: [clrCandidateWindowBorder CGColor]];
|
||||
[panelView.layer setBorderWidth: 1];
|
||||
[panelView.layer setCornerRadius: 6];
|
||||
[panelView.layer setBackgroundColor: [clrCandidateWindowBG CGColor]];
|
||||
|
||||
self = [self initWithWindow:panel];
|
||||
if (self) {
|
||||
contentRect.origin = NSMakePoint(0.0, 0.0);
|
||||
|
||||
NSRect stripRect = contentRect;
|
||||
stripRect.size.width = 10.0;
|
||||
_keyLabelStripView = [[VTVerticalKeyLabelStripView alloc] initWithFrame:stripRect];
|
||||
[_keyLabelStripView setWantsLayer: YES];
|
||||
[_keyLabelStripView.layer setBorderWidth: 0];
|
||||
|
||||
[[panel contentView] addSubview:_keyLabelStripView];
|
||||
|
||||
NSRect scrollViewRect = contentRect;
|
||||
scrollViewRect.origin.x = stripRect.size.width;
|
||||
scrollViewRect.size.width -= stripRect.size.width;
|
||||
scrollViewRect.size.width -= stripRect.size.width;
|
||||
|
||||
_scrollView = [[NSScrollView alloc] initWithFrame:scrollViewRect];
|
||||
|
||||
[_scrollView setAutohidesScrollers: YES];
|
||||
[_scrollView setWantsLayer: YES];
|
||||
[_scrollView.layer setBorderWidth: 0];
|
||||
[_scrollView setDrawsBackground:NO];
|
||||
|
||||
// >=10.7 only, elastic scroll causes some drawing issues with visible scroller, so we disable it
|
||||
if ([_scrollView respondsToSelector:@selector(setVerticalScrollElasticity:)]) {
|
||||
[_scrollView setVerticalScrollElasticity:NSScrollElasticityNone];
|
||||
|
@ -95,6 +126,8 @@ static const CGFloat kCandidateTextLeftMarginWithMandatedTableViewPadding = 0.0;
|
|||
NSTableColumn *column = [[NSTableColumn alloc] initWithIdentifier:@"candidate"];
|
||||
[column setDataCell:[[NSTextFieldCell alloc] init]];
|
||||
[column setEditable:NO];
|
||||
[column.dataCell setTextColor: clrCandidateSelectedText];
|
||||
// [column.dataCell setSelectionColor: clrCandidateSelectedBG];
|
||||
|
||||
_candidateTextPadding = kCandidateTextPadding;
|
||||
_candidateTextLeftMargin = kCandidateTextLeftMargin;
|
||||
|
@ -106,9 +139,11 @@ static const CGFloat kCandidateTextLeftMarginWithMandatedTableViewPadding = 0.0;
|
|||
[_tableView setAllowsEmptySelection:YES];
|
||||
[_tableView setDoubleAction:@selector(rowDoubleClicked:)];
|
||||
[_tableView setTarget:self];
|
||||
[_tableView setBackgroundColor:[NSColor clearColor]];
|
||||
[_tableView setGridColor:[NSColor clearColor]];
|
||||
|
||||
#if defined(__MAC_10_16)
|
||||
if (@available(macOS 10.16, *)) {
|
||||
#if defined(__MAC_11_0)
|
||||
if (@available(macOS 11.0, *)) {
|
||||
[_tableView setStyle:NSTableViewStyleFullWidth];
|
||||
_candidateTextPadding = kCandidateTextPaddingWithMandatedTableViewPadding;
|
||||
_candidateTextLeftMargin = kCandidateTextLeftMarginWithMandatedTableViewPadding;
|
||||
|
@ -394,8 +429,8 @@ static const CGFloat kCandidateTextLeftMarginWithMandatedTableViewPadding = 0.0;
|
|||
|
||||
NSScroller *verticalScroller = [_scrollView verticalScroller];
|
||||
[verticalScroller setControlSize:controlSize];
|
||||
[verticalScroller setScrollerStyle:NSScrollerStyleLegacy];
|
||||
scrollerWidth = [NSScroller scrollerWidthForControlSize:controlSize scrollerStyle:NSScrollerStyleLegacy];
|
||||
[verticalScroller setScrollerStyle:NSScrollerStyleOverlay];
|
||||
scrollerWidth = [NSScroller scrollerWidthForControlSize:controlSize scrollerStyle:NSScrollerStyleOverlay];
|
||||
}
|
||||
|
||||
_keyLabelStripView.keyLabelFont = _keyLabelFont;
|
||||
|
@ -416,9 +451,9 @@ static const CGFloat kCandidateTextLeftMarginWithMandatedTableViewPadding = 0.0;
|
|||
}
|
||||
|
||||
CGFloat rowSpacing = [_tableView intercellSpacing].height;
|
||||
CGFloat stripWidth = ceil(maxKeyLabelWidth * 1.20);
|
||||
CGFloat stripWidth = ceil(maxKeyLabelWidth);
|
||||
CGFloat tableViewStartWidth = ceil(_maxCandidateAttrStringWidth + scrollerWidth);;
|
||||
CGFloat windowWidth = stripWidth + 1.0 + tableViewStartWidth;
|
||||
CGFloat windowWidth = stripWidth + tableViewStartWidth;
|
||||
CGFloat windowHeight = keyLabelCount * (rowHeight + rowSpacing);
|
||||
|
||||
NSRect frameRect = [[self window] frame];
|
||||
|
@ -428,7 +463,7 @@ static const CGFloat kCandidateTextLeftMarginWithMandatedTableViewPadding = 0.0;
|
|||
frameRect.origin = NSMakePoint(topLeftPoint.x, topLeftPoint.y - frameRect.size.height);
|
||||
|
||||
[_keyLabelStripView setFrame:NSMakeRect(0.0, 0.0, stripWidth, windowHeight)];
|
||||
[_scrollView setFrame:NSMakeRect(stripWidth + 1.0, 0.0, tableViewStartWidth, windowHeight)];
|
||||
[_scrollView setFrame:NSMakeRect(stripWidth, 0.0, tableViewStartWidth, windowHeight)];
|
||||
[[self window] setFrame:frameRect display:NO];
|
||||
}
|
||||
@end
|
||||
|
|
|
@ -1,7 +1,12 @@
|
|||
//
|
||||
// VTVerticalKeyLabelStripView.h
|
||||
//
|
||||
// Copyright (c) 2012 Lukhnos D. Liu (http://lukhnos.org)
|
||||
// Copyright (c) 2021-2022 The vChewing Project.
|
||||
// Copyright (c) 2011-2022 The OpenVanilla Project.
|
||||
//
|
||||
// Contributors:
|
||||
// Lukhnos Liu (@lukhnos) @ OpenVanilla
|
||||
// Shiki Suen (ShikiSuen) @ vChewing
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person
|
||||
// obtaining a copy of this software and associated documentation
|
||||
|
@ -33,6 +38,11 @@
|
|||
@synthesize keyLabels = _keyLabels;
|
||||
@synthesize highlightedIndex = _highlightedIndex;
|
||||
|
||||
static NSColor *colorFromRGBA(unsigned char r, unsigned char g, unsigned char b, unsigned char a)
|
||||
{
|
||||
return [NSColor colorWithDeviceRed:(r/255.0f) green:(g/255.0f) blue:(b/255.0f) alpha:(a/255.0f)];
|
||||
}
|
||||
|
||||
- (void)dealloc
|
||||
{
|
||||
_keyLabelFont = nil;
|
||||
|
@ -57,7 +67,7 @@
|
|||
- (void)drawRect:(NSRect)dirtyRect
|
||||
{
|
||||
NSRect bounds = [self bounds];
|
||||
[[NSColor whiteColor] setFill];
|
||||
[[NSColor clearColor] setFill];
|
||||
[NSBezierPath fillRect:bounds];
|
||||
|
||||
NSUInteger count = [_keyLabels count];
|
||||
|
@ -66,22 +76,22 @@
|
|||
}
|
||||
|
||||
CGFloat cellHeight = bounds.size.height / count;
|
||||
NSColor *black = [NSColor blackColor];
|
||||
NSColor *darkGray = [NSColor colorWithDeviceWhite:0.7 alpha:1.0];
|
||||
NSColor *lightGray = [NSColor colorWithDeviceWhite:0.8 alpha:1.0];
|
||||
|
||||
NSColor *clrCandidateBG = colorFromRGBA(28,28,28,255);
|
||||
NSColor *clrCandidateTextIndex = colorFromRGBA(233,233,233,213);
|
||||
NSColor *clrCandidateSelectedBG = [NSColor alternateSelectedControlColor];
|
||||
|
||||
NSMutableParagraphStyle *style = [[NSParagraphStyle defaultParagraphStyle] mutableCopy];
|
||||
[style setAlignment:NSCenterTextAlignment];
|
||||
|
||||
NSDictionary *textAttr = [NSDictionary dictionaryWithObjectsAndKeys:
|
||||
_keyLabelFont, NSFontAttributeName,
|
||||
black, NSForegroundColorAttributeName,
|
||||
clrCandidateTextIndex, NSForegroundColorAttributeName,
|
||||
style, NSParagraphStyleAttributeName,
|
||||
nil];
|
||||
|
||||
for (NSUInteger index = 0; index < count; index++) {
|
||||
NSRect textRect = NSMakeRect(0.0, index * cellHeight + _labelOffsetY, bounds.size.width, cellHeight - _labelOffsetY);
|
||||
NSRect cellRect = NSMakeRect(0.0, index * cellHeight, bounds.size.width, cellHeight - 1);
|
||||
NSRect cellRect = NSMakeRect(0.0, index * cellHeight, bounds.size.width, cellHeight);
|
||||
|
||||
// fill in the last cell
|
||||
if (index + 1 >= count) {
|
||||
|
@ -89,10 +99,10 @@
|
|||
}
|
||||
|
||||
if (index == _highlightedIndex) {
|
||||
[darkGray setFill];
|
||||
[clrCandidateSelectedBG setFill];
|
||||
}
|
||||
else {
|
||||
[lightGray setFill];
|
||||
[clrCandidateBG setFill];
|
||||
}
|
||||
|
||||
[NSBezierPath fillRect:cellRect];
|
||||
|
|
Loading…
Reference in New Issue