mirror of
https://github.com/cappuccino/cappuccino.git
synced 2026-08-25 04:57:03 +00:00
209 lines
6.6 KiB
Plaintext
209 lines
6.6 KiB
Plaintext
/*
|
|
* _CPAutocompleteMenu.j
|
|
* AppKit
|
|
*
|
|
* Created by Alexander Ljungberg on May 10, 2012.
|
|
* Copyright 2012, Alexander Ljungberg. All rights reserved.
|
|
*
|
|
* This library is free software; you can redistribute it and/or
|
|
* modify it under the terms of the GNU Lesser General Public
|
|
* License as published by the Free Software Foundation; either
|
|
* version 2.1 of the License, or (at your option) any later version.
|
|
*
|
|
* This library is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
* Lesser General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU Lesser General Public
|
|
* License along with this library; if not, write to the Free Software
|
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
|
*/
|
|
|
|
@import <Foundation/CPObject.j>
|
|
|
|
@import "CPTextField.j"
|
|
@import "_CPMenuWindow.j"
|
|
|
|
|
|
/*!
|
|
An "autocomplete" menu displayed by a text field.
|
|
*/
|
|
@implementation _CPAutocompleteMenu : CPObject
|
|
{
|
|
CPTextField textField @accessors;
|
|
CPArray contentArray @accessors;
|
|
|
|
CPView contentView @accessors;
|
|
CPScrollView scrollView;
|
|
CPTableView tableView;
|
|
|
|
CPTimer _showCompletionsTimer;
|
|
}
|
|
|
|
- (id)initWithTextField:(CPTextField)aTextField
|
|
{
|
|
if (self = [super init])
|
|
{
|
|
textField = aTextField;
|
|
|
|
contentView = [[CPView alloc] initWithFrame:CGRectMakeZero()];
|
|
|
|
[contentView setBackgroundColor:[_CPMenuWindow backgroundColorForBackgroundStyle:_CPMenuWindowPopUpBackgroundStyle]];
|
|
|
|
scrollView = [[CPScrollView alloc] initWithFrame:CGRectMakeZero()];
|
|
[scrollView setAutohidesScrollers:YES];
|
|
[scrollView setHasHorizontalScroller:NO];
|
|
[contentView addSubview:scrollView];
|
|
|
|
tableView = [[CPTableView alloc] initWithFrame:CPRectMakeZero()];
|
|
|
|
var tableColumn = [CPTableColumn new];
|
|
[tableColumn setResizingMask:CPTableColumnAutoresizingMask];
|
|
[tableView addTableColumn:tableColumn];
|
|
|
|
[tableView setDataSource:self];
|
|
[tableView setDelegate:self];
|
|
[tableView setAllowsMultipleSelection:NO];
|
|
[tableView setHeaderView:nil];
|
|
[tableView setCornerView:nil];
|
|
[tableView setRowHeight:30.0];
|
|
[tableView setGridStyleMask:CPTableViewSolidHorizontalGridLineMask];
|
|
[tableView setBackgroundColor:[CPColor clearColor]];
|
|
[tableView setGridColor:[CPColor colorWithRed:242.0 / 255.0 green:243.0 / 255.0 blue:245.0 / 255.0 alpha:1.0]];
|
|
|
|
[scrollView setDocumentView:tableView];
|
|
}
|
|
|
|
return self;
|
|
}
|
|
|
|
/*!
|
|
Set an array of strings to use as the available completions.
|
|
*/
|
|
- (void)setContentArray:(CPArray)anArray
|
|
{
|
|
contentArray = anArray;
|
|
|
|
[tableView reloadData];
|
|
}
|
|
|
|
- (void)setIndexOfSelectedItem:(int)anIndex
|
|
{
|
|
[tableView selectRowIndexes:[CPIndexSet indexSetWithIndex:anIndex] byExtendingSelection:NO];
|
|
[tableView scrollRowToVisible:anIndex];
|
|
}
|
|
|
|
- (int)indexOfSelectedItem
|
|
{
|
|
return [tableView selectedRow];
|
|
}
|
|
|
|
- (CPString)selectedItem
|
|
{
|
|
return contentArray ? contentArray[[tableView selectedRow]] : nil;
|
|
}
|
|
|
|
- (void)layoutSubviews
|
|
{
|
|
// TODO
|
|
// The autocompletion menu should be underneath the current token, it should at least be wide enough to fit the widest
|
|
// option but no wider than the width of the token field. It might stick out on the right side, so that if the token
|
|
// is small enough to fit on the right side the menu might extend a full token field width more into space on the right
|
|
// side. It should not stick out outside of the screen. The height should be the smallest possible to fit all options
|
|
// or at most ~307px (based on Cocoa). If the options don't fit horizontally they should be truncated with an ellipsis.
|
|
|
|
var frame = [textField frame];
|
|
|
|
// Correctly size the tableview
|
|
// FIXME Horizontal scrolling will not work because we are not actually looking at the content to set the width for the table column
|
|
[[[tableView tableColumns] firstObject] setWidth:[[scrollView contentView] frame].size.width];
|
|
|
|
// Manually sizeToFit because CPTableView's sizeToFit doesn't work properly
|
|
var frameOrigin = [textField convertPoint:[textField bounds].origin toView:[contentView superview]],
|
|
newFrame = CGRectMake(frameOrigin.x, frameOrigin.y + frame.size.height, CPRectGetWidth([textField bounds]), 92.0);
|
|
[contentView setFrame:newFrame];
|
|
[scrollView setFrame:CGRectInset([contentView bounds], 1.0, 1.0)];
|
|
}
|
|
|
|
- (void)_showCompletions:(CPTimer)timer
|
|
{
|
|
var indexOfSelectedItem = [self indexOfSelectedItem];
|
|
|
|
[self setContentArray:[textField _completionsForSubstring:[textField _inputElement].value indexOfToken:0 indexOfSelectedItem:indexOfSelectedItem]];
|
|
|
|
// TODO Support indexOfSelectedItem. Always 0 right now.
|
|
[self setIndexOfSelectedItem:indexOfSelectedItem];
|
|
|
|
[textField setThemeState:CPThemeStateAutocompleting];
|
|
[contentView setHidden:NO];
|
|
|
|
[self layoutSubviews];
|
|
}
|
|
|
|
- (void)_delayedShowCompletions
|
|
{
|
|
var completionDelay = 0.5;
|
|
|
|
if ([textField respondsToSelector:@selector(completionDelay)])
|
|
completionDelay = [textField completionDelay];
|
|
|
|
_showCompletionsTimer = [CPTimer scheduledTimerWithTimeInterval:completionDelay
|
|
target:self
|
|
selector:@selector(_showCompletions:)
|
|
userInfo:nil
|
|
repeats:NO];
|
|
}
|
|
|
|
- (void)_hideCompletions
|
|
{
|
|
[_showCompletionsTimer invalidate];
|
|
_showCompletionsTimer = nil;
|
|
|
|
[textField unsetThemeState:CPThemeStateAutocompleting];
|
|
[contentView setHidden:YES];
|
|
[self layoutSubviews];
|
|
}
|
|
|
|
- (void)selectNext
|
|
{
|
|
var index = [self indexOfSelectedItem] + 1;
|
|
|
|
if (index >= [contentArray count])
|
|
return;
|
|
|
|
[self setIndexOfSelectedItem:index];
|
|
}
|
|
|
|
- (void)selectPrevious
|
|
{
|
|
var index = [self indexOfSelectedItem] - 1;
|
|
|
|
if (index < 0)
|
|
return;
|
|
|
|
[self setIndexOfSelectedItem:index];
|
|
}
|
|
|
|
- (int)numberOfRowsInTableView:(CPTableView)tableView
|
|
{
|
|
return [contentArray count];
|
|
}
|
|
|
|
- (void)tableView:(CPTableView)tableView objectValueForTableColumn:(CPTableColumn)tableColumn row:(int)row
|
|
{
|
|
return [contentArray objectAtIndex:row];
|
|
}
|
|
|
|
- (void)tableViewSelectionDidChange:(CPNotification)notification
|
|
{
|
|
// FIXME
|
|
// make sure a mouse click in the tableview doesn't steal first responder state
|
|
window.setTimeout(function()
|
|
{
|
|
[[contentView window] makeFirstResponder:textField];
|
|
}, 2.0);
|
|
}
|
|
|
|
@end
|