mirror of
https://github.com/cappuccino/cappuccino.git
synced 2026-09-10 20:57:11 +00:00
716 lines
22 KiB
Plaintext
716 lines
22 KiB
Plaintext
/*
|
|
* _CPPopUpList.j
|
|
* AppKit
|
|
*
|
|
* Created by Aparajita Fishman.
|
|
* Copyright (c) 2011, Intalio, Inc.
|
|
*
|
|
* 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 "CPTableView.j"
|
|
|
|
|
|
/*!
|
|
Notification sent when the list is about to pop up. \c object is the _CPPopUpList.
|
|
*/
|
|
_CPPopUpListWillPopUpNotification = @"_CPPopUpListWillPopUpNotification";
|
|
|
|
/*!
|
|
Notification sent when the list is about to be dismissed. \c object is the _CPPopUpList.
|
|
*/
|
|
_CPPopUpListWillDismissNotification = @"_CPPopUpListWillDismissNotification";
|
|
|
|
/*!
|
|
Notification sent when the list is dismissed. \c object is the _CPPopUpList.
|
|
*/
|
|
_CPPopUpListDidDismissNotification = @"_CPPopUpListDidDismissNotification";
|
|
|
|
/*!
|
|
Notification sent when the selection of the list changes. \c object is the _CPPopUpList.
|
|
*/
|
|
_CPPopUpListDidDismissNotification = @"_CPPopUpListDidDismissNotification";
|
|
|
|
/*!
|
|
Notification sent when the list is dismissed. \c object is the _CPPopUpList.
|
|
*/
|
|
_CPPopUpListDidDismissNotification = @"_CPPopUpListDidDismissNotification";
|
|
|
|
/*!
|
|
Notification sent by when an item is selected. \c object is the _CPPopUpList.
|
|
When this is received the list has already been dismissed and the dismiss notification has been sent.
|
|
*/
|
|
_CPPopUpListItemWasClickedNotification = @"_CPPopUpListItemWasClickedNotification";
|
|
|
|
/*!
|
|
@ignore
|
|
|
|
The minimum number of items that must be visible below the related field.
|
|
If less than this number would be completely visible, and there is room for this many complete items
|
|
above the field, the list is displayed above.
|
|
*/
|
|
var ListMinimumItems = 3;
|
|
|
|
/*! @ignore */
|
|
var ListColumnIdentifier = @"1";
|
|
|
|
|
|
/*!
|
|
This class is a controller for a panel that can pop up and display a scrollable list of items in a CPTableView.
|
|
For tables that display single-line rows of scalar data, no subclassing should be necessary.
|
|
|
|
The delegate of this class MUST implement the following methods:
|
|
|
|
numberOfItems The number of items the list should display
|
|
numberOfVisibleItems The maximum number of items to display at once
|
|
objectValueForItemAtIndex: Retrieves an object value for an item in the range 0..(numberOfItems - 1)
|
|
|
|
Objects of this class send the following notifications:
|
|
|
|
_CPPopUpListWillPopUpNotification
|
|
_CPPopUpListWillDismissNotification
|
|
_CPPopUpListDidDismissNotification
|
|
_CPPopUpListItemWasClickedNotification
|
|
*/
|
|
@implementation _CPPopUpList : CPObject
|
|
{
|
|
_CPPopUpListDelegate _delegate;
|
|
BOOL _itemWasClicked;
|
|
BOOL _listWasClicked;
|
|
int _listWidth;
|
|
_CPPopUpPanel _panel @accessors(readonly, property=panel);
|
|
CPScrollView _scrollView @accessors(readonly, property=scrollView);
|
|
_CPPopUpTableView _tableView @accessors(readonly, property=tableView);
|
|
CPTableColumn _tableColumn;
|
|
}
|
|
|
|
/*!
|
|
Creates a pop up list of choices which will display relative to the given rect in base coordinates.
|
|
|
|
@param aDelegate The object that usually is controlling this list.
|
|
*/
|
|
- (id)initWithDelegate:(_CPPopUpListDelegate)aDelegate
|
|
{
|
|
self = [super init];
|
|
|
|
if (self)
|
|
{
|
|
_delegate = aDelegate;
|
|
_itemWasClicked = NO;
|
|
_listWasClicked = NO;
|
|
_listWidth = 0;
|
|
|
|
_tableView = [self makeTableView];
|
|
|
|
// Start with a default size, we will resize it later
|
|
frame = CGRectMake(0, 0, 200, 200);
|
|
|
|
_tableColumn = [[CPTableColumn alloc] initWithIdentifier:ListColumnIdentifier];
|
|
[_tableColumn setWidth:CGRectGetWidth(frame) - [CPScroller scrollerWidth]];
|
|
[_tableColumn setResizingMask:CPTableColumnAutoresizingMask];
|
|
[_tableView addTableColumn:_tableColumn];
|
|
|
|
_scrollView = [self makeScrollViewWithFrame:CGRectMake(0, 0, CGRectGetWidth(frame), CGRectGetHeight(frame))];
|
|
[_scrollView setDocumentView:_tableView];
|
|
|
|
// This has to be done after setDocumentView so that the table knows which scroll view to update
|
|
[_tableView setHeaderView:nil];
|
|
|
|
_panel = [self makeListPanelWithFrame:frame];
|
|
[[_panel contentView] addSubview:_scrollView];
|
|
[_panel setInitialFirstResponder:_tableView];
|
|
|
|
if ([_delegate numberOfItems] > 0)
|
|
[_tableView selectRowIndexes:[CPIndexSet indexSetWithIndex:0] byExtendingSelection:NO];
|
|
else
|
|
[_tableView setEnabled:NO];
|
|
|
|
[_scrollView scrollToBeginningOfDocument:nil];
|
|
|
|
[self finalizeTableView:_tableView];
|
|
}
|
|
|
|
return self;
|
|
}
|
|
|
|
/*!
|
|
Create and configure the panel containing the table view.
|
|
Subclasses should override this (and usually call super first)
|
|
if they want to customize the list panel.
|
|
*/
|
|
- (CPPanel)makeListPanelWithFrame:(CGRect)aFrame
|
|
{
|
|
var panel = [[_CPPopUpPanel alloc] initWithContentRect:aFrame styleMask:CPBorderlessWindowMask];
|
|
|
|
[panel setTitle:@""];
|
|
[panel setFloatingPanel:YES];
|
|
[panel setBecomesKeyOnlyIfNeeded:YES];
|
|
[panel setHasShadow:YES];
|
|
[panel setShadowStyle:CPMenuWindowShadowStyle];
|
|
[panel setDelegate:self];
|
|
|
|
return panel;
|
|
}
|
|
|
|
/*!
|
|
Create and configure the table view. Subclasses should use \ref finalizeTableView:.
|
|
*/
|
|
- (_CPPopUpTableView)makeTableView
|
|
{
|
|
[self removeTableViewObservers];
|
|
|
|
var table = [[_CPPopUpTableView alloc] initWithFrame:CGRectMakeZero()];
|
|
|
|
[table setDelegate:self];
|
|
[table setDataSource:self];
|
|
[table setColumnAutoresizingStyle:CPTableViewLastColumnOnlyAutoresizingStyle];
|
|
[table setUsesAlternatingRowBackgroundColors:NO];
|
|
[table setAllowsMultipleSelection:NO];
|
|
[table setIntercellSpacing:CGSizeMake(3, 2)];
|
|
[table setTarget:self];
|
|
[table setDoubleAction:@selector(tableViewClickAction:)];
|
|
[table setAction:@selector(tableViewClickAction:)];
|
|
[table setRowHeight:[self rowHeightForTableView:table]];
|
|
|
|
return table;
|
|
}
|
|
|
|
- (void)removeTableViewObservers
|
|
{
|
|
if (_tableView)
|
|
{
|
|
var defaultCenter = [CPNotificationCenter defaultCenter];
|
|
|
|
[defaultCenter removeObserver:self name:CPTableViewSelectionIsChangingNotification object:_tableView];
|
|
[defaultCenter removeObserver:self name:CPTableViewSelectionDidChangeNotification object:_tableView];
|
|
}
|
|
}
|
|
|
|
/*!
|
|
If subclasses want to configure the table view after it has been
|
|
completely configured, for example to set a custom data view,
|
|
this is the place. Such customization can also be done by an
|
|
observer of _CPPopUpListListWillDisplayNotification.
|
|
*/
|
|
- (void)finalizeTableView:(CPTableView)aTableView
|
|
{
|
|
}
|
|
|
|
/*!
|
|
Creates and configures the scroll view containing the table view.
|
|
Subclasses should override this (and usually call super first)
|
|
if they want to customize the scroll view.
|
|
*/
|
|
- (CPScrollView)makeScrollViewWithFrame:(CGRect)aFrame
|
|
{
|
|
var scroll = [[CPScrollView alloc] initWithFrame:aFrame];
|
|
|
|
[scroll setBorderType:CPLineBorder];
|
|
[scroll setAutohidesScrollers:NO];
|
|
[scroll setHasVerticalScroller:YES];
|
|
[scroll setHasHorizontalScroller:NO];
|
|
[scroll setLineScroll:[_tableView rowHeight]];
|
|
[scroll setVerticalPageScroll:0.0];
|
|
|
|
return scroll;
|
|
}
|
|
|
|
/*!
|
|
Returns the desired width of the list.
|
|
*/
|
|
- (int)listWidth
|
|
{
|
|
return _listWidth;
|
|
}
|
|
|
|
/*!
|
|
Sets the desired width of the list for the next call to \ref showListForfield:relativeTo:.
|
|
Note that the actual display width may be larger if the given width is less than the width of the associated
|
|
field.
|
|
*/
|
|
- (void)setListWidth:(int)width
|
|
{
|
|
_listWidth = width;
|
|
}
|
|
|
|
- (void)setFont:(CPFont)aFont
|
|
{
|
|
var oldDataView = [_tableColumn dataView],
|
|
newDataView = [CPTextField new];
|
|
|
|
[newDataView setFont:aFont];
|
|
[newDataView setAlignment:[oldDataView alignment]];
|
|
[_tableColumn setDataView:newDataView];
|
|
|
|
// Force the data view cache to flush
|
|
[_tableView reloadData];
|
|
}
|
|
|
|
- (void)setAlignment:(CPTextAlignment)alignment
|
|
{
|
|
var oldDataView = [_tableColumn dataView],
|
|
newDataView = [CPTextField new];
|
|
|
|
[newDataView setAlignment:alignment];
|
|
[newDataView setFont:[oldDataView font]];
|
|
[_tableColumn setDataView:newDataView];
|
|
|
|
// Force the data view cache to flush
|
|
[_tableView reloadData];
|
|
}
|
|
|
|
/*!
|
|
Pop up the list if it is not already visible.
|
|
If it is not visible, a _CPPopUpListWillPopUpNotification will be sent.
|
|
|
|
@param aRect A rect (in \c aView coordinates) to display relative to
|
|
@param aView The view whose coordinate system \c aRect is in
|
|
@param offset How far to offset the list from \c aRect
|
|
*/
|
|
- (void)popUpRelativeToRect:(CGRect)aRect view:(CPView)aView offset:(int)offset
|
|
{
|
|
if ([_panel isVisible])
|
|
return;
|
|
|
|
var rowRect = [_tableView rectOfRow:[self numberOfRowsInTableView:_tableView] - 1],
|
|
frame = CGRectMake(0, 0, MAX(_listWidth, CGRectGetWidth(aRect)), CGRectGetMaxY(rowRect));
|
|
|
|
// Place the frame relative to aRect and constrain it to the screen bounds
|
|
frame = [self constrain:frame relativeToRect:aRect view:aView offset:offset];
|
|
|
|
[_panel setFrame:frame];
|
|
[_scrollView setFrameSize:CGSizeMakeCopy(frame.size)];
|
|
[self scrollItemAtIndexToTop:[_tableView selectedRow]];
|
|
|
|
[self listWillPopUp];
|
|
|
|
[_panel orderFront:nil];
|
|
}
|
|
|
|
/*!
|
|
Return a frame in platform window base coordinates such that the list, when displayed, will show at least ListMinimumItems
|
|
items completely on screen. Normally the list should be displayed below \c aRect, but if there is not room
|
|
for at least ListMinimumItems items, an attempt should be made to display that many
|
|
items above \c aRect. If the minimum cannot be displayed on top, whichever direction can display more items
|
|
is chosen.
|
|
*/
|
|
- (CGRect)constrain:(CGRect)aFrame relativeToRect:(CGRect)aRect view:(CPView)aView offset:(int)offset
|
|
{
|
|
// Convert from the view's coordinate system to the coordinate system of the primary platform window
|
|
var baseOrigin = [aView convertPointToBase:aRect.origin],
|
|
windowOrigin = [[aView window] convertBaseToPlatformWindow:baseOrigin],
|
|
rowHeight = [self rowHeightForTableView:_tableView] + [_tableView intercellSpacing].height,
|
|
|
|
// Be sure to clip the number of displayed rows to what the field wants
|
|
numberOfRows = MIN([self numberOfRowsInTableView:_tableView], [_delegate numberOfVisibleItems]),
|
|
|
|
// Add 2 to height for border
|
|
frame = CGRectMake(windowOrigin.x, windowOrigin.y + CGRectGetHeight(aRect) + offset, MAX(_listWidth, CGRectGetWidth(aFrame)), (rowHeight * numberOfRows) + 2),
|
|
|
|
// Get the bottom coordinate of the frame and the platform window
|
|
bottomFrame = CGRectMakeCopy(frame),
|
|
bottom = CGRectGetMaxY(bottomFrame),
|
|
viewRect = [[CPPlatformWindow primaryPlatformWindow] visibleFrame],
|
|
visibleBottom = CGRectGetMaxY(viewRect),
|
|
bottomVisibleRows = numberOfRows;
|
|
|
|
// Make sure it will fit in the screen. If not, reduce the number of items till we reach the minimum.
|
|
while (bottom > visibleBottom && bottomVisibleRows >= ListMinimumItems)
|
|
{
|
|
bottom -= rowHeight;
|
|
bottomFrame.size.height -= rowHeight;
|
|
--bottomVisibleRows;
|
|
}
|
|
|
|
if (bottom >= visibleBottom || bottomVisibleRows < ListMinimumItems)
|
|
{
|
|
// The minimum number of items will not fit, try above
|
|
var topFrame = CGRectMakeCopy(frame);
|
|
|
|
topFrame.origin.y = windowOrigin.y - offset - CGRectGetHeight(topFrame);
|
|
|
|
var visibleTop = CGRectGetMinY(viewRect),
|
|
topVisibleRows = numberOfRows;
|
|
|
|
while (topFrame.origin.y <= visibleTop && topVisibleRows >= ListMinimumItems)
|
|
{
|
|
topFrame.origin.y += rowHeight;
|
|
topFrame.size.height -= rowHeight;
|
|
--topVisibleRows;
|
|
}
|
|
|
|
// If there is room on the top or it can display more than at the bottom, show it there
|
|
if ((topFrame.origin.y > visibleTop && topVisibleRows >= ListMinimumItems) || topVisibleRows > bottomVisibleRows)
|
|
frame = topFrame;
|
|
else
|
|
frame = bottomFrame;
|
|
}
|
|
else
|
|
frame = bottomFrame;
|
|
|
|
return frame;
|
|
}
|
|
|
|
/*!
|
|
Returns whether the list is currently visible.
|
|
*/
|
|
- (BOOL)isVisible
|
|
{
|
|
return [_panel isVisible];
|
|
}
|
|
|
|
/*!
|
|
Subclasses MUST call this method just before the list is about to display.
|
|
*/
|
|
- (void)listWillPopUp
|
|
{
|
|
[[CPNotificationCenter defaultCenter] postNotificationName:_CPPopUpListWillPopUpNotification object:self];
|
|
}
|
|
|
|
/*!
|
|
Select the next item in the list if there one. If there is currently no selected item,
|
|
the first item is selected. Returns YES if the selection changed.
|
|
*/
|
|
- (BOOL)selectNextItem
|
|
{
|
|
if (![_tableView isEnabled])
|
|
return NO;
|
|
|
|
var row = [_tableView selectedRow];
|
|
|
|
if (row < ([_delegate numberOfItems] - 1))
|
|
return [self selectRow:++row];
|
|
else
|
|
return NO;
|
|
}
|
|
|
|
/*!
|
|
Select the previous item in the list. If there is currently no selected item,
|
|
nothing happens. Returns YES if the selection changed.
|
|
*/
|
|
- (BOOL)selectPreviousItem
|
|
{
|
|
if (![_tableView isEnabled])
|
|
return NO;
|
|
|
|
var row = [_tableView selectedRow];
|
|
|
|
if (row > 0)
|
|
return [self selectRow:--row];
|
|
else
|
|
return NO;
|
|
}
|
|
|
|
/*!
|
|
Scroll the list down one page.
|
|
*/
|
|
- (void)scrollPageDown
|
|
{
|
|
[_scrollView scrollPageDown:nil];
|
|
}
|
|
|
|
/*!
|
|
Scroll the list up one page.
|
|
*/
|
|
- (void)scrollPageUp
|
|
{
|
|
[_scrollView scrollPageUp:nil];
|
|
}
|
|
|
|
/*!
|
|
Scroll to the top of the list.
|
|
*/
|
|
- (void)scrollToTop
|
|
{
|
|
[_scrollView scrollToBeginningOfDocument:nil];
|
|
}
|
|
|
|
/*!
|
|
Scroll to the bottom of the list.
|
|
*/
|
|
- (void)scrollToBottom
|
|
{
|
|
[_scrollView scrollToEndOfDocument:nil];
|
|
}
|
|
|
|
- (BOOL)selectRow:(int)row
|
|
{
|
|
if (row === [_tableView selectedRow])
|
|
return NO;
|
|
|
|
var indexes = row >= 0 ? [CPIndexSet indexSetWithIndex:row] : [CPIndexSet indexSet];
|
|
|
|
[_tableView selectRowIndexes:indexes byExtendingSelection:NO];
|
|
|
|
if (row >= 0)
|
|
{
|
|
[_tableView scrollRowToVisible:row];
|
|
return YES;
|
|
}
|
|
else
|
|
return NO;
|
|
}
|
|
|
|
- (void)scrollItemAtIndexToTop:(int)row
|
|
{
|
|
var rect = [_tableView rectOfRow:row];
|
|
|
|
[[_tableView superview] scrollToPoint:rect.origin];
|
|
}
|
|
|
|
/*!
|
|
Returns the selected value as a single-line string. If no value is selected,
|
|
returns nil.
|
|
*/
|
|
- (CPString)selectedStringValue
|
|
{
|
|
var row = [_tableView selectedRow];
|
|
|
|
return (row >= 0) ? [self stringValueForObjectValue:[_delegate objectValueForItemAtIndex:row] row:row] : nil;
|
|
}
|
|
|
|
/*!
|
|
Returns whether an item in the list was clicked since it was opened.
|
|
If there are no items, \ref itemWasClicked will always return NO.
|
|
*/
|
|
- (BOOL)itemWasClicked
|
|
{
|
|
return _itemWasClicked && ([_delegate numberOfItems] > 0);
|
|
}
|
|
|
|
/*!
|
|
Sets whether an item in the list was clicked since it was opened.
|
|
If there are no items, \ref itemWasClicked will always return NO.
|
|
|
|
Subclasses will usually want to set this in the mouseDown:
|
|
of the control.
|
|
*/
|
|
- (void)setItemWasClicked:(BOOL)flag
|
|
{
|
|
_itemWasClicked = ([_delegate numberOfItems] > 0) && flag;
|
|
}
|
|
|
|
/*!
|
|
Returns whether any view in the list was clicked since it was opened.
|
|
If there are no items, \ref listWasClicked will always return NO.
|
|
*/
|
|
- (BOOL)listWasClicked
|
|
{
|
|
return _listWasClicked && ([_delegate numberOfItems] > 0);
|
|
}
|
|
|
|
/*!
|
|
Sets whether any view in the list was clicked since it was opened.
|
|
If there are no items, \ref listWasClicked will always return NO.
|
|
|
|
Subclasses will usually want to use a subclass of CPPanel and override
|
|
sendEvent: to set this flag when the event type is CPLeftMouseDown
|
|
or CPRightMouseDown. This is distinct from \ref itemWasClicked because,
|
|
for example, a scroller in the list may be clicked without clicking an
|
|
item in the list.
|
|
*/
|
|
- (void)setListWasClicked:(BOOL)flag
|
|
{
|
|
_listWasClicked = ([_delegate numberOfItems] > 0) && flag;
|
|
}
|
|
|
|
/*!
|
|
Close the list if it is currently visible. If it is visible,
|
|
a CPComboBoxWillDismissNotification will be sent. If the
|
|
list is being closed after an item was clicked, the close
|
|
is delayed slightly so the user can briefly see the clicked row
|
|
get highlighted.
|
|
*/
|
|
- (void)close
|
|
{
|
|
if (![_panel isVisible])
|
|
return;
|
|
|
|
if ([self listWasClicked])
|
|
{
|
|
[self setListWasClicked:NO];
|
|
|
|
// Wait until we get through the run loop and delay a little
|
|
// so the user can briefly see the clicked row get highlighted.
|
|
if ([self itemWasClicked])
|
|
{
|
|
[self setItemWasClicked:NO];
|
|
[CPTimer scheduledTimerWithTimeInterval:0.1 target:self selector:@selector(closeListAfterItemClick) userInfo:nil repeats:NO];
|
|
return;
|
|
}
|
|
}
|
|
|
|
[[CPNotificationCenter defaultCenter] postNotificationName:_CPPopUpListWillDismissNotification object:self];
|
|
[_panel close];
|
|
[[CPNotificationCenter defaultCenter] postNotificationName:_CPPopUpListDidDismissNotification object:self];
|
|
}
|
|
|
|
/*!
|
|
Close the list after an item was clicked.
|
|
*/
|
|
- (void)closeListAfterItemClick
|
|
{
|
|
[self close];
|
|
[[CPNotificationCenter defaultCenter] postNotificationName:_CPPopUpListItemWasClickedNotification object:self];
|
|
}
|
|
|
|
/*!
|
|
Returns the desired row height for the table view.
|
|
Subclasses should override this if they want something other than the default.
|
|
*/
|
|
- (int)rowHeightForTableView:(CPTableView)aTableView
|
|
{
|
|
return [aTableView rowHeight];
|
|
}
|
|
|
|
/*!
|
|
Returns a value to display for a single row in the list. Subclasses should override
|
|
this if the table data needs to be converted or formatted in some way to be displayed.
|
|
If there are no search results, an empty string is returned.
|
|
If subclasses use a data representation other than CPStrings, they must override
|
|
this method and return the appropriate data when there are no search results.
|
|
|
|
If the table uses a custom data view, this method should return a value suitable
|
|
for sending to the setObjectValue: method of the data view.
|
|
|
|
@param aValue Table data for the given row
|
|
@param aRow The row being displayed
|
|
@return A value to be displayed in the list
|
|
*/
|
|
- (id)displayValueForObjectValue:(id)aValue row:(int)aRow
|
|
{
|
|
return aValue || @"";
|
|
}
|
|
|
|
/*!
|
|
Returns a single-line string for use in an autocomplete field. Subclasses should override
|
|
this if the row data is not convertable to a simple string, and return the data as a single-line string.
|
|
|
|
@param aValue Table data to be converted to a string
|
|
@param aRow The row whose data is being converted
|
|
@return A value to be displayed in the autocomplete field
|
|
*/
|
|
- (CPString)stringValueForObjectValue:(id)aValue row:(int)aRow
|
|
{
|
|
return String(aValue);
|
|
}
|
|
|
|
- (void)tableViewClickAction:(id)sender
|
|
{
|
|
[self close];
|
|
}
|
|
|
|
@end
|
|
|
|
|
|
var _CPPopUpListFieldKey = @"_CPPopUpListDelegateKey",
|
|
_CPPopUpListListWidthKey = @"_CPPopUpListListWidthKey",
|
|
_CPPopUpListListPanelKey = @"_CPPopUpListListPanelKey",
|
|
_CPPopUpListScrollViewKey = @"_CPPopUpListScrollViewKey",
|
|
_CPPopUpListTableViewKey = @"_CPPopUpListTableViewKey";
|
|
|
|
@implementation _CPPopUpList (CPCoding)
|
|
|
|
- (id)initWithCoder:(CPCoder)aCoder
|
|
{
|
|
self = [super initWithCoder:aCoder];
|
|
|
|
if (self)
|
|
{
|
|
_listWasClicked = NO;
|
|
_itemWasClicked = NO;
|
|
|
|
_delegate = [aCoder decodeObjectForKey:_CPPopUpListDelegateKey];
|
|
_listWidth = [aCoder decodeIntForKey:_CPPopUpListListWidthKey];
|
|
_panel = [aCoder decodeObjectForKey:_CPPopUpListListPanelKey];
|
|
_scrollView = [aCoder decodeObjectForKey:_CPPopUpListScrollViewKey];
|
|
_tableView = [aCoder decodeObjectForKey:_CPPopUpListTableViewKey];
|
|
_tableColumn = [_tableView tableColumnWithIdentifier:ListColumnIdentifier];
|
|
[_scrollView setDocumentView:_tableView];
|
|
}
|
|
|
|
return self;
|
|
}
|
|
|
|
- (void)encodeWithCoder:(CPCoder)aCoder
|
|
{
|
|
[super encodeWithCoder:aCoder];
|
|
|
|
[aCoder encodeObject:_delegate forKey:_CPPopUpListDelegateKey];
|
|
[aCoder encodeObject:_listWidth forKey:_CPPopUpListListWidthKey];
|
|
[aCoder encodeObject:_panel forKey:_CPPopUpListListPanelKey];
|
|
[aCoder encodeObject:_scrollView forKey:_CPPopUpListScrollViewKey];
|
|
[aCoder encodeObject:_tableView forKey:_CPPopUpListTableViewKey];
|
|
}
|
|
|
|
@end
|
|
|
|
@implementation _CPPopUpList (CPTableViewDataSource)
|
|
|
|
- (int)numberOfRowsInTableView:(id)aTableView
|
|
{
|
|
return MAX([_delegate numberOfItems], 1);
|
|
}
|
|
|
|
- (id)tableView:(id)aTableView objectValueForTableColumn:(CPTableColumn)aColumn row:(int)aRow
|
|
{
|
|
return [self displayValueForObjectValue:[_delegate objectValueForItemAtIndex:aRow] row:aRow];
|
|
}
|
|
|
|
@end
|
|
|
|
@implementation _CPPopUpTableView : CPTableView
|
|
|
|
- (void)mouseDown:(CPEvent)anEvent
|
|
{
|
|
if (![self isEnabled])
|
|
return;
|
|
|
|
[[self delegate] setItemWasClicked:YES];
|
|
[super mouseDown:anEvent];
|
|
}
|
|
|
|
/*
|
|
We always want the autocomplete to have focus
|
|
*/
|
|
- (BOOL)acceptsFirstResponder
|
|
{
|
|
return NO;
|
|
}
|
|
|
|
/*!
|
|
Return the column used for the list.
|
|
*/
|
|
- (CPTableColumn)listColumn
|
|
{
|
|
return _tableColumn;
|
|
}
|
|
|
|
@end
|
|
|
|
@implementation _CPPopUpPanel : CPPanel
|
|
|
|
- (void)sendEvent:(CPEvent)anEvent
|
|
{
|
|
var type = [anEvent type];
|
|
|
|
if (type === CPLeftMouseDown || type === CPRightMouseDown)
|
|
[[self delegate] setListWasClicked:YES];
|
|
|
|
return [super sendEvent:anEvent];
|
|
}
|
|
|
|
@end
|