vChewing-macOS/Source/CandidateUI/VTHorizontalCandidateContro...

252 lines
7.8 KiB
Objective-C

//
// VTHorizontalCandidateController.m
//
// Copyright (c) 2012 Lukhnos D. Liu (http://lukhnos.org)
//
// 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.
//
#import "VTHorizontalCandidateController.h"
#import "VTHorizontalCandidateView.h"
@interface VTHorizontalCandidateController (Private)
- (NSUInteger)pageCount;
- (void)layoutCandidateView;
- (void)pageButtonAction:(id)sender;
- (void)candidateViewMouseDidClick:(id)sender;
@end
@implementation VTHorizontalCandidateController
- (void)dealloc
{
[_candidateView release];
[_prevPageButton release];
[_nextPageButton release];
[super dealloc];
}
- (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] autorelease];
[panel setLevel:CGShieldingWindowLevel() + 1];
[panel setHasShadow:YES];
self = [self initWithWindow:panel];
if (self) {
contentRect.origin = NSMakePoint(0.0, 0.0);
_candidateView = [[VTHorizontalCandidateView alloc] initWithFrame:contentRect];
_candidateView.target = self;
_candidateView.action = @selector(candidateViewMouseDidClick:);
[[panel contentView] addSubview:_candidateView];
contentRect.size = NSMakeSize(36.0, 20.0);
_nextPageButton = [[NSButton alloc] initWithFrame:contentRect];
_prevPageButton = [[NSButton alloc] initWithFrame:contentRect];
[_nextPageButton setButtonType:NSMomentaryLightButton];
[_nextPageButton setBezelStyle:NSSmallSquareBezelStyle];
[_nextPageButton setTitle:@"»"];
[_nextPageButton setTarget:self];
[_nextPageButton setAction:@selector(pageButtonAction:)];
[_prevPageButton setButtonType:NSMomentaryLightButton];
[_prevPageButton setBezelStyle:NSSmallSquareBezelStyle];
[_prevPageButton setTitle:@"«"];
[_prevPageButton setTarget:self];
[_prevPageButton setAction:@selector(pageButtonAction:)];
[[panel contentView] addSubview:_nextPageButton];
[[panel contentView] addSubview:_prevPageButton];
}
return self;
}
- (void)reloadData
{
_candidateView.highlightedIndex = 0;
_currentPage = 0;
[self layoutCandidateView];
}
- (BOOL)showNextPage
{
if (_currentPage + 1 >= [self pageCount]) {
return NO;
}
_currentPage++;
_candidateView.highlightedIndex = 0;
[self layoutCandidateView];
return YES;
}
- (BOOL)showPreviousPage
{
if (_currentPage == 0) {
return NO;
}
_currentPage--;
_candidateView.highlightedIndex = 0;
[self layoutCandidateView];
return YES;
}
- (BOOL)highlightNextCandidate
{
NSUInteger currentIndex = self.selectedCandidateIndex;
if (currentIndex + 1 >= [_delegate candidateCountForController:self]) {
return NO;
}
self.selectedCandidateIndex = currentIndex + 1;
return YES;
}
- (BOOL)highlightPreviousCandidate
{
NSUInteger currentIndex = self.selectedCandidateIndex;
if (currentIndex == 0) {
return NO;
}
self.selectedCandidateIndex = currentIndex - 1;
return YES;
}
- (NSUInteger)candidateIndexAtKeyLabelIndex:(NSUInteger)index
{
NSUInteger result = _currentPage * [_keyLabels count] + index;
return result < [_delegate candidateCountForController:self] ? result : NSUIntegerMax;
}
- (NSUInteger)selectedCandidateIndex
{
return _currentPage * [_keyLabels count] + _candidateView.highlightedIndex;
}
- (void)setSelectedCandidateIndex:(NSUInteger)newIndex
{
NSUInteger keyLabelCount = [_keyLabels count];
if (newIndex < [_delegate candidateCountForController:self]) {
_currentPage = newIndex / keyLabelCount;
_candidateView.highlightedIndex = newIndex % keyLabelCount;
[self layoutCandidateView];
}
}
@end
@implementation VTHorizontalCandidateController (Private)
- (NSUInteger)pageCount
{
NSUInteger totalCount = [_delegate candidateCountForController:self];
NSUInteger keyLabelCount = [_keyLabels count];
return totalCount / keyLabelCount + ((totalCount % keyLabelCount) != 0 ? 1 : 0);
}
- (void)layoutCandidateView
{
[_candidateView setKeyLabelFont:_keyLabelFont candidateFont:_candidateFont];
NSMutableArray *candidates = [NSMutableArray array];
NSUInteger count = [_delegate candidateCountForController:self];
NSUInteger keyLabelCount = [_keyLabels count];
for (NSUInteger index = _currentPage * keyLabelCount, j = 0; index < count && j < keyLabelCount; index++, j++) {
[candidates addObject:[_delegate candidateController:self candidateAtIndex:index]];
}
[_candidateView setKeyLabels:_keyLabels displayedCandidates:candidates];
NSSize newSize = _candidateView.sizeForView;
NSRect frameRect = [_candidateView frame];
frameRect.size = newSize;
[_candidateView setFrame:frameRect];
if ([self pageCount] > 1) {
NSRect buttonRect = [_nextPageButton frame];
CGFloat spacing = 0.0;
if (newSize.height < 40.0) {
buttonRect.size.height = floor(newSize.height / 2);
}
else {
buttonRect.size.height = 20.0;
}
if (newSize.height >= 60.0) {
spacing = ceil(newSize.height * 0.1);
}
CGFloat buttonOriginY = (newSize.height - (buttonRect.size.height * 2.0 + spacing)) / 2.0;
buttonRect.origin = NSMakePoint(newSize.width + 8.0, buttonOriginY);
[_nextPageButton setFrame:buttonRect];
buttonRect.origin = NSMakePoint(newSize.width + 8.0, buttonOriginY + buttonRect.size.height + spacing);
[_prevPageButton setFrame:buttonRect];
[_nextPageButton setEnabled:(_currentPage + 1 < [self pageCount])];
[_prevPageButton setEnabled:(_currentPage != 0)];
newSize.width += 52.0;
[_nextPageButton setHidden:NO];
[_prevPageButton setHidden:NO];
}
else {
[_nextPageButton setHidden:YES];
[_prevPageButton setHidden:YES];
}
frameRect = [[self window] frame];
NSPoint topLeftPoint = NSMakePoint(frameRect.origin.x, frameRect.origin.y + frameRect.size.height);
frameRect.size = newSize;
frameRect.origin = NSMakePoint(topLeftPoint.x, topLeftPoint.y - frameRect.size.height);
[[self window] setFrame:frameRect display:YES];
[_candidateView setNeedsDisplay:YES];
}
- (void)pageButtonAction:(id)sender
{
if (sender == _nextPageButton) {
[self showNextPage];
}
else if (sender == _prevPageButton) {
[self showPreviousPage];
}
}
- (void)candidateViewMouseDidClick:(id)sender
{
[_delegate candidateController:self didSelectCandidateAtIndex:self.selectedCandidateIndex];
}
@end