From 32737e0b7225e55c27938ce889be2cc7388582e4 Mon Sep 17 00:00:00 2001 From: Aparajita Fishman Date: Fri, 6 Jul 2012 00:15:23 -0700 Subject: [PATCH] CPComboBox and CPTextField enhancements - Full Cocoa-compliant implementation of CPComboBox and CPComboBoxDelegate. - Better focus ring for CPTextField and all subclasses. - CPTextField and its subclasses draw disabled contents differently, per Cocoa. --- AppKit/AppKit.j | 1 + AppKit/CPComboBox.j | 1193 +++++++++++++++++ AppKit/CPKeyValueBinding.j | 2 + AppKit/CPTextField.j | 22 +- AppKit/CPTokenField.j | 43 +- .../Resources/combobox-bezel-center.png | Bin 0 -> 145 bytes .../combobox-bezel-disabled-center.png | Bin 0 -> 139 bytes .../combobox-bezel-disabled-left.png | Bin 0 -> 196 bytes .../combobox-bezel-disabled-right.png | Bin 0 -> 487 bytes .../combobox-bezel-focused-center.png | Bin 0 -> 162 bytes .../Resources/combobox-bezel-focused-left.png | Bin 0 -> 383 bytes .../combobox-bezel-focused-right.png | Bin 0 -> 700 bytes .../Aristo/Resources/combobox-bezel-left.png | Bin 0 -> 209 bytes .../combobox-bezel-no-border-center.png | Bin 0 -> 141 bytes ...mbobox-bezel-no-border-disabled-center.png | Bin 0 -> 141 bytes ...combobox-bezel-no-border-disabled-left.png | Bin 0 -> 211 bytes ...ombobox-bezel-no-border-disabled-right.png | Bin 0 -> 392 bytes ...ombobox-bezel-no-border-focused-center.png | Bin 0 -> 162 bytes .../combobox-bezel-no-border-focused-left.png | Bin 0 -> 373 bytes ...combobox-bezel-no-border-focused-right.png | Bin 0 -> 615 bytes .../combobox-bezel-no-border-left.png | Bin 0 -> 220 bytes .../combobox-bezel-no-border-right.png | Bin 0 -> 413 bytes .../Aristo/Resources/combobox-bezel-right.png | Bin 0 -> 527 bytes .../textfield-bezel-rounded-center.png | Bin 123 -> 141 bytes ...extfield-bezel-rounded-disabled-center.png | Bin 0 -> 141 bytes .../textfield-bezel-rounded-disabled-left.png | Bin 0 -> 436 bytes ...textfield-bezel-rounded-disabled-right.png | Bin 0 -> 473 bytes ...textfield-bezel-rounded-focused-center.png | Bin 149 -> 165 bytes .../textfield-bezel-rounded-focused-left.png | Bin 757 -> 837 bytes .../textfield-bezel-rounded-focused-right.png | Bin 735 -> 910 bytes .../textfield-bezel-rounded-left.png | Bin 559 -> 451 bytes .../textfield-bezel-rounded-right.png | Bin 531 -> 501 bytes .../Resources/textfield-bezel-square-0.png | Bin 1029 -> 155 bytes .../Resources/textfield-bezel-square-1.png | Bin 1004 -> 129 bytes .../Resources/textfield-bezel-square-2.png | Bin 1033 -> 161 bytes .../Resources/textfield-bezel-square-3.png | Bin 994 -> 117 bytes .../Resources/textfield-bezel-square-4.png | Bin 991 -> 109 bytes .../Resources/textfield-bezel-square-5.png | Bin 994 -> 115 bytes .../Resources/textfield-bezel-square-6.png | Bin 1034 -> 160 bytes .../Resources/textfield-bezel-square-7.png | Bin 997 -> 124 bytes .../Resources/textfield-bezel-square-8.png | Bin 1034 -> 161 bytes .../textfield-bezel-square-disabled-0.png | Bin 1029 -> 155 bytes .../textfield-bezel-square-disabled-1.png | Bin 1004 -> 129 bytes .../textfield-bezel-square-disabled-2.png | Bin 1031 -> 167 bytes .../textfield-bezel-square-disabled-3.png | Bin 994 -> 117 bytes .../textfield-bezel-square-disabled-4.png | Bin 991 -> 109 bytes .../textfield-bezel-square-disabled-5.png | Bin 994 -> 115 bytes .../textfield-bezel-square-disabled-6.png | Bin 1033 -> 153 bytes .../textfield-bezel-square-disabled-7.png | Bin 997 -> 124 bytes .../textfield-bezel-square-disabled-8.png | Bin 1034 -> 157 bytes .../textfield-bezel-square-focused-0.png | Bin 1112 -> 216 bytes .../textfield-bezel-square-focused-1.png | Bin 1012 -> 134 bytes .../textfield-bezel-square-focused-2.png | Bin 1132 -> 231 bytes .../textfield-bezel-square-focused-3.png | Bin 1012 -> 130 bytes .../textfield-bezel-square-focused-4.png | Bin 991 -> 109 bytes .../textfield-bezel-square-focused-5.png | Bin 1009 -> 129 bytes .../textfield-bezel-square-focused-6.png | Bin 1123 -> 229 bytes .../textfield-bezel-square-focused-7.png | Bin 1007 -> 134 bytes .../textfield-bezel-square-focused-8.png | Bin 1124 -> 218 bytes .../Resources/token-center-disabled.png | Bin 0 -> 153 bytes .../Aristo/Resources/token-left-disabled.png | Bin 0 -> 477 bytes .../Aristo/Resources/token-right-disabled.png | Bin 0 -> 498 bytes AppKit/Themes/Aristo/ThemeDescriptors.j | 230 +++- AppKit/_CPPopUpList.j | 849 ++++++++++++ AppKit/_CPPopUpListDataSource.j | 98 ++ Tests/Manual/CPComboBoxTest/AppController.j | 228 ++++ Tests/Manual/CPComboBoxTest/Info.plist | 10 + Tests/Manual/CPComboBoxTest/Jakefile | 94 ++ .../CPComboBoxTest/Resources/MainMenu.cib | 1 + .../CPComboBoxTest/Resources/MainMenu.xib | 828 ++++++++++++ .../CPComboBoxTest/Resources/spinner.gif | Bin 0 -> 1849 bytes Tests/Manual/CPComboBoxTest/index-debug.html | 103 ++ Tests/Manual/CPComboBoxTest/index.html | 78 ++ Tests/Manual/CPComboBoxTest/main.j | 18 + .../Manual/NewTextFieldBezel/AppController.j | 121 ++ Tests/Manual/NewTextFieldBezel/Info.plist | 12 + Tests/Manual/NewTextFieldBezel/Jakefile | 93 ++ .../NewTextFieldBezel/Resources/spinner.gif | Bin 0 -> 1849 bytes .../Manual/NewTextFieldBezel/index-debug.html | 107 ++ Tests/Manual/NewTextFieldBezel/index.html | 78 ++ Tests/Manual/NewTextFieldBezel/main.j | 18 + Tools/nib2cib/NSAppKit.j | 1 + Tools/nib2cib/NSComboBox.j | 105 ++ 83 files changed, 4252 insertions(+), 81 deletions(-) create mode 100644 AppKit/CPComboBox.j create mode 100644 AppKit/Themes/Aristo/Resources/combobox-bezel-center.png create mode 100644 AppKit/Themes/Aristo/Resources/combobox-bezel-disabled-center.png create mode 100644 AppKit/Themes/Aristo/Resources/combobox-bezel-disabled-left.png create mode 100644 AppKit/Themes/Aristo/Resources/combobox-bezel-disabled-right.png create mode 100644 AppKit/Themes/Aristo/Resources/combobox-bezel-focused-center.png create mode 100644 AppKit/Themes/Aristo/Resources/combobox-bezel-focused-left.png create mode 100644 AppKit/Themes/Aristo/Resources/combobox-bezel-focused-right.png create mode 100644 AppKit/Themes/Aristo/Resources/combobox-bezel-left.png create mode 100644 AppKit/Themes/Aristo/Resources/combobox-bezel-no-border-center.png create mode 100644 AppKit/Themes/Aristo/Resources/combobox-bezel-no-border-disabled-center.png create mode 100644 AppKit/Themes/Aristo/Resources/combobox-bezel-no-border-disabled-left.png create mode 100644 AppKit/Themes/Aristo/Resources/combobox-bezel-no-border-disabled-right.png create mode 100644 AppKit/Themes/Aristo/Resources/combobox-bezel-no-border-focused-center.png create mode 100644 AppKit/Themes/Aristo/Resources/combobox-bezel-no-border-focused-left.png create mode 100644 AppKit/Themes/Aristo/Resources/combobox-bezel-no-border-focused-right.png create mode 100644 AppKit/Themes/Aristo/Resources/combobox-bezel-no-border-left.png create mode 100644 AppKit/Themes/Aristo/Resources/combobox-bezel-no-border-right.png create mode 100644 AppKit/Themes/Aristo/Resources/combobox-bezel-right.png create mode 100644 AppKit/Themes/Aristo/Resources/textfield-bezel-rounded-disabled-center.png create mode 100644 AppKit/Themes/Aristo/Resources/textfield-bezel-rounded-disabled-left.png create mode 100644 AppKit/Themes/Aristo/Resources/textfield-bezel-rounded-disabled-right.png create mode 100644 AppKit/Themes/Aristo/Resources/token-center-disabled.png create mode 100644 AppKit/Themes/Aristo/Resources/token-left-disabled.png create mode 100644 AppKit/Themes/Aristo/Resources/token-right-disabled.png create mode 100644 AppKit/_CPPopUpList.j create mode 100644 AppKit/_CPPopUpListDataSource.j create mode 100644 Tests/Manual/CPComboBoxTest/AppController.j create mode 100644 Tests/Manual/CPComboBoxTest/Info.plist create mode 100644 Tests/Manual/CPComboBoxTest/Jakefile create mode 100644 Tests/Manual/CPComboBoxTest/Resources/MainMenu.cib create mode 100644 Tests/Manual/CPComboBoxTest/Resources/MainMenu.xib create mode 100644 Tests/Manual/CPComboBoxTest/Resources/spinner.gif create mode 100644 Tests/Manual/CPComboBoxTest/index-debug.html create mode 100644 Tests/Manual/CPComboBoxTest/index.html create mode 100644 Tests/Manual/CPComboBoxTest/main.j create mode 100644 Tests/Manual/NewTextFieldBezel/AppController.j create mode 100644 Tests/Manual/NewTextFieldBezel/Info.plist create mode 100644 Tests/Manual/NewTextFieldBezel/Jakefile create mode 100644 Tests/Manual/NewTextFieldBezel/Resources/spinner.gif create mode 100644 Tests/Manual/NewTextFieldBezel/index-debug.html create mode 100644 Tests/Manual/NewTextFieldBezel/index.html create mode 100644 Tests/Manual/NewTextFieldBezel/main.j create mode 100644 Tools/nib2cib/NSComboBox.j diff --git a/AppKit/AppKit.j b/AppKit/AppKit.j index 2a34e76f4..c48b219d3 100644 --- a/AppKit/AppKit.j +++ b/AppKit/AppKit.j @@ -47,6 +47,7 @@ @import "CPColorPanel.j" @import "CPColorSpace.j" @import "CPColorWell.j" +@import "CPComboBox.j" @import "CPCompatibility.j" @import "CPControl.j" @import "CPController.j" diff --git a/AppKit/CPComboBox.j b/AppKit/CPComboBox.j new file mode 100644 index 000000000..1d2af4928 --- /dev/null +++ b/AppKit/CPComboBox.j @@ -0,0 +1,1193 @@ +/* + * CPComboBox.j + * AppKit + * + * Created by Aparajita Fishman. + * Copyright (c) 2012, The Cappuccino Foundation + * + * 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 "CPTextField.j" +@import "_CPPopUpList.j" + + +CPComboBoxSelectionDidChangeNotification = @"CPComboBoxSelectionDidChangeNotification"; +CPComboBoxSelectionIsChangingNotification = @"CPComboBoxSelectionIsChangingNotification"; +CPComboBoxWillDismissNotification = @"CPComboBoxWillDismissNotification"; +CPComboBoxWillPopUpNotification = @"CPComboBoxWillPopUpNotification"; + +CPComboBoxStateButtonBordered = CPThemeState("button-bordered"); + +var CPComboBoxTextSubview = @"text", + CPComboBoxButtonSubview = @"button", + CPComboBoxDefaultNumberOfVisibleItems = 5, + CPComboBoxFocusRingWidth = -1; + + +@implementation CPComboBox : CPTextField +{ + CPArray _items; + _CPPopUpList _listDelegate; + CPComboBoxDataSource _dataSource; + BOOL _usesDataSource; + BOOL _completes; + BOOL _canComplete; + int _numberOfVisibleItems; + BOOL _forceSelection; + BOOL _hasVerticalScroller; + CPString _selectedStringValue; + BOOL _popUpButtonCausedResign; +} + ++ (CPString)defaultThemeClass +{ + return "combobox"; +} + ++ (id)themeAttributes +{ + return [CPDictionary dictionaryWithObjectsAndKeys:_CGSizeMake(21.0, 29.0), @"popup-button-size", _CGInsetMake(3.0, 3.0, 3.0, 3.0), @"border-inset"]; +} + ++ (Class)_binderClassForBinding:(CPString)theBinding +{ + if (theBinding === CPContentBinding || theBinding === CPContentValuesBinding) + return [_CPComboBoxContentBinder class]; + + return [super _binderClassForBinding:theBinding]; +} + +- (id)initWithFrame:(CGRect)aFrame +{ + self = [super initWithFrame:aFrame]; + + if (self) + [self _initComboBox]; + + return self; +} + +- (void)_initComboBox +{ + _items = [CPArray array]; + _listClass = [_CPPopUpList class]; + _usesDataSource = NO; + _completes = NO; + _canComplete = NO; + _numberOfVisibleItems = CPComboBoxDefaultNumberOfVisibleItems; + _forceSelection = NO; + _hasVerticalScroller = YES; + _selectedStringValue = @""; + _popUpButtonCausedResign = NO; + + [self setTheme:[CPTheme defaultTheme]]; + [self setBordered:YES]; + [self setBezeled:YES]; + [self setEditable:YES]; + [self setThemeState:CPComboBoxStateButtonBordered]; +} + +#pragma mark Setting Display Attributes + +- (BOOL)hasVerticalScroller +{ + return _hasVerticalScroller; +} + +- (void)setHasVerticalScroller:(BOOL)flag +{ + flag = !!flag; + + if (_hasVerticalScroller === flag) + return; + + _hasVerticalScroller = flag; + [[_listDelegate scrollView] setHasVerticalScroller:flag]; +} + +- (CGSize)intercellSpacing +{ + return [[_listDelegate tableView] intercellSpacing]; +} + +- (void)setIntercellSpacing:(CGSize)aSize +{ + [[_listDelegate tableView] setIntercellSpacing:aSize]; +} + +- (BOOL)isButtonBordered +{ + return [self hasThemeState:CPComboBoxStateButtonBordered]; +} + +- (void)setButtonBordered:(BOOL)flag +{ + if (!!flag) + [self setThemeState:CPComboBoxStateButtonBordered]; + else + [self unsetThemeState:CPComboBoxStateButtonBordered]; +} + +- (float)itemHeight +{ + return [[_listDelegate tableView] rowHeight]; +} + +- (void)setItemHeight:(float)itemHeight +{ + [[_listDelegate tableView] setRowHeight:itemHeight]; + + // FIXME: This shouldn't be necessary, but CPTableView does not tile after setRowHeight + [[_listDelegate tableView] reloadData]; +} + +- (int)numberOfVisibleItems +{ + return _numberOfVisibleItems; +} + +- (void)setNumberOfVisibleItems:(int)visibleItems +{ + // There should always be at least 1 visible item! + _numberOfVisibleItems = MAX(visibleItems, 1); +} + +#pragma mark Setting a Delegate + +- (id < CPComboBoxDelegate >)delegate +{ + return [super delegate]; +} + +/*! + Sets the CPComboBox delegate. Note that although the Cocoa + docs say that the delegate must conform to the NSComboBoxDelegate + protocol, in actual fact it doesn't. Also note that the same + delegate may conform to the NSTextFieldDelegate protocol. +*/ +- (void)setDelegate:(id < CPComboBoxDelegate >)aDelegate +{ + var delegate = [self delegate]; + + if (aDelegate === delegate) + return; + + var defaultCenter = [CPNotificationCenter defaultCenter]; + + if (delegate) + { + [defaultCenter removeObserver:delegate name:CPComboBoxSelectionIsChangingNotification object:self]; + [defaultCenter removeObserver:delegate name:CPComboBoxSelectionDidChangeNotification object:self]; + [defaultCenter removeObserver:delegate name:CPComboBoxWillDismissNotification object:self]; + [defaultCenter removeObserver:delegate name:CPComboBoxWillPopUpNotification object:self]; + } + + if (aDelegate) + { + if ([aDelegate respondsToSelector:@selector(comboBoxSelectionIsChanging:)]) + [defaultCenter addObserver:delegate + selector:@selector(comboBoxSelectionIsChanging:) + name:CPComboBoxSelectionIsChangingNotification + object:self]; + + if ([aDelegate respondsToSelector:@selector(comboBoxSelectionDidChange:)]) + [defaultCenter addObserver:delegate + selector:@selector(comboBoxSelectionDidChange:) + name:CPComboBoxSelectionDidChangeNotification + object:self]; + + if ([aDelegate respondsToSelector:@selector(comboBoxWillPopUp:)]) + [defaultCenter addObserver:delegate + selector:@selector(comboBoxWillPopUp:) + name:CPComboBoxWillPopUpNotification + object:self]; + + if ([aDelegate respondsToSelector:@selector(comboBoxWillDismiss:)]) + [defaultCenter addObserver:delegate + selector:@selector(comboBoxWillDissmis:) + name:CPComboBoxWillDismissNotification + object:self]; + } + + [super setDelegate:aDelegate]; +} + +#pragma mark Setting a Data Source + +- (id < CPComboBoxDataSource >)dataSource +{ + if (!_usesDataSource) + [self _dataSourceWarningForMethod:_cmd condition:NO]; + + return _dataSource; +} + +- (void)setDataSource:(id < CPComboBoxDataSource >)aSource +{ + if (!_usesDataSource) + [self _dataSourceWarningForMethod:_cmd condition:NO]; + else if (_dataSource !== aSource) + { + if (![aSource respondsToSelector:@selector(numberOfItemsInComboBox:)] || + ![aSource respondsToSelector:@selector(comboBox:objectValueForItemAtIndex:)]) + { + CPLog.warn("Illegal %s data source (%s). Must implement numberOfItemsInComboBox: and comboBox:objectValueForItemAtIndex:", [self className], [aSource description]); + } + else + _dataSource = aSource; + } +} + +- (BOOL)usesDataSource +{ + return _usesDataSource; +} + +- (void)setUsesDataSource:(BOOL)flag +{ + flag = !!flag; + + if (_usesDataSource === flag) + return; + + _usesDataSource = flag; + + // Cocoa empties the internal item list if usesDataSource is YES + if (_usesDataSource) + [_items removeAllObjects]; + + [self reloadData]; +} + +#pragma mark Working with an Internal List + +- (void)addItemsWithObjectValues:(CPArray)objects +{ + [_items addObjectsFromArray:objects]; + + [self reloadDataSourceForSelector:_cmd]; +} + +- (void)addItemWithObjectValue:(id)anObject +{ + [_items addObject:anObject]; + + [self reloadDataSourceForSelector:_cmd]; +} + +- (void)insertItemWithObjectValue:(id)anObject atIndex:(int)anIndex +{ + // Issue the warning first, because removeObjectAtIndex may raise + if (_usesDataSource) + [self _dataSourceWarningForMethod:_cmd condition:YES]; + + [_items insertObject:anObject atIndex:anIndex]; + [self reloadData]; +} + +/*! + Returns the internal array of items. NOTE: Unlike Cocoa the array is mutable, + since all arrays in Objective-J are mutable. But you should treat it as + an immutable array. Do NOT attempt to change the returned array in any way. + + If usesDataSource is YES, a warning is logged and an empty array is returned. +*/ +- (CPArray)objectValues +{ + if (_usesDataSource) + [self _dataSourceWarningForMethod:_cmd condition:YES]; + + return _items; +} + +- (void)removeAllItems +{ + [_items removeAllObjects]; + + [self reloadDataSourceForSelector:_cmd]; +} + +- (void)removeItemAtIndex:(int)index +{ + // Issue the warning first, because removeObjectAtIndex may raise + if (_usesDataSource) + [self _dataSourceWarningForMethod:_cmd condition:YES]; + + [_items removeObjectAtIndex:index]; + [self reloadData]; +} + +- (void)removeItemWithObjectValue:(id)anObject +{ + [_items removeObject:anObject]; + + [self reloadDataSourceForSelector:_cmd]; +} + +- (int)numberOfItems +{ + if (_usesDataSource) + return [_dataSource numberOfItemsInComboBox:self]; + else + return _items.length; +} + +#pragma mark Manipulating the Displayed List + +/*! + Returns the delegate to be used when creating the pop up list. +*/ +- (_CPPopUpList)listDelegate +{ + return _listDelegate; +} + +/*! + Sets the delegate to be used when creating the pop up list. + By default this is _CPPopUpList. If you are using a subclass + of _CPPopUpList, call this method with your subclass. +*/ +- (void)setListDelegate:(_CPPopUpList)aDelegate +{ + if (_listDelegate === aDelegate) + return; + + var defaultCenter = [CPNotificationCenter defaultCenter]; + + if (_listDelegate) + { + [defaultCenter removeObserver:self name:_CPPopUpListWillPopUpNotification object:_listDelegate]; + [defaultCenter removeObserver:self name:_CPPopUpListWillDismissNotification object:_listDelegate]; + [defaultCenter removeObserver:self name:_CPPopUpListDidDismissNotification object:_listDelegate]; + [defaultCenter removeObserver:self name:_CPPopUpListItemWasClickedNotification object:_listDelegate]; + + var oldTableView = [_listDelegate tableView]; + + if (oldTableView) + { + [defaultCenter removeObserver:self name:CPTableViewSelectionIsChangingNotification object:oldTableView]; + [defaultCenter removeObserver:self name:CPTableViewSelectionDidChangeNotification object:oldTableView]; + } + } + + _listDelegate = aDelegate; + + [defaultCenter addObserver:self + selector:@selector(comboBoxWillPopUp:) + name:_CPPopUpListWillPopUpNotification + object:_listDelegate]; + + [defaultCenter addObserver:self + selector:@selector(comboBoxWillDismiss:) + name:_CPPopUpListWillDismissNotification + object:_listDelegate]; + + [defaultCenter addObserver:self + selector:@selector(listDidDismiss:) + name:_CPPopUpListDidDismissNotification + object:_listDelegate]; + + [defaultCenter addObserver:self + selector:@selector(itemWasClicked:) + name:_CPPopUpListItemWasClickedNotification + object:_listDelegate]; + + [[_listDelegate scrollView] setHasVerticalScroller:_hasVerticalScroller]; + + var tableView = [_listDelegate tableView]; + + [defaultCenter addObserver:self + selector:@selector(comboBoxSelectionIsChanging:) + name:CPTableViewSelectionIsChangingNotification + object:tableView]; + + [defaultCenter addObserver:self + selector:@selector(comboBoxSelectionDidChange:) + name:CPTableViewSelectionDidChangeNotification + object:tableView]; + + // Apply our text style to the list + [_listDelegate setFont:[self font]]; + [_listDelegate setAlignment:[self alignment]]; +} + +- (int)indexOfItemWithObjectValue:(id)anObject +{ + if (_usesDataSource) + [self _dataSourceWarningForMethod:_cmd condition:YES]; + + return [_items indexOfObject:anObject]; +} + +- (id)itemObjectValueAtIndex:(int)index +{ + if (_usesDataSource) + [self _dataSourceWarningForMethod:_cmd condition:YES]; + + return [_items objectAtIndex:index]; +} + +- (void)noteNumberOfItemsChanged +{ + [[_listDelegate tableView] noteNumberOfRowsChanged]; +} + +- (void)scrollItemAtIndexToTop:(int)index +{ + [_listDelegate scrollItemAtIndexToTop:index]; +} + +- (void)scrollItemAtIndexToVisible:(int)index +{ + [[_listDelegate tableView] scrollRowToVisible:index]; +} + +- (void)reloadData +{ + [[_listDelegate tableView] reloadData]; +} + +/*! @ignore */ +- (void)popUpList +{ + if (!_listDelegate) + [self setListDelegate:[[_CPPopUpList alloc] initWithDataSource:self]]; + + [self _selectMatchingItem]; + + // Note the offset here is 1 less than the focus ring width because the outer edge + // of the focus ring is very transparent and it looks better if the list is closer. + if (CPComboBoxFocusRingWidth < 0) + { + var inset = [self currentValueForThemeAttribute:@"border-inset"]; + + CPComboBoxFocusRingWidth = inset.bottom; + } + + [_listDelegate popUpRelativeToRect:[self _borderFrame] view:self offset:CPComboBoxFocusRingWidth - 1]; +} + +/*! @ignore */ +- (BOOL)listIsVisible +{ + return _listDelegate ? [_listDelegate isVisible] : NO; +} + +/*! @ignore */ +- (void)reloadDataSourceForSelector:(SEL)cmd +{ + if (_usesDataSource) + [self _dataSourceWarningForMethod:cmd condition:YES] + else + [self reloadData]; +} + +/*! + If the list is non-empty, sets the value of the field from the currently selected value of the list + and returns YES. If the list is empty or the list has no selected item, returns NO. + @ignore +*/ +- (BOOL)takeStringValueFromList +{ + if (_usesDataSource && _dataSource && [_dataSource numberOfItemsInComboBox:self] === 0) + return NO; + + var selectedStringValue = [_listDelegate selectedStringValue]; + + if (selectedStringValue === nil) + return NO; + else + _selectedStringValue = selectedStringValue; + + [self setStringValue:_selectedStringValue]; + [self _reverseSetBinding]; + + return YES; +} + +/*! + The receiver receives this notification when the list is closed. + @ignore +*/ +- (void)listDidDismiss:(CPNotification)aNotification +{ + [[self window] makeFirstResponder:self]; +} + +/*! + The receiver receives this notification when an item in the list is clicked. + @ignore +*/ +- (void)itemWasClicked:(CPNotification)aNotification +{ + [self takeStringValueFromList]; + [self sendAction:[self action] to:[self target]]; +} + +#pragma mark Manipulating the Selection + +- (void)deselectItemAtIndex:(int)index +{ + var table = [_listDelegate tableView], + row = [table selectedRow]; + + if (row !== index) + return; + + [table deselectRow:index]; +} + +- (int)indexOfSelectedItem +{ + return [[_listDelegate tableView] selectedRow]; +} + +- (id)objectValueOfSelectedItem +{ + var row = [[_listDelegate tableView] selectedRow]; + + if (row >= 0) + { + if (_usesDataSource) + [self _dataSourceWarningForMethod:_cmd condition:YES]; + + return _items[row]; + } + + return nil; +} + +- (void)selectItemAtIndex:(int)index +{ + var table = [_listDelegate tableView], + row = [table selectedRow]; + + if (row === index) + return; + + [table selectRowIndexes:[CPIndexSet indexSetWithIndex:index] byExtendingSelection:NO]; +} + +- (void)selectItemWithObjectValue:(id)anObject +{ + var index = [self indexOfItemWithObjectValue:anObject]; + + if (index !== CPNotFound) + [self selectItemAtIndex:index]; +} + +#pragma mark Completing the Text Field + +- (BOOL)completes +{ + return _completes; +} + +- (void)setCompletes:(BOOL)flag +{ + _completes = !!flag; +} + +- (CPString)completedString:(CPString)substring +{ + if (_usesDataSource) + return [self comboBoxCompletedString:substring]; + else + { + var index = [_items indexOfObjectPassingTest:CPComboBoxCompletionTest context:substring]; + + return index !== CPNotFound ? _items[index] : nil; + } +} + +/*! + Returns whether the combo box forces the user to enter or select + an item that is in the item list. +*/ +- (BOOL)forceSelection +{ + return _forceSelection; +} + +/*! + Sets whether the combo box forces the user to enter or select + an item that is in the item list. If \c flag is \c YES and the user enters a value + that is not in the list, when the field loses focus it will revert + to the previous value. If \c flag is \c NO, the user can enter any value they wish. + + Note that this flag is ignored if \ref setStringValue or \ref setObjectValue are + called directly. +*/ +- (void)setForceSelection:(BOOL)flag +{ + _forceSelection = !!flag; +} + +#pragma mark CPTextField Delegate Methods and Overrides + +/*! @ignore */ +- (BOOL)sendAction:(SEL)anAction to:(id)anObject +{ + // When the action is sent, be sure to get the value and close the list. + // This covers the case where the action is triggered by pressing a key + // that triggers the text field action. + + if ([self listIsVisible]) + { + [self takeStringValueFromList]; + [_listDelegate close]; + } + + return [super sendAction:anAction to:anObject]; +} + +/*! @ignore */ +- (void)setObjectValue:(id)object +{ + [super setObjectValue:object]; + + _selectedStringValue = [self stringValue]; +} + +/*! @ignore */ +- (void)interpretKeyEvents:(CPArray)events +{ + var theEvent = events[0]; + + // Only if characters are added at the end of the value can completion occur + _canComplete = NO; + + if (_completes) + { + console.log("%d: %s", [theEvent keyCode], [theEvent _couldBeKeyEquivalent]); + if (![theEvent _couldBeKeyEquivalent] && [theEvent characters].charAt(0) !== CPDeleteCharacter) + { + var value = [self _inputElement].value, + selectedRange = [self selectedRange]; + + _canComplete = CPMaxRange(selectedRange) === value.length; + } + } + + [super interpretKeyEvents:events]; +} + +/*! @ignore */ +- (void)paste:(id)sender +{ + if (_completes) + { + // Completion can occur only if pasting at the end of the value + var value = [self _inputElement].value, + selectedRange = [self selectedRange]; + + _canComplete = CPMaxRange(selectedRange) === value.length; + } + else + _canComplete = NO; + + [super paste:sender]; +} + +/*! @ignore */ +- (void)textDidChange:(CPNotification)aNotification +{ + /* + Completion is attempted iff: + - _completes is YES + - Characters were added at the end of the value + */ + var uncompletedString = [self stringValue], + newString = uncompletedString; + + if (_completes && _canComplete) + { + newString = [self completedString:uncompletedString]; + + if (newString && newString.length > uncompletedString.length) + { + [self setStringValue:newString]; + [self setSelectedRange:CPMakeRange(uncompletedString.length, newString.length - uncompletedString.length)]; + } + } + + [self _selectMatchingItem]; + _canComplete = NO; + + [super textDidChange:aNotification]; +} + +/*! + Override of CPView -performKeyEquivalent + @ignore +*/ +- (BOOL)performKeyEquivalent:(CPEvent)anEvent +{ + if ([[self window] firstResponder] === self) + { + var key = [anEvent charactersIgnoringModifiers]; + + switch (key) + { + case CPDownArrowFunctionKey: + if (![self listIsVisible]) + { + [self popUpList]; + return YES; + } + break; + + case CPEscapeFunctionKey: + if ([self listIsVisible]) + { + // If we are forcing a selection and the user has entered a value which is not + // in the list, revert to the most recent valid value. + if (_forceSelection && ([self _inputElement].value !== _selectedStringValue)) + [self setStringValue:_selectedStringValue]; + } + break; + } + + if ([_listDelegate performKeyEquivalent:anEvent]) + return YES; + } + + return [super performKeyEquivalent:anEvent]; +} + +/*! @ignore */ +- (BOOL)resignFirstResponder +{ + var buttonCausedResign = _popUpButtonCausedResign; + + _popUpButtonCausedResign = NO; + + /* + If the list or popup button is clicked, we lose focus. The list will refuse first responder, + and we refuse to resign. But we still have to manually restore the focus to the input element. + */ + var shouldResign = !buttonCausedResign && (!_listDelegate || [_listDelegate controllingViewShouldResign]); + + if (!shouldResign) + { +#if PLATFORM(DOM) + // In FireFox this needs to be done in setTimeout, otherwise there is no caret + // We have to save the input element now, when we lose focus it will change. + var element = [self _inputElement]; + window.setTimeout(function() { element.focus(); }, 0); +#endif + + return NO; + } + + // The list was not clicked, we need to close it now + [_listDelegate close]; + + // If the field is empty, allow it to remain empty. + // Otherwise restore the most recently selected value if forcing selection. + var value = [self stringValue]; + + if (value) + { + if (_forceSelection && ![value isEqual:_selectedStringValue]) + [self setStringValue:_selectedStringValue]; + } + else + _selectedStringValue = @""; + + return [super resignFirstResponder]; +} + +- (void)setFont:(CPFont)aFont +{ + [super setFont:aFont]; + [_listDelegate setFont:aFont]; +} + +- (void)setAlignment:(CPTextAlignment)alignment +{ + [super setAlignment:alignment]; + [_listDelegate setAlignment:alignment]; +} + +#pragma mark Pop Up Button Layout + +- (CGRect)popupButtonRectForBounds:(CGRect)bounds +{ + var borderInset = [self currentValueForThemeAttribute:@"border-inset"], + buttonSize = [self currentValueForThemeAttribute:@"popup-button-size"]; + + bounds.origin.x = CGRectGetMaxX(bounds) - borderInset.right - buttonSize.width; + bounds.origin.y += borderInset.top; + + bounds.size.width = buttonSize.width; + bounds.size.height = buttonSize.height; + + return bounds; +} + +- (CGRect)rectForEphemeralSubviewNamed:(CPString)aName +{ + if (aName === "popup-button-view") + return [self popupButtonRectForBounds:[self bounds]]; + + return [super rectForEphemeralSubviewNamed:aName]; +} + +- (CPView)createEphemeralSubviewNamed:(CPString)aName +{ + if (aName === "popup-button-view") + { + var view = [[_CPComboBoxPopUpButton alloc] initWithFrame:_CGRectMakeZero() comboBox:self]; + + return view; + } + + return [super createEphemeralSubviewNamed:aName]; +} + +- (void)layoutSubviews +{ + [super layoutSubviews]; + + var popupButtonView = [self layoutEphemeralSubviewNamed:@"popup-button-view" + positioned:CPWindowAbove + relativeToEphemeralSubviewNamed:@"content-view"]; +} + +#pragma mark Internal Helpers + +/*! @ignore */ +- (void)_dataSourceWarningForMethod:(SEL)cmd condition:(CPString)flag +{ + CPLog.warn("-[%s %s] should not be called when usesDataSource is set to %s", [self className], cmd, flag ? "YES" : "NO"); +} + +/*! + Select the item that matches the current value of the combobox. + @ignore +*/ +- (void)_selectMatchingItem +{ + var index = CPNotFound, + stringValue = [self stringValue]; + + if (_usesDataSource) + { + if (_dataSource && [_dataSource respondsToSelector:@selector(comboBox:indexOfItemWithStringValue:)]) + index = [_dataSource comboBox:self indexOfItemWithStringValue:stringValue] + } + else + index = [self indexOfItemWithObjectValue:stringValue]; + + [_listDelegate selectRow:index]; + + // selectRow scrolls the row to visible, if a row is selected scroll it to the top + if (index !== CPNotFound) + { + [_listDelegate scrollItemAtIndexToTop:index]; + _selectedStringValue = stringValue; + } +} + +/*! + Calculate the frame in base coordinates that will nestle just below the visible border of the text field. + @ignore +*/ +- (CGRect)_borderFrame +{ + var inset = [self currentValueForThemeAttribute:@"border-inset"], + frame = [self bounds]; + + frame.origin.x += inset.left; + frame.origin.y += inset.top; + frame.size.width -= inset.left + inset.right; + frame.size.height -= inset.top + inset.bottom; + + return frame; +} + +/* @ignore */ +- (void)_popUpButtonWasClicked +{ + if (![self isEnabled]) + return; + + // If we are currently the first responder, we will be asked to resign when the list pops up. + // Set a flag to let resignResponder know that the button was clicked and we should not resign. + var firstResponder = [[self window] firstResponder]; + + _popUpButtonCausedResign = firstResponder === self; + + if ([self listIsVisible]) + [_listDelegate close]; + else + { + if (firstResponder !== self) + [[self window] makeFirstResponder:self]; + + [self popUpList]; + } +} + +@end + +@implementation CPComboBox (CPComboBoxDelegate) + +/*! @ignore */ +- (void)comboBoxSelectionIsChanging:(CPNotification)aNotification +{ + [[CPNotificationCenter defaultCenter] postNotificationName:CPComboBoxSelectionIsChangingNotification object:self]; +} + +/*! @ignore */ +- (void)comboBoxSelectionDidChange:(CPNotification)aNotification +{ + [[CPNotificationCenter defaultCenter] postNotificationName:CPComboBoxSelectionDidChangeNotification object:self]; +} + +/*! @ignore */ +- (void)comboBoxWillPopUp:(CPNotification)aNotification +{ + [[CPNotificationCenter defaultCenter] postNotificationName:CPComboBoxWillPopUpNotification object:self]; +} + +/*! @ignore */ +- (void)comboBoxWillDismiss:(CPNotification)aNotification +{ + [[CPNotificationCenter defaultCenter] postNotificationName:CPComboBoxWillDismissNotification object:self]; +} + +@end + +@implementation CPComboBox (CPComboBoxDataSource) + +/*! @ignore */ +- (CPString)comboBoxCompletedString:(CPString)uncompletedString +{ + if ([_dataSource respondsToSelector:@selector(comboBox:completedString:)]) + return [_dataSource comboBox:self completedString:uncompletedString]; + else + return nil; +} + +@end + +@implementation CPComboBox (_CPPopUpListDataSource) + +- (int)numberOfItemsInList:(_CPPopUpList)aList +{ + return [self numberOfItems]; +} + +- (int)numberOfVisibleItemsInList:(_CPPopUpList)aList +{ + return [self numberOfVisibleItems]; +} + +- (id)list:(_CPPopUpList)aList objectValueForItemAtIndex:(int)index +{ + if (_usesDataSource) + return [_dataSource comboBox:self objectValueForItemAtIndex:index]; + else + return _items[index]; +} + +- (id)list:(_CPPopUpList)aList displayValueForObjectValue:(id)aValue +{ + return aValue || @""; +} + +- (CPString)list:(_CPPopUpList)aList stringValueForObjectValue:(id)aValue +{ + return String(aValue); +} + +@end + +@implementation CPComboBox (Bindings) + +/*! @ignore */ +- (void)setContentValues:(CPArray)anArray +{ + [self setUsesDataSource:NO]; + [self removeAllItems]; + [self addItemsWithObjectValues:anArray]; +} + +/*! @ignore */ +- (void)setContent:(CPArray)anArray +{ + [self setUsesDataSource:NO]; + + // Directly nuke _items, [_items removeAll] will trigger an extra call to setContent + _items = []; + + var values = []; + + [anArray enumerateObjectsUsingBlock:function(object) + { + values.push([object description]); + }]; + + [self addItemsWithObjectValues:values]; +} + +@end + +var CPComboBoxItemsKey = @"CPComboBoxItemsKey", + CPComboBoxListKey = @"CPComboBoxListKey", + CPComboBoxDelegateKey = @"CPComboBoxDelegateKey", + CPComboBoxDataSourceKey = @"CPComboBoxDataSourceKey", + CPComboBoxUsesDataSourceKey = @"CPComboBoxUsesDataSourceKey", + CPComboBoxCompletesKey = @"CPComboBoxCompletesKey", + CPComboBoxNumberOfVisibleItemsKey = @"CPComboBoxNumberOfVisibleItemsKey", + CPComboBoxHasVerticalScrollerKey = @"CPComboBoxHasVerticalScrollerKey", + CPComboBoxButtonBorderedKey = @"CPComboBoxButtonBorderedKey"; + +@implementation CPComboBox (CPCoding) + +- (id)initWithCoder:(CPCoder)aCoder +{ + self = [super initWithCoder:aCoder]; + + if (self) + { + [self _initComboBox]; + + _items = [aCoder decodeObjectForKey:CPComboBoxItemsKey]; + _listDelegate = [aCoder decodeObjectForKey:CPComboBoxListKey]; + _delegate = [aCoder decodeObjectForKey:CPComboBoxDelegateKey]; + _dataSource = [aCoder decodeObjectForKey:CPComboBoxDataSourceKey]; + _usesDataSource = [aCoder decodeBoolForKey:CPComboBoxUsesDataSourceKey]; + _completes = [aCoder decodeBoolForKey:CPComboBoxCompletesKey]; + _numberOfVisibleItems = [aCoder decodeIntForKey:CPComboBoxNumberOfVisibleItemsKey]; + _hasVerticalScroller = [aCoder decodeBoolForKey:CPComboBoxHasVerticalScrollerKey]; + [self setButtonBordered:[aCoder decodeBoolForKey:CPComboBoxButtonBorderedKey]]; + } + + return self; +} + +- (void)encodeWithCoder:(CPCoder)aCoder +{ + [super encodeWithCoder:aCoder]; + + [aCoder encodeObject:_items forKey:CPComboBoxItemsKey]; + [aCoder encodeObject:_listDelegate forKey:CPComboBoxListKey]; + [aCoder encodeObject:_delegate forKey:CPComboBoxDelegateKey]; + [aCoder encodeObject:_dataSource forKey:CPComboBoxDataSourceKey]; + [aCoder encodeBool:_usesDataSource forKey:CPComboBoxUsesDataSourceKey]; + [aCoder encodeBool:_completes forKey:CPComboBoxCompletesKey]; + [aCoder encodeInt:_numberOfVisibleItems forKey:CPComboBoxNumberOfVisibleItemsKey]; + [aCoder encodeBool:_hasVerticalScroller forKey:CPComboBoxHasVerticalScrollerKey]; + [aCoder encodeBool:[self isButtonBordered] forKey:CPComboBoxButtonBorderedKey]; +} + +@end + + +var CPComboBoxCompletionTest = function(object, index, context) +{ + return object.toString().indexOf(context) === 0; +}; + + +/* + This class is only used for CPContentBinding and CPContentValuesBinding. +*/ +@implementation _CPComboBoxContentBinder : CPBinder + +- (void)setValueFor:(CPString)theBinding +{ + var destination = [_info objectForKey:CPObservedObjectKey], + keyPath = [_info objectForKey:CPObservedKeyPathKey], + options = [_info objectForKey:CPOptionsKey], + newValue = [destination valueForKeyPath:keyPath], + isPlaceholder = CPIsControllerMarker(newValue); + + [_source removeAllItems]; + + if (isPlaceholder) + { + // By default the placeholders will all result in an empty list + switch (newValue) + { + case CPMultipleValuesMarker: + newValue = [options objectForKey:CPMultipleValuesPlaceholderBindingOption] || []; + break; + + case CPNoSelectionMarker: + newValue = [options objectForKey:CPNoSelectionPlaceholderBindingOption] || []; + break; + + case CPNotApplicableMarker: + if ([options objectForKey:CPRaisesForNotApplicableKeysBindingOption]) + [CPException raise:CPGenericException + reason:@"can't transform non applicable key on: " + _source + " value: " + newValue]; + + newValue = [options objectForKey:CPNotApplicablePlaceholderBindingOption] || []; + break; + + case CPNullMarker: + newValue = [options objectForKey:CPNullPlaceholderBindingOption] || []; + break; + } + + if (![newValue isKindOfClass:[CPArray class]]) + newValue = []; + } + else + newValue = [self transformValue:newValue withOptions:options]; + + switch (theBinding) + { + case CPContentBinding: [_source setContent:newValue]; + break; + + case CPContentValuesBinding: [_source setContentValues:newValue]; + break; + } +} + +@end + +@implementation _CPComboBoxPopUpButton : CPView +{ + CPComboBox _comboBox; +} + +- (id)initWithFrame:(CGRect)aFrame comboBox:(CPComboBox)aComboBox +{ + self = [super initWithFrame:aFrame]; + + if (self) + _comboBox = aComboBox; + + return self; +} + +- (void)mouseDown:(CPEvent)theEvent +{ + [_comboBox _popUpButtonWasClicked]; +} + +- (BOOL)acceptsFirstResponder +{ + return NO; +} + +@end diff --git a/AppKit/CPKeyValueBinding.j b/AppKit/CPKeyValueBinding.j index 608f7ae4a..1794085a3 100644 --- a/AppKit/CPKeyValueBinding.j +++ b/AppKit/CPKeyValueBinding.j @@ -558,6 +558,8 @@ CPValueBinding = @"value"; CPValueURLBinding = @"valueURL"; CPValuePathBinding = @"valuePath"; CPDataBinding = @"data"; +CPContentBinding = @"content"; +CPContentValuesBinding = @"contentValues"; //Binding options constants CPAllowsEditingMultipleValuesSelectionBindingOption = @"CPAllowsEditingMultipleValuesSelection"; diff --git a/AppKit/CPTextField.j b/AppKit/CPTextField.j index bda0c5a1b..60874a91a 100644 --- a/AppKit/CPTextField.j +++ b/AppKit/CPTextField.j @@ -486,10 +486,8 @@ CPTextFieldStatePlaceholder = CPThemeState("placeholder"); #if PLATFORM(DOM) var element = [self _inputElement], - font = [self currentValueForThemeAttribute:@"font"]; - - // generate the font metric - [font _getMetrics]; + font = [self currentValueForThemeAttribute:@"font"], + lineHeight = ROUND([font defaultLineHeightForFont]); element.value = _stringValue; element.style.color = [[self currentValueForThemeAttribute:@"text-color"] cssString]; @@ -511,26 +509,26 @@ CPTextFieldStatePlaceholder = CPThemeState("placeholder"); switch (verticalAlign) { case CPTopVerticalTextAlignment: - var topPoint = (_CGRectGetMinY(contentRect) + 1) + "px"; // for the same reason we have a -1 for the left, we also have a + 1 here + var topPoint = _CGRectGetMinY(contentRect) + "px"; break; case CPCenterVerticalTextAlignment: - var topPoint = (_CGRectGetMidY(contentRect) - (font._lineHeight / 2) + 1) + "px"; + var topPoint = (_CGRectGetMidY(contentRect) - (lineHeight / 2)) + "px"; break; case CPBottomVerticalTextAlignment: - var topPoint = (_CGRectGetMaxY(contentRect) - font._lineHeight) + "px"; + var topPoint = (_CGRectGetMaxY(contentRect) - lineHeight) + "px"; break; default: - var topPoint = (_CGRectGetMinY(contentRect) + 1) + "px"; + var topPoint = _CGRectGetMinY(contentRect) + "px"; break; } element.style.top = topPoint; - element.style.left = (_CGRectGetMinX(contentRect) - 1) + "px"; // why -1? + element.style.left = (_CGRectGetMinX(contentRect) - 1) + "px"; // -1 because input element seems to have 1px left inset element.style.width = _CGRectGetWidth(contentRect) + "px"; - element.style.height = font._lineHeight + "px"; // private ivar for the line height of the DOM text at this particular size + element.style.height = lineHeight + "px"; _DOMElement.appendChild(element); @@ -1315,9 +1313,6 @@ CPTextFieldStatePlaceholder = CPThemeState("placeholder"); { var contentInset = [self currentValueForThemeAttribute:@"content-inset"]; - if (!contentInset) - return bounds; - bounds.origin.x += contentInset.left; bounds.origin.y += contentInset.top; bounds.size.width -= contentInset.left + contentInset.right; @@ -1365,7 +1360,6 @@ CPTextFieldStatePlaceholder = CPThemeState("placeholder"); else { var view = [[_CPImageAndTextView alloc] initWithFrame:_CGRectMakeZero()]; - //[view setImagePosition:CPNoImage]; [view setHitTests:NO]; diff --git a/AppKit/CPTokenField.j b/AppKit/CPTokenField.j index d306052e9..a0c094816 100755 --- a/AppKit/CPTokenField.j +++ b/AppKit/CPTokenField.j @@ -90,6 +90,11 @@ var CPScrollDestinationNone = 0, return "tokenfield"; } ++ (id)themeAttributes +{ + return [CPDictionary dictionaryWithObject:_CGInsetMakeZero() forKey:@"editor-inset"]; +} + - (id)initWithFrame:(CPRect)frame { if (self = [super initWithFrame:frame]) @@ -179,6 +184,7 @@ var CPScrollDestinationNone = 0, // Give the delegate a chance to confirm, replace or add to the list of tokens being added. var delegateApprovedObjects = [self _shouldAddObjects:[CPArray arrayWithObject:token] atIndex:_selectedRange.location], delegateApprovedObjectsCount = [delegateApprovedObjects count]; + if (delegateApprovedObjects) { for (var i = 0; i < delegateApprovedObjectsCount; i++) @@ -313,11 +319,12 @@ var CPScrollDestinationNone = 0, #if PLATFORM(DOM) var string = [self stringValue], - element = [self _inputElement]; + element = [self _inputElement], + font = [self currentValueForThemeAttribute:@"font"]; element.value = nil; element.style.color = [[self currentValueForThemeAttribute:@"text-color"] cssString]; - element.style.font = [[self currentValueForThemeAttribute:@"font"] cssString]; + element.style.font = [font cssString]; element.style.zIndex = 1000; switch ([self alignment]) @@ -332,9 +339,9 @@ var CPScrollDestinationNone = 0, var contentRect = [self contentRectForBounds:[self bounds]]; element.style.top = CGRectGetMinY(contentRect) + "px"; - element.style.left = (CGRectGetMinX(contentRect) - 1) + "px"; // why -1? + element.style.left = (CGRectGetMinX(contentRect) - 1) + "px"; // element effectively imposes a 1px left margin element.style.width = CGRectGetWidth(contentRect) + "px"; - element.style.height = CGRectGetHeight(contentRect) + "px"; + element.style.height = ROUND([font defaultLineHeightForFont]) + "px"; [_tokenScrollView documentView]._DOMElement.appendChild(element); @@ -472,6 +479,7 @@ var CPScrollDestinationNone = 0, - (id)objectValue { var objectValue = []; + for (var i = 0, count = [[self _tokens] count]; i < count; i++) { var token = [[self _tokens] objectAtIndex:i]; @@ -570,6 +578,20 @@ var CPScrollDestinationNone = 0, [self setNeedsDisplay:YES]; } +- (void)setEnabled:(BOOL)shouldBeEnabled +{ + [super setEnabled:shouldBeEnabled]; + + // Set the enabled state of the tokens + for (var i = 0, count = [[self _tokens] count]; i < count; i++) + { + var token = [[self _tokens] objectAtIndex:i]; + + if ([token respondsToSelector:@selector(setEnabled:)]) + [token setEnabled:shouldBeEnabled]; + } +} + - (void)sendAction:(SEL)anAction to:(id)anObject { _shouldNotifyTarget = NO; @@ -962,7 +984,10 @@ var CPScrollDestinationNone = 0, offset = CPPointMake(contentOrigin.x, contentOrigin.y), spaceBetweenTokens = CPSizeMake(2.0, 2.0), isEditing = [[self window] firstResponder] == self, - tokenToken = [_CPTokenFieldToken new]; + tokenToken = [_CPTokenFieldToken new], + font = [self currentValueForThemeAttribute:@"font"], + lineHeight = ROUND([font defaultLineHeightForFont]), + editorInset = [self currentValueForThemeAttribute:@"editor-inset"]; // Get the height of a typical token, or a token token if you will. [tokenToken sizeToFit]; @@ -1001,15 +1026,17 @@ var CPScrollDestinationNone = 0, // XXX The "X" here is used to estimate the space needed to fit the next character // without clipping. Since different fonts might have different sizes of "X" this // solution is not ideal, but it works. - textWidth = [(element.value || @"") + "X" sizeWithFont:[self font]].width; + textWidth = [(element.value || @"") + "X" sizeWithFont:font].width; + if (useRemainingWidth) textWidth = MAX(contentSize.width - offset.x - 1, textWidth); } _inputFrame = fitAndFrame(textWidth, tokenHeight); + _inputFrame.size.height = lineHeight; - element.style.left = _inputFrame.origin.x + "px"; - element.style.top = _inputFrame.origin.y + "px"; + element.style.left = (_inputFrame.origin.x + editorInset.left) + "px"; + element.style.top = (_inputFrame.origin.y + editorInset.top) + "px"; element.style.width = _inputFrame.size.width + "px"; element.style.height = _inputFrame.size.height + "px"; diff --git a/AppKit/Themes/Aristo/Resources/combobox-bezel-center.png b/AppKit/Themes/Aristo/Resources/combobox-bezel-center.png new file mode 100644 index 0000000000000000000000000000000000000000..8f5171d3c673d102f7e1b56ff2ad2283c856db7a GIT binary patch literal 145 zcmeAS@N?(olHy`uVBq!ia0vp^j6f{Q!3HF=8QC&{lw^r(L`iUdT1k0gQ7VIDN`6wR zf@f}GdTLN=VoGJ<$y6JlB4bY%$B>F!Nk9Jow`Ue+7I5g$jo$Vrz2ei8ll5)&|Ns3> rPfAH~nYPr7aZ7I_<5gA$Mm7fZUBcXcrE`*i+8I1u{an^LB{Ts5AHOYr literal 0 HcmV?d00001 diff --git a/AppKit/Themes/Aristo/Resources/combobox-bezel-disabled-center.png b/AppKit/Themes/Aristo/Resources/combobox-bezel-disabled-center.png new file mode 100644 index 0000000000000000000000000000000000000000..584597d709e4960a1fe0b567bc129a874077e6b1 GIT binary patch literal 139 zcmeAS@N?(olHy`uVBq!ia0vp^j6f{Q!3HF=8QC&{lw^r(L`iUdT1k0gQ7VIDN`6wR zf@f}GdTLN=VoGJ<$y6JlB3(}x$B>F!Nk9Jow`Ue+7I5h37T5om{^Qfr)Aei%j?}Ag k&Ju9AEg=yQ%OH@zP*5)X(kSm>8c-vHr>mdKI;Vst0J&}{xBvhE literal 0 HcmV?d00001 diff --git a/AppKit/Themes/Aristo/Resources/combobox-bezel-disabled-left.png b/AppKit/Themes/Aristo/Resources/combobox-bezel-disabled-left.png new file mode 100644 index 0000000000000000000000000000000000000000..5cd37245fc3f3f5fd0bddfc262528d1145e322d3 GIT binary patch literal 196 zcmeAS@N?(olHy`uVBq!ia0vp^Y(Ol_0U|r^$_fA}$r9IylHmNblJdl&R0hYC{G?O` z&)mfH)S%SFl*+=BsWw1GX`U{QAr-fh{`~)M&un(!NCWeODG4rSuO1!k&T&}9*C8Bn zLBy=6pdh59tIKGCx60{Lr;G}Uijr<9atWoRq#W5IqvA2I*j+V4;p4CS`|BfApY5ys r+{UQVsXKKGbD@ax*B~W_21bU^SB#xYT9iD&_F9CPP1q}(bmI-M;ZI*;I(tx#{HntQAQn?4a_Gf>tlOWDH zR0|9!`FuFF1`lVYl!Uq_AV#sCo^wb#CXF^*)+^H1QrZjYO` zy)i&c0_F_-;4L_H>icsQsOSR~A*djVF>Zd>>s$h;YicrCJyyhzGJr%ZWfXl?02vkJ zN|E9USP}qa1w7{_X8=qlAv|=uKq*bxG);rH=Ye6Ami7S8C`wADT!N10WM{)<{F!Nh_kNZ_nv$Y+TsT+23y7^z!`dXda&SbvA#` ze~{;J5aQXQc+U3EnFCv1KM7@1b7OR6Tjn2cx1Pn*hk?U@L3^Lr(<1^~@t@O1Ta JS?83{1OTq!H17Za literal 0 HcmV?d00001 diff --git a/AppKit/Themes/Aristo/Resources/combobox-bezel-focused-left.png b/AppKit/Themes/Aristo/Resources/combobox-bezel-focused-left.png new file mode 100644 index 0000000000000000000000000000000000000000..cf33abf0daabf36392d7ffe4456c71054c4046dd GIT binary patch literal 383 zcmV-_0f7FAP)3MX1hH|%^_gm3t_(fWmx#( z#q|)<*|Y%wO(G#SiBP&B4|a)TqDO2=canz#-}BCtRNF!bkS==Sd;U3=I>^SaQwcg0 zPV|(N9i6_JIPl~C(VpN$Ky*2-P)DbS2hiVd11A)*K>#9(u<3y(g%x(Td?QQyxe{y7 zFM(A8ss&aEtpBUJVs*KH*@3l}uM6{6A}8k78Yr{809_bchA(1RmL=py%ZH;(qbHxHO_MSM8kyTg#SY#4~Y4@`d0gc4ZR91=W;OkGzYx d_YP)D%pAheX0g7pJWf;SId{U^NmCx}SFo1p)L$AXsa!4_QmLCv;lH{B#V zGrmbuVUt~5$oSwF$eYaj&AfSU@?)<)Y~Kbw79d)P6NH0kBRIpyOAWy#;vBJu*g|X~ zb`%jCH^&}m+5re5Am{{pp6|cG*H4H#JNx-nTYMmSw@{ikjY8oClKep50fRyg=5Aig z9KG!abbI%}Y&RQ@Id$Daf-1Vdu+bp`Bb9Pyf)Py5)!Y!&zipY6Qsug=+)U+7NSQrB zgaD^Z9XE|V!-zbSiU6U*BrX(r{!pq%v;(e>AZd&v0T*0bnMxqt1j@-Z?LY__wOkhg z=fE|cK~yX4CXe1ebuqtXaU3j><4Bro%(JK4)0Zn&u*a!b;G&Npt91YNDq)#VnYc$g5F57eWb+0trb67~ND~Xny>4 zeSLg{>a%-$DkndDettgBi_V4r9v*JbagaIcv3ClGKmvpCB-lr*<{an^L HB{Ts5b>dNL literal 0 HcmV?d00001 diff --git a/AppKit/Themes/Aristo/Resources/combobox-bezel-no-border-center.png b/AppKit/Themes/Aristo/Resources/combobox-bezel-no-border-center.png new file mode 100644 index 0000000000000000000000000000000000000000..0d654e92e89fd4d96dad68dc34fb408cbe865124 GIT binary patch literal 141 zcmeAS@N?(olHy`uVBq!ia0vp^j6f{Q!3HF=8QC&{lw^r(L`iUdT1k0gQ7VIDN`6wR zf@f}GdTLN=VoGJ<$y6JlB7IL6$B>F!Nk9Jow`Ue+7I5g$jo$Vrz2euGm-TE5j?}Ag m&JtkflSxQ$C}nhLU}VrfBy3ds_&5hpD}$%2pUXO@geCy{mno3| literal 0 HcmV?d00001 diff --git a/AppKit/Themes/Aristo/Resources/combobox-bezel-no-border-disabled-center.png b/AppKit/Themes/Aristo/Resources/combobox-bezel-no-border-disabled-center.png new file mode 100644 index 0000000000000000000000000000000000000000..49cb956b387da9c9d5f475145091e098a52395b4 GIT binary patch literal 141 zcmeAS@N?(olHy`uVBq!ia0vp^j6f{Q!3HF=8QC&{lw^r(L`iUdT1k0gQ7VIDN`6wR zf@f}GdTLN=VoGJ<$y6JlB7IL6$B>F!Nk9Jow`Ue+7I5h37T5om{^Qfr)Aei%j?}Ag m&Jx(3e?Kk3p_I{~fsvtTvIx6t&7Si>tqh*7elF{r5}E)mKr2=N literal 0 HcmV?d00001 diff --git a/AppKit/Themes/Aristo/Resources/combobox-bezel-no-border-disabled-left.png b/AppKit/Themes/Aristo/Resources/combobox-bezel-no-border-disabled-left.png new file mode 100644 index 0000000000000000000000000000000000000000..dc9d6ac337bbf0746540790750376dfa6172f9ec GIT binary patch literal 211 zcmeAS@N?(olHy`uVBq!ia0vp^Y(Ol_0U|r^$_fA}$r9IylHmNblJdl&R0hYC{G?O` z&)mfH)S%SFl*+=BsWw1GrJgR1Ar-fh{`~)M&un(!NCWeODG83xV)j%_FVdQ I&MBb@0R8GsH2?qr literal 0 HcmV?d00001 diff --git a/AppKit/Themes/Aristo/Resources/combobox-bezel-no-border-disabled-right.png b/AppKit/Themes/Aristo/Resources/combobox-bezel-no-border-disabled-right.png new file mode 100644 index 0000000000000000000000000000000000000000..811bbcd91911a3aecd3a463ddaa5201b50f8d347 GIT binary patch literal 392 zcmV;30eAk1P)MF&e+#~T{W|YE5CFLqRP(}rDERm9-~VslzWoRK z=q)JXsfFQjz{tqRz`?-*VhYhLl0lY$@X$`CqdvgM2gE2keE2X?hS}QMl4k)3u(7de z0I3r|%#TI-BM_Sb@h!50=-01bU;h00a|K&o1&Ut+%73LalAi!`dnpj3xbpAczc+zm z#X#m$YDDsJple%zMZhZ%2WaqfpaqRU=4ooCqNPAf<^wHx0W^FDkiU}RRD=fp0S#{k zmcE~W>^@K&kYoXo`2ZB5ZB)w#*wXh1EsKE34&;M(G_e3wy?yxb0mPg`)xz%f?b{4! mt%_P|TEIBkvLgfl0t^5^_QKP685%?Y0000F!Nh_kNZ_nv$Y+TsT+23y7^z!`dXda&SbvA#` ze~{;J5aQXQc+U3EnFCv1KM7@1b7OR6Tjn2cx1Pn*hk?U@L3^Lr(<1^~@t@O1Ta JS?83{1OTq!H17Za literal 0 HcmV?d00001 diff --git a/AppKit/Themes/Aristo/Resources/combobox-bezel-no-border-focused-left.png b/AppKit/Themes/Aristo/Resources/combobox-bezel-no-border-focused-left.png new file mode 100644 index 0000000000000000000000000000000000000000..475f79853bcabbc7c16e430fca4f411052558e1e GIT binary patch literal 373 zcmV-*0gC>KP)xe1kCxr`>iUs-)%0-OjV)L!2M&Kr*SxCeo-?42+VAa3Pjo!L|I FKfQ6x|- zM1c_Hk18v&%l%6aQM&oMSo~EHlAo-{ER6Y*i{xp)$=F&8DK!Sqlf1$w!!U~8QQgJY z)W`i`n2X0?9^3?0PHdwCvE5CMnvoH?rFQtup9Ap?AifO551ta<>EVEvT=^x8Tp4TW}5|GaCaNkGLcQ8(S{Wk|#i+mlRuIr>_iV{P_Ks z;o|*Q3_riTWMJi&lK@(v0TezB#Lpr8jG8{U0oq>so2_z&5#9Ry% z0wx%Pm4%6ci-QeWjuRwIH4DITz{m(9;9LeO044?+0}KloX>9=m?Jc0LA6SSn-$V2{ zoPGH4bDW0R+S(Ff0S;hiX9vo7CxDnAi!`W!H2eSm|1GlP;LxE%Uy6!~t}rs9dJ&i@ z|Cg7SUjoX1r8JVC1Ox<>`uh5!xDqIK)7#s-7|47|Try?E8_CD>^72}=wY6V?IEIFX z&w>0#XqiQwWXi_IwzQ$4VZMQZ!3!Wg0~karNlQh9!9Q_v@#aaBCV?uWK4@h{iUmaF z15kvvk(Up!fE}+T$*z;JL^A!#qW@I2;LqRx;A#^o4!%R1GL)4?=N^8B*U9JZ0h2c~ zE4Xz5ZNhw`*n(XruOfIr!x=e67=Hcv{Q}xP`arP-i~@=b$n7GK;m~%`WoW~TG7CO^ z`Me58%kCkx`ABhn(2vwM{RS<1KjLbek_rF<3;^qtuIms<{K)_S002ovPDHLkV1gAh B4x0b~ literal 0 HcmV?d00001 diff --git a/AppKit/Themes/Aristo/Resources/combobox-bezel-no-border-left.png b/AppKit/Themes/Aristo/Resources/combobox-bezel-no-border-left.png new file mode 100644 index 0000000000000000000000000000000000000000..67d0702e0c752a11fe911f536f735f3a5f0f7c65 GIT binary patch literal 220 zcmeAS@N?(olHy`uVBq!ia0vp^Y(Ol_0U|r^$_fA}$r9IylHmNblJdl&R0hYC{G?O` z&)mfH)S%SFl*+=BsWw1Gb)GJcAr-fh{`~)M&un(UW9E@*y3scpLd*q@Z&4%P)II-z6m~l{5TIte+P0asOE+LQ1JWr@Bc4fzWfjL z(OXc&Qwzi6fQ5yHK}bjl#1x`gB!etrWMmxT$#m2Q82Nx03l1MXOq5}^wzh;Vzy<8= z>@vnC`1J=fkQQ&w{^y|Dsv&_aBBJReb;oe{2@KefySS$?}y9KY#wj zkYi_OXNZXmXAl+^Cg=kukPrS~!D1pJ49VdESY4SK83dNcrVrf*OfVmy<8MEIF^EV= zGx#{$p=j`Tb7T+{lLX6S(}&dufB#{}@4o(EFgG`2&{0l;6WH2!?VR#P|$E627 zPvMLM7ADcl-Fo~ ze*b28`|>%1w5Z@76bnFg^7V5kD7Ju$gZ;a-sL%l^VW9|QamLY>9U%Y^U;t&MX5J(I RXi5M8002ovPDHLkV1k-Q<(>cl literal 0 HcmV?d00001 diff --git a/AppKit/Themes/Aristo/Resources/textfield-bezel-rounded-center.png b/AppKit/Themes/Aristo/Resources/textfield-bezel-rounded-center.png index 2ffc73c8b44af8d784c58b18da775a3cf84b7fb9..47b21b4227a44de060eb9603d6d0275aee464e91 100644 GIT binary patch delta 88 zcmV-e0H^|6H_V+Po~-c73q7rIEGZ*O8W8tzdf@svw%ZKx48bl^dFy|o~~zGaHL*^ nbC!U^Z3&4BF$_u!Ogs!%_=I1_ea(3b)XL!L>gTe~DWM4fyY8E2a$=Ec%BPENXYkvCY&mXciAN=<18`+xIzkmOp zY|Y0%fBt-dSldxF>+9?P1yW_NU%zG`D&WvF1~hX_c=__>e?kCPq!vGa{(RG`SFi9| z%!tc*&;nrsFq7nnh=_oTAEGs*6?|PlLkt821Q<9uIT?WE8KgKOHbtS8p3*=p!8kN) e42m=Z1Q-C=b-Ir|2f^BCG~#o=lKbS(C>jZi~TeA?%ARW2CO&@e?!7M+dTZp14uPQ-~$Z`0Wdh++3{H=(3uC?p`{9_yhe+n=FhHa7fHe&^1 P00000NkvXXu0mjfRu|T; literal 0 HcmV?d00001 diff --git a/AppKit/Themes/Aristo/Resources/textfield-bezel-rounded-focused-center.png b/AppKit/Themes/Aristo/Resources/textfield-bezel-rounded-focused-center.png index b5dad6f9f1f5dd9a65b9e113e5582f3fc914ccb5..e1aad4ee2081aea77d8318e9fcfa11e558ae6f91 100644 GIT binary patch delta 99 zcmV-p0G$7o0i^+uNnA%sL_t(|+G40$d)tDEfq|iriI0ajjOovtTMP_`t~~wE@E-_3 z5)8B<&OQ9hz_jb+RR$(T0YwI;PhUQ-0!j3P>}3E5FaW0L8PE{^C{_Rf002ovPDHLk FV1k*ZDSiL| delta 83 zcmZ3=IF)gNr;oX(i(?3fY;r`!tBE$u6FS%he>)thZ*yH;{x{vC{_DB=wsLv9zv(|d nf0ys&*zhqyJ8@d`+=UDbWp+9K5-$@I7=Xaj)z4*}Q$iB}sm~%H diff --git a/AppKit/Themes/Aristo/Resources/textfield-bezel-rounded-focused-left.png b/AppKit/Themes/Aristo/Resources/textfield-bezel-rounded-focused-left.png index b44bf2c1c8b8cbaf9bdc9dfa34156d901333e9a3..66a00a37e8aa72461c6e9ae03f21479fc8e4486b 100644 GIT binary patch delta 812 zcmV+{1JnHV1;qv-iBL{Q4GJ0x0000DNk~Le0000F0000U2nGNE0P|c#bdez_f9FX= zK~#9!jFro7(?Ar4f7|0*?rBSDo0h7S%K}8H3X3kdDhr+g38@d!hu}$g10;};5Nuc# z(GBVbRY_^-B@KnxO>B=noD&?CN+GqSFZLq;{4?kLKGt5o-N&fwx7X3>W)gX#nBE;i zh!G-#ZZ0uK)QEXvj+i1Uynq-Yf6`K?DzQK;6RSdq$HEYEhG9V0G-!kvvc()RO)L?0 z%e0<5wpCPN7b<8Ykv+t51gPXpoI2)Hw+G~~W(xD3i4gG#)rAB(*T(cz8P%c<$28A5 zo9THTl4#wr?Rn)NA_+UFO;m7e;Sy%5ITT$BjwK)r{jWGJ4xe#}9s9!0e;zay;>q$N zuFq6a%9$_?{ak$p&ThKhI=QYW{|GuHp54EJo3%1+(HPnhJuMQqW0{L%(HS-A;pyG0 zBZYl&dRFe^Dpxi3TbP|3$F=Fv!hx78JkNbpQ5Oaj?krAHVFWI^^fYo;H~=d2Q7Gmy zRdykCEt8m?FLQE00hpaAf1}`B>^cy0$jcl#4#HT;fhF|JVy=qCSyf12TUI~2S;a9C zDy1mwI-*D-q35jP9`UO$Fif2I0YaH%7W>3O9LLavi|?%t{2+1SR`4<9F|a%c^V`ipf6hOL4y z*c`x&26p(wt%cXKoL6z*(n7T4@IMh%c0b*Tj{PUyOei;goo^$SKE{ q*h&XSVeqZeRK_=G*!4$%0RWccI3?_&b^ibW002ovPDHLk0$_qDjCT(J delta 731 zcmV<10wn##2K5CYiBL{Q4GJ0x0000DNk~Le0000H0000U2nGNE0LnY{FOeZAf0s!_ zK~zY`oz+WE6Hyoj;2JS5(1gf>#u(kG8*!;Wz#B_VaABfxp)TY{s7u*<3nZomsUfBk zBP9{!s#GX6ZIJ>g6znCowYC&2p!D|op5Zh!lj(JmXF2bj@0@SGqwAUp=*l=i2k9^! zrAE@z2|7uq%DsGuj!+YwrHgcxe{Rq%xyf%-((EABp?*`FL>Jl1cz-{WJ zfN|P~PKyn1-VfvBpcSK&4ouk>V4w5A>0W_r!HdF8td}LU%7B=`>V=_ie;fnD)0lBC z!Lu4fFcihF-wDJMn@DUVv9Xy%VHtY42ciVO2rzvZ$HbINc{v(OAi2GR-Bb#hOcuFZ z4ms>S`4F*+W_m~yMw=f!{a<07b;B2o;7@WJ>2yYUQR~skMrxAh|BO<`A&0U85wNxW z7ny7p+OO}2h)z61_h{5OfAs^F5gR<-fU*J+Q0~#mR=z-w=x5iM8#c$1vUy4gWh3@N zL|RhfVq_J>gKhJtSxQ}ATGyz)mTOcUR#)mm{|{3&TBR^ShiU)- N002ovPDHLkV1k;oRLTGV diff --git a/AppKit/Themes/Aristo/Resources/textfield-bezel-rounded-focused-right.png b/AppKit/Themes/Aristo/Resources/textfield-bezel-rounded-focused-right.png index aeed868998a5331cfa617ff6588fbdd8841208af..53711d5ad441e26edf8d0cd237517a96a70a3cc8 100644 GIT binary patch delta 886 zcmV-+1Bv|K1&#+HiBL{Q4GJ0x0000DNk~Le0000F0000U2nGNE0P|c#bdez^e*-W{ zL_t(|+MHF(P8>%RJ>6a1%rG;I4cIsV#{yZlBPB8lN+cF}C`uM=@&T;!2ia$pU&t3E zD|_WHz>nKgp^9F zVqAhel`Ph%DttOM28ROcB!p7xYYtx{YG;y_ZQ)9@f_l9Mo%Wy{b(O;(iQhBHV)cr` z#OM%nkKj0RZ!mVQoy9z5V|Zwghm*p#QkE@Eu4(T~a#m=(@)P($0LvXL z>z%_b={RSSgDA&xt3#69DU!2n(U4EyIcBbFJ0V&xc3@S9!O{#&hiQvw_G!e`*C8JK zwT8@cDKASSP3~}Ne~FOZR;YeCN~p4<5Mwq8UAuxL3Wapvbd#{Wx*~jD=<+y3RS`#W zTz}aqcM~GRZBgalxbzv(HGK_gX>FG+D94*##N!A`RZ}{W98>Li=R8zaDw3f_`t+)8ykLl*6~mGF9?k_P+oF0O1OobA&R6tN;K2 M07*qoM6N<$f|zfgL;wH) delta 710 zcmV;%0y+JT2j2xDiBL{Q4GJ0x0000DNk~Le0000H0000U2nGNE0LnY{FOeZ9e*%F? zL_t(Y$EB4^Pg7A4$4h{)KoTMgn`m@n+=yF007l)KV2p{z4Q~7tF7*Q_1QOF0AvT5@ zA|cff6M6I=tAf5Am?4x9kTK)0NXKNhe6=71iIg8N_uTm=_IguS4v znS>4?36{Vka1RWDv!Gu@^{-^|xruZ@qklzDW-K&5^M=OfU8GqJv#bPGzymN0&V%Fo zMJnG$h`j5c$n6i1&Ama3?>zL~D4s}DU@J~e??;+9+e!0ci8R&_i!wqqEK=*0imf7?DpRdexm=-NdwWzU?ov9F ztI3vaKAN7bi=ra6AyMq^x@7-hVX0K6?}Z{o;wiGa)@f?)EomK57A=cn4~pyWI8Y)* zSFTj(NAYJ(#1Uy1JW{dwf7Y&uKI&{Lkq(PEB2LX{L7{D*NnHPkXvm&JB^(i_#x>$% z>nwhjq(nn9Na?hQnJv01H2eo?w+=u#{d8T07*qoM6N<$f+NH@asU7T diff --git a/AppKit/Themes/Aristo/Resources/textfield-bezel-rounded-left.png b/AppKit/Themes/Aristo/Resources/textfield-bezel-rounded-left.png index c4d22bfc2e2876806b7ff0085afabc86ef1d1e22..39a880af9e406a4f3d35c1e2da5fb091f5a36fc9 100644 GIT binary patch delta 422 zcmV;X0a^a91j7R%iBL{Q4GJ0x0000DNk~Le0000F0000U2nGNE0P|c#bdez_e`QHT zK~#9!V*LOAKLfddiGcz@k!BWR6>izG#T7{T0kI_zivqD63lW-}fK)FtGqV9NFE0Zh zA0Go37Z(F3Cns*3ftr{>npjv^@Tz?xWDSs8!^F)%SPVb=`RxSE@rJ5WnY zi$Op@fPsyTje(JoktjcR0i77Af3L640CFnGCTxHaJ)S{+WM^mJYiw)`wh`n!QlhF? zR#ujQpPwJEMhwkBTWx@$XrQR5h|{U~Z1xio5djAdIVsFZOiTG$v7$<}=E?c29xYhM52#S5}EAOHCAjq^Ebi8@<<_VWBUHVT5;7a+$4)^ijT z6c{8VB#76HR`7KJ4KV;2ASfuv07`|xJWp6Nj?z;ah$R?@W{p9SW`F<#0J7(kQs9i1 QI{*Lx07*qoM6N<$f?*S{UH||9 delta 531 zcmV+u0_^?61Fr-jiBL{Q4GJ0x0000DNk~Le0000D0000M2nGNE02}%iB#|K~f6+-q zK~y-)m6Y2{0#Ojg=PBqZ=qU*L!-D>Rptp*odgx9_H=?rWMoO86kT1caC2F z#V1tXHp*|;4jap+jO(sd`yn2APBC~H!q9C5?;oQ06pdk2lu(RG$U88gM`tRZwQODQ zI=%dGWygtObupLR2v!m|avuBzXyW zO)N-q{elh1(Hdq@)sIUyX#$Eu5p@$(+lWHP3=4bClk)5EU09W2c{GNNFt=!j1Gle& zKv&*qWJB1iGjWhQ7SpIrw4?YPLgiNof5jc>2Lfx`hfJK(v&&FT_%^aa7kGZg{R0EJ V;&Z(8LHPgx002ovPDHLkV1nC)`8xmr diff --git a/AppKit/Themes/Aristo/Resources/textfield-bezel-rounded-right.png b/AppKit/Themes/Aristo/Resources/textfield-bezel-rounded-right.png index 8281342b392227e04a46bb724d3ddea9d7dd6bbf..8aac94d7b0ed25d1330dc6e13794f033568b3241 100644 GIT binary patch delta 473 zcmV;~0Ve*F1oZGGekxHd* z==M{fXtO8mL9tk5V->n}8R)1)QA8$_L7`CK<#XV3W)CDuLL!kU(efg2f0A$@IR+%x zfng3}E|=r!RjBl&sPk|h3Z^~ta25*Y3?wl_!IWt{e1w8^UB_;<`Gz%3gIBJ>U{zIN znr73hcmFV#Yq#6w>Emu?9fjNNHb$dSbzgUh9)h^5wpuOpdcB(05a0_Q3N!{P9S zmiGrc313#L6_(2-#^bRIFA~)B_SiVqJ>8Fye){R2KMLl5{xMF1zXTWnrV*J5Jt%?N P00000NkvXXu0mjfVN2C@ delta 503 zcmV40#Ojg&r{%2;8P&<{|UWS6xBm_BDxW!MpmSlT_`d%v8*UEH7ymavNO3$QQ)#%pPeJVZ4x$$^*bkh5&FO(jv)$V}YOW&H`gYwLgbygtEfhcyM9AiH zz-OM}E|HSpZFdk%i|bc?+Bp@0AJF$hAIRqgc;qv18M^_OFHE4fcf?%re=Af}7eo=B zGA|NHidbsnpHT4-NQzXd&FM~}Ih7?LQlwI;M>5B-;82%@ianA!r>KVGu*ibwkgIVV z$CfJ)mkm*GRHEnLI4c_xvBbnfnl^_o8}bDs5&7lew$Pg4e*Vjd@+`*zb7*R8SDmubpEbA^aS7 td@+EwT5&OJuxaJ$hKJz~M^gA4_gAsN^6MoiJhT7+002ovPDHLkV1i8O=n((_ diff --git a/AppKit/Themes/Aristo/Resources/textfield-bezel-square-0.png b/AppKit/Themes/Aristo/Resources/textfield-bezel-square-0.png index 1f0cfabe59ae5e1180640329ac6a4bfc7eb133f9..9277864a32d97d88aa9a1dd0591aa3444599b049 100644 GIT binary patch delta 125 zcmZqWn9Zoz8Q|y6%O%Cdz`(%k>ERLtq}f2214KSJ^WI~kqIxict*47)NX4zBKmY&R zGn*Ya(!l&+N`m9FoSU0kc|A&*3wgR&l$Ddk#l^$tty!b9icg{A>a}ZW0zyJb3>*dw Y%WOI3JWiQ91!y9Jr>mdKI;Vst0O5!ykpKVy literal 1029 zcmbVL&ui0A9M3kbI@n22RFFpoda=oSNt<7+j;v{1(QKou*o)9Kd2Pd%yqLVTSq}<= zpr9Zgyn6KJAD{>EB!Yi|e}WfJGC>4i`eQ1L9SkJzM?Rm=_xF>njT=jg7Z*8>TdJ>H z4Yn?@_r&P}``#=*I>nX?wAP~Aq)Ufxf;rPC9SrKB+rtg)`uq1j;T1;e2F(_2Ikyat zgo2x6ge;61o8wkiv)J`^Fa;gl3!)1D?cIAG1b&6TQ+A*eS8+dBA0>Euw9)iNJD%?I ztJlFwW-x&eQx|06Zj>5Xg&*r0Y@c6?JQzdhPKBR1)pE8#l_VIH1z7Z;0)c`AB$rfG zy#^$Rpa>-qNkya@vSdIArVr1oC4SdvSoYKwJ5~5TrLiH3!{JaE$^uDxBGPp|*N~(l zLlo2fh`L!ZN|$E}7EZk+h-p9~kSn?!vPUaC^K=qI7(33PaFk9H#Zo3_ZY&}JieZ?? zHAbhjf&aL1Bsy*G$5?FOl4DTTEyE6aYXA@g=c>R zKkyBRG>DK|f~o`+4Iv#t-Lh=OHceYrENP~3B)5dhimB-}S=AA;Yz->Xnqo_)Su59S znmXgwqm;Ulhi7(!-0p;{9m_SU33e$-nuP4mI$*0$C`tPy2G#8{a9l5l@^fCENwgMD zf&upJgoI$6Un4lu{=adXa@jVKDYHPoQcdCF>j8)nq_vyIxycJwmv%? z4iApl#3XDq?v}15Y^=(4%WP&}I)1y|p6}cSFHd#~&(55^^7-xP``1f_!C-Lkdh^x& mAHRMcJb3=}{NuTKZmz&ZFV0yDA3t2q2eV$=u->e-AN~d&NINnB diff --git a/AppKit/Themes/Aristo/Resources/textfield-bezel-square-1.png b/AppKit/Themes/Aristo/Resources/textfield-bezel-square-1.png index 72c8add06e0e4df8da3810730fe8256d7e963bb8..373b4521a124a7a6e79bd3eb77b804d05044c45e 100644 GIT binary patch delta 78 zcmaFE-pDvXoQsWvje&uIN#Kj&L`8K=24znd$B>F!Nk9Jow`Ue+7I5g$jo$Vrz2euG im-TE5j?_0WFf%OR<~_NsZQEa?jLFJ;v)5S>*0~LnTmngZHvX6onkREI5j3!aJ@li$6*jg&3kHM98c| zQ-ekmAqzpvbv?s#98Wh~tWR9B({%k63Fi^J*g&_qm3CPrg= z_rpgqRyRAY(=XnShQr}EQvCe>`SH_Vx8JOM(xjDZQuoE>A77sBT`lLY)82JoZV#XQ E2IgEf2mk;8 diff --git a/AppKit/Themes/Aristo/Resources/textfield-bezel-square-2.png b/AppKit/Themes/Aristo/Resources/textfield-bezel-square-2.png index 3679527d64ac8e5f4af0ffece33df268a37228ee..8a25d7d5670b94a5b3fb8534315fb9ebd970458c 100644 GIT binary patch delta 131 zcmeC=Sjec@8Q|y6%O%Cdz`(%k>ERLtq}f2214KSJ^WI~kqIx8Qv!{z=NX4zBKmY&R zGn*Ya(!l&+N`jf8VP*O2Yr2{W_m(eP_Dy`9GZ0LeJ=?l};>3-dM>SYkS=n-Pa|NtL dBbgKqFl5W|-BQro82~hw!PC{xWt~$(696tHDkuN| literal 1033 zcmbVLJ#W)M7BWkC#xk8=_ikg5(?vhTys^Ss}WH`Z><&0d-1IBu@7YBt$= zp1l`lrrGyq>Cr{DT&7lswn&c-+yrxmPr4X1LU#){vFjh)e~T9wsTZ_6wBy{;JrW9T zjuEmjW^9gISjuA8+rboc@m3Jk_~RF^co6tC{!Yb#PF%TI81i#!-X=uV9vJJoSEK%FEQR0LS^paOw{1SFSLRlNoz zh@c215lJPa>awIm2qq8DtR;R=Z<_YR7CY7WKBciPii5#G7{~%iwnU_9TCO2UC59-a z2N89%Qk2dY3MNjyB#3E1B9JS(U9v}OJo9uMLKr*FiExxo62(#`W^ODZ0g7Rm$2CHy zw2A+?aVk1(AH-N};*{(q9;-)hz96&Qooy%wGH>+tBw$5xcTM8$g*c)Ov&OSOf*<%g zL{*58T863wl`29Sf|_aCiftISte8@vaVobgm8(d#ELqhMGVLl@rJ;5#|Nt=+}q60Sigp#yRVo+~Yfa7{Wl%MnRjH5Mi66|B& zPDltw`PG9{?f)CMAy;ez88QoGrChZkKjHfSlQWSyBj(NVSF;pXtON7yN$a!2$?)Ka zO-#Z@W9Fq%VPmB=OrxEB==L@@UaZeY=kcwMLKmPx> lXXbf-W8-6c9tIW(hIcP@;vX;~Sm2z*1*ED2mhAiR^E~hO>*J#*JKOiRB}v-p9r}H--VpD` z)~5L0|9a=WSnl%fke|>AUtmTgFQ#JxdMTcgKEd(%i_fGjNRwnRrtON<-5c0?{bWGmgtf zR_xXaJ}DxW^EB4uica}_C2P17o_CA#2!^2d!U z(Z%3ACu*M*bj~7CkI8OL7P-6LPz4m;IL}xjih|F48qHIZ@t*I>;*Sz1u>+9>5i*<5 z)SzJ@WFu(%eqaQi7wCqs)f!iFn_AOCme$ox8zDciprIWYf#!MLR<~=JHMf@)9A^=! z?IxAo6&GF0bvle-PT7Fcv$_M0XOz=oMsv_PX@L+&NmiY!@~oou2}@p*IAAmd%ltaY zmG=LQ+tXWthdf;ba?rE_D6hHk|Kv;+&Zt#${M9V=mFU1~d)fNpa5+3A6BEP4XncD6 s=Ajs?+dbbKlwZc9(J23U>!!4^DLvTR+WYlA`cX|?uY2UbI~cwC4L;{BVE_OC diff --git a/AppKit/Themes/Aristo/Resources/textfield-bezel-square-4.png b/AppKit/Themes/Aristo/Resources/textfield-bezel-square-4.png index 6dcbf53ef69eab07396df03ff3f893fbb0383576..b9d310c9103991a26764dacab462ca493ced76e7 100644 GIT binary patch delta 9 Qcmcc5o;$%~@-Ajo02F`&p#T5? literal 991 zcmbVLJ#W)M758XS4uP5l`qD_f_HPDuld@<7?rfS|>`ROs{dNBMs_#F5_CFD?T89+_({4jTR-* z2c)8BED`mX?lfePyW0&(pzy|f!7@=4d>Yc^EGGr;hrTNQXla&u5IGPbyA5pvS`I=k zf^HZ_Rulx0X@y3kaU-{Fv>oJFJ=1m(3L^(v#=aF9LD1{;dXC+2`$ffZk&wo2Che}c zom;tHml4b<8&P`NbimP!a$3!33A)1$h;fn?@+`}t#3E|2OWy z>_hdsJfsj4!^CJTzCJ3%Sl#c3 j!KnT=`E_-*_w?S6I z@mr9P*pOi6FEBB&vNCc`;sR3D0ZaCM_<5f9`|aW2>DH|Ww-iO$>hI&BTyMyCZDU=2 zAAZ04Q7-pIZ!C`3RLlvdiXXEH1^tv9(;+4C`OB|#SCXd5Xe`Fzfg7<@BNav~(_FF@ zWp}U4NpwO5n9$=S^VFZ8zNjFHJ@t7jgkj#Lvt<8*)1!;QD7rX_oLJp^0(MJR3ZzsJ zP^PC@;g+7d&~@d$y4F>&fQS=MT{<-m4?&l43R)U$M9_l3LK-rgwrxKG21HPYhK`H| zvR%_~Aq1;OmDYGXb%!`u*^(zuoe7bDm`6>kmg}{DV!CnM9GxtCCPQ9K|M{YxEAO_4Cx;?u0$83 z^PK8KTCg)7$$Ct8YO>7T^@b{-^u~S06Im2;idl4)(oFQRr^-KCoWw3fZHSQFgth^# zHbM@94#t5M_QTK^s~|#|jMJ@3nfpwq0}kSs_Rk(b{fO z*({Mx>`xw$z|*47n#d*ktkciV5Osq6O!_)$NCD!2du diff --git a/AppKit/Themes/Aristo/Resources/textfield-bezel-square-6.png b/AppKit/Themes/Aristo/Resources/textfield-bezel-square-6.png index 8bd048b991434d841532c20d0ac615cb421eeffc..657130254422d6e577ed696b45108066ad3b5712 100644 GIT binary patch delta 130 zcmeC;Siq>*8Q|y6%O%Cdz`(%k>ERLtq}f2214KSJ^WI~kqIv{_lc$SgNX4zBAOHW` zGxNN^z5V^$_3``vH8Th^Yem%j|5w{)U;ocwgF?5FkTf-Q9m$f8ZVAjjJQfUo doDB@j45B8=^`^09Q-H=Yc)I$ztaD0e0su<2DhdDq literal 1034 zcmbVLyKmD#95w<9s#LMCKqYi?rHX;rcXndORzu~+F^#B8Nh6VsIQFHnTKkNBC2kia zqzqj0#&e9+_UjGWu$Od~ z1cH-cgfxg4o8#u@)5vkxF$FEW=7%Nz%kvjJ@Vyd$r(i=nD&vm7xEo9r z!Sg*Gq9Q~{%|lg!N)aIqLCrKR#WD;_R!nKEaV$5Vm$bZORb*8|$h3-3krot7GK@;0 zQYorqZZ%A(6S{b8*U#(@xs?;SdO5}pC2^gQjd2I8bOG1R0 tg9rUzKOgPCe@5Q)dcE1*-Q8L4)C9Nxak~8B@spiwI;)js^XWqK;ctZiNO1rF diff --git a/AppKit/Themes/Aristo/Resources/textfield-bezel-square-7.png b/AppKit/Themes/Aristo/Resources/textfield-bezel-square-7.png index e96d14560105656624b9226f867c1692b74fc192..516547dd324b7ff0470f116c2d6042fd885d19fb 100644 GIT binary patch delta 72 zcmaFLUNb?Qi;aVgfq{WZ;EUlzMRgMfIZqeIkcwMLKloXEcpMItJUGC}#-`BEc!*Vy cfsu`2ZzHGEySqPCfLa(lUHx3vIVCg!0L;J?+yDRo literal 997 zcmbVLJ#W)M7&an8P*E{4fP{2%B_?9u`7=J%ZJju#k?OWegUHCmzBE>ApRupR?a0Ot zVT6f|fvzmfs3U)Xm63BA7m%tBShDZK&-1+B@Ah|}udX~^ktAt#u#uZOl5S6v(U_0J9UQS#AvH#+(p<15 zX??TGNpwUxn9#!{bLF3(zsMkoUHPRM!Z7dAS+adr(1WwxQFL|`IkCLC0oE%l1X9Wg zsM6!C#FZ;Abg|gi*QyK_5Psy!mrjkteb8eC1*QVq5wsw%kb-o>w(Vy?g9xfnQ<2t2 zHr6!^Ay_`LuvWxVJoJO5Epc+?8Rt1x)%kp`%yoqohbnR$r`FK4wm`JY(~Ogzn<4$8NZTtmGt%Xk$02 z?HY#W7`k>N7xxNEI4ees9XB1YKVzJgGnRwifeAtqC0Tv0%X1m6PmAOYje~-vV3A*( zTx50I&XncJcIcm0puS8smERLtq}f2214KSJ^WI~kqIx8Qv!{z=NX4zBAN(x) z>;C@QpMQVfb_X?P9^=11Kes>p_xCrCgF!nZ=LQ+eq9?W!;?A5n5z(!4kmFJtuYutM f1`AaNCLRXcP{rBofg4JI<}!G?`njxgN@xNAx$i8$ literal 1034 zcmbVLyKmD#95&)zrD6t_lRF_b_MPp-vDJ_|ahyifrAi}_fdR+9G*)Y$YhQ`m302C# z#?Xy{k&SuE-}n9A&sSF(vom*QIF6fbE}1R1 zUS{u=8`s$PL4J6hEw^dCL)S=;4xAWshDW*>Gy`WHx3J^wY`w<|jMVen9on&%b(aK! zlVOB3h!~sW7Ak4vxEq*)E?)P;GJp8?9S?l3%s(pF(2i=j?=S7fcx`v3?e1>4n#Wh} zgN0OQ0s*EDNQ2EV(bF_~%p58L8i7j?2^LzJn<|(%abrKCJ_$jl=yb_8E%VINaR@&Ch0q`ebiv4s<|9lNX^y}2owU?skAf+BC~N`y+V1 zr$bbN2&oEGC0HyWq#>x8rd6~I!;*`pG}Snls}z(%RW|Cfsv%@rC0LZIMN2Y_dZAt~ zsZ(wQGIE?5RKWEMzODOr%8aJ~P@naG?Gv*!4xS*BO41GDXE>$Ah@ z@ZgY5Ow2~(=rNJlSm{mEXs4gLKW|;l<#Jz^7xzAYcvU$Z4u>c5@$ciKgKr;Se{D1x pC-}wwzH)DVUitOo;AL*{*(L5fzFQgI+{%WVYt~oHH`OP5e*nhEL!bZv diff --git a/AppKit/Themes/Aristo/Resources/textfield-bezel-square-disabled-0.png b/AppKit/Themes/Aristo/Resources/textfield-bezel-square-disabled-0.png index 86d3a0b3c1bd16ebc5040f8eac5b24be630f5dbf..9d9c481494545014484a74ffb2b843817d2ca8f1 100644 GIT binary patch delta 125 zcmZqWn9Zoz8Q|y6%O%Cdz`(%k>ERLtq}f2214KSJ^WI~kqIxict*47)NX4zBKmY&R zGn*Ya(!l&+N`m9Fm^~E}c|A&*3wgR&l$Ddk)z#DItyrP4icg_q>cokO4<0;7VBj!d Y*p|%E8k; z17hM6@C}%lU|?b48z6)j8DL;wL{yxUxPVl3z>zPYk|d70z5mDZNs zX6FKX7tb%T@2$#{bL_Z8n_ap~26W=3n6m=X$DkE?d$^6g;Nbpyyum<&u+ybo_qO4a zNbm|9A&(M<=D3Z`Jn{T}OhF&-g|W$hfAf|HVPNw26c@Tl0}sQk!xZlxZg>2{eP0jw z%^P4NHyA;LsR#0C6lX?m@>5=e-3ztIgQ*GKH~CpmU3UjGNQ!|Xz={u52vj5>xvFW} zbs#|mMJS0#svymfB?Ce*e|Y9C4F*QrcILjAWb#8w6GIdylZh~q1(NQGNZ0j(Ly{`Y zqLLlN)XOVzwq7#WIP=pmp&^Mu!RYnLn3_C`be2Mtxb87=oXrcxN+#xBA|e5bQB>qL zwa#c8{|Vzn>#TE-V6lxeGERNgkHLBgX0%u=ngrDvLOO!FZ9A%CS&ppQQps^5R&OdzMN*nF10vh0K~<`&j$~O(->hjR zwiRd8i+x=B4GX_BZ1q&E(MYjJN!lS~R8GLokWi8hNdg+X3UEC?j0?GF&n#OTr{Mz} zI4Oz1w7y1olK-84<9{94*UwXcJ?e42jugBlcF08G+`1F!Nk9Jow`Ue+7I5h37T5om{^Qfr i)Aei%j?_0WFf%N@$LG6f#{qSqJ_b)$KbLh*2~7a$Y8!6= literal 1004 zcmbVLJ#W)M7&f8;RH-Wh#Bg#aBx2v$@uzBv8^<&fPNOu4jB)HsVzu^}^Od++kQk8o z4g3To{s03EEX*v3nT3gki3QF{TtKQiV9CA@zt8i$pD%me2V0xBHU&Z0>g;=czFy+* z#@#4mU$Q*VFt!{nq-dn{p~vuB(Wnt)&dyhEj&y17Ze{Zx`SwO6j`yjdk^fC zHYZ3i3qhG4XN6rl;*!_q`|4U2!P0~sIpWHxVbB9DLNU-J*odGGfsQ1kHVwnL3lxZ; z3>6tE4P@A=VnYblkI2<%JhA(pzt-X>N1QR1+p;{L&!xF45jvHTWmy%6qBOWgqd3i2 zST?d^yJqlk5z!=P3CTdk7>>yab42dxDugr-f-~Z*SSO07OfJJ*MiP|Mw2EtKU9dj> z&Wyrm;4`{-R5*~XbI!STHI-Vo)KT@2;Hbf>w z$Y?@Cfx3y1g`nkmzV5rOuj-ysbDW3OT8d?PI&7<^f{^E%P*?VJUvb^G)^3|djqPLw z3$qB&=DWyMErj-(rVqt6HvXTS$=n&aYL35}rM}`FSZ&W*pC8VK2WNa@ zC?AbiA6{SQV|BaZxr6e{cr+UIqVngDZ_i%*y8nLTt0HXN5W42oPmAWAQ8j;^cGr8e HH+udX)~_=k diff --git a/AppKit/Themes/Aristo/Resources/textfield-bezel-square-disabled-2.png b/AppKit/Themes/Aristo/Resources/textfield-bezel-square-disabled-2.png index 9a8ffa1bc3eda6af54a91ba83a2ea00c438a70be..c16b43a4c3a5a81777125387bb081b932042eda8 100644 GIT binary patch delta 137 zcmZqYSk9=}8Q|y6%O%Cdz`(%k>ERLtq}f2214KSJ^WI~kqIx`or>Bc!NX4zBKmY&R zGn*Ya(!l&+N&+7bPtEsFPrWr2?x`y(eiUEl92XZip}SkVf8xZAoUW($*Z==l|NGn9 l|3|yU?>EUX9cEx;V`$}8(wX`yzXoVJgQu&X%Q~loCIIx^G6Dbq literal 1031 zcmbVLJ#W)M7jUWgi;@FqQYV9-jmAD-k zkQfj@gBAD#3``6xj12sR4y78E3Yo{WsxCTm13ylL(^F79Z9;=%sZsjMnxtvaz?`3HG)EGZa^D zgXO~F1TkSgDB|rTw+dSv^ICjgUdtjFo3JfgJa($(DoY*R+2X_g#{QsEYr zd^cf!QAzTpDFY^XkVPqrXaY(`zfX6VEpktfLx@w)J0VW;NuqelB$&j}%6s z1(5*}(yLHcpk^RsB4}dlYOdqBs)m&*$7$GFT`^6pRU4|IAcS25YRanSDvr~rH5!IK z#Ws_i`AI;gx)Il%VAV6RRy`v=qgjX2?P&+JhLq8KNK;VXr~%IpqNF^RUaZeY=kcwMLKmPx> lXXc6DS@hJNhk-?c;nP%+>_0k2$AM}YJYD@<);T3K0RYRc87%++ literal 994 zcmbVL%Wl&^6m^BDs)`D!Vnf-CT(KkejNSO9n##?@G!iaR8i_13u_uYu+GEC3;+7pd zK7wCBEZDJN%`YGp`~g3}f^ixbkg6`QWY5F*oO7S=`p3_|AWeMrWjlgV(V_G7=#tZu%j02uc^bQkdhitNSDqxu zs34%q&hpZ$e09m|$$fpTt6*s&PJQ*tsZrDi9mXkWYp@kV3jzyi$lSAS`w1{0f;u#G zWVDd&nT7`;SUsv#IUak@)Q>Is>(2)l9EUV*MT9;x#|G06Z zbve8!s6L=2JLj>i$8@&=%iP^AR2xcfycax`MImRH#pfB#MGyO`{G%ml;z8s41{p#K+8C^LL&&e?QYkx8*DEx1<7OD z=%!M4g|%WG*_|%>+N;x%ft2X&|FRom!t9h t&Bi@BR@*%s46ARG@p#<-b^oriwyr$h-q@L%AK%wg*XthR4~OHozX5+xD>(oF diff --git a/AppKit/Themes/Aristo/Resources/textfield-bezel-square-disabled-4.png b/AppKit/Themes/Aristo/Resources/textfield-bezel-square-disabled-4.png index 2e66015bafff42603809691033e80fc2fb91aebb..b9d310c9103991a26764dacab462ca493ced76e7 100644 GIT binary patch delta 9 Qcmcc5o;$%~@-Ajo02F`&p#T5? literal 991 zcmbVLJ#W)M7Uv zgEF0Fg;TonlGhRY>ROe-(u7Z3dF9j~JOeGt2xuy>5kUh211U&9FimqGXb?daYAVti z$aHkgfe@@8S*Wpi|8~*ZC4zc)({qrVv%uNHnL)` zX7EW7u_WgS%|OM7hjhkWS$Mh%AXU9^=ULqNyadF^JqZJ9N;lNB6i5vg?( zp}WSyTd_`y5zHy;Q#!3X;A~7eEygqltzHv^I7+hWT$N`Ptxs6;n#2L4DOl#$Np8@G z*1vIkdNc5lr`re}A6NmD*Vy=fa;6Gr)T%lDYL@y+bYQjJw7xiOhKFQgVwf0>H~TNX pi?O=j@x6Zeb@=Q0`snf7E$Qyn_EqD{<&SFQI_*>c!|}^^zX7jjFN**G diff --git a/AppKit/Themes/Aristo/Resources/textfield-bezel-square-disabled-5.png b/AppKit/Themes/Aristo/Resources/textfield-bezel-square-disabled-5.png index 785335b230b3811deccca1d0f88457ea3831eab9..1bbb21e960c21f11bf72a463d765207ff117aba2 100644 GIT binary patch delta 84 zcmaFFUaZ&|;OEZECB?hB` zFd;E8u&^+(GqJ+L%E&p53rJN5EZO(r_j#W8^VQMe1!WWnk$xrB*fPRLjWI%9oe)gH{3D6`Rj`%2g;>I*naBZVhSs~Dp zw6|XsI6fg9jL9_3J^AN{k1|LTPkv@ZFex|Js{d0nxuuT>c=P56l?Uph64jzE_(0t^MVVrW8OA_eJf%d#E<4I-#QO+{J@ zS+1_R5Q5bs3pJKZ+(8how8Y7iXPg(VsxB4_WuYsSO;zMLPR*fdEn(3r&vTBeR$lHl z3;`))mKHpvIj9-&n9jK;3r{aY$ciYsBF@WIqD0En3KuF;pqgcMTubYc56B-kuC*?Q z=LJy*q@;5ei+W6U8?eaT%|f-I@Wy@0Qc)Cq8qj#2k(~DfPZocaBu!k1Y>1H6hL#3R z8zBclCkR3_^!-pb1Fhk>4r_FEWSN@L(`^l*Ahe;Wb<9xn{hrb5*;a$?=OxE^Od8!( z=&rEs8?kPe5zHwYQhM5Sz|o9yTFz(zy2l2HaGd7#xh~ITv;kr13zCG4W?-3LH@!w5 z+W*Gw>qh7!Uw07dwCxbeD{S&VIa7r*YTX=vHA{0PIEb^Pnj?X9h?*V5X$)cvus({jGNucxlxI}F}-p1=GJVqz?c diff --git a/AppKit/Themes/Aristo/Resources/textfield-bezel-square-disabled-6.png b/AppKit/Themes/Aristo/Resources/textfield-bezel-square-disabled-6.png index cd3848f179f2a232c81f361ce23f8224405b2752..34f8ea207e2bfe55d7d1638aa176775b272aaccf 100644 GIT binary patch delta 123 zcmeC=n8~Qv8Q|y6%O%Cdz`(%k>ERLtq}f2214KSJ^WI~kqIw{MwWo_?NX4zBAOHW` zGxOZvRr>nv{r&a-n;C?ewIcpJJj}j9Nz9~k)As!PMofh|${u3U2}uVS3%nRuBp9;W WRP2L)>zn|Z$KdJe=d#Wzp$P!^c_V8b-Uo6WV6X^H?+ybWa_3{K~Mw* z5&r`{c=F)En|SC=uzK+-c=hT*P>Nce?4v4_9td-BW#`(7&CJbe51u zLeb4_#4L;%n&ajdve@<3G3DEMEr?3O=T|!dANVEVYS95sT*2L7v7g}8{&K_XuX~0s zEL`B{GsFl&OkF+;H=-0}C1Jpe*gn6O1b$#b*Gt0Csiw2SS4e{Sq6i8ePyw$(5h`<< zrk&$u0D%N#3CabiAw@<2@S{gyYKh-Lb;}-Uu~SLtQW_&k>h*eJPZ3G7CPBk6at>K8 zFpEOE6;U@UMCt69!NRGR1ThUr#OI7|n{3jOz&ss>5XO#kKpdr`M6r}fnHx(`1X390 zaSg0fTE~CfIMh0AY{giriRw)izCAQ7w7QaTvB(QPi>twN<>$OS z!)Ps>1UIm6CnV$t`9;AY`au6TZc{1RCNvcT!t$JM17U>q|0ib>b4JRW4ZGHRCD$Ud}Nt=6Nxv!|AJcXuEB+W)!zmOGw)dUxgJ w_P6NcN4?)9CSFXyN4z0ZfUR$aE9ms_`g1MEmeDgXcg diff --git a/AppKit/Themes/Aristo/Resources/textfield-bezel-square-disabled-7.png b/AppKit/Themes/Aristo/Resources/textfield-bezel-square-disabled-7.png index af73498eb90667d53d3efb62737e29dd539b52b4..78e4e0197bf29cf6d4e3958e610e11e20d36cb3b 100644 GIT binary patch delta 72 zcmaFLUNb?Qi;aVgfq{WZ;EUlzMRgMfIZqeIkcwMLKloXEcpMIt{Qj29#-`BEc!*Vy bfsu{jurcT4f=7zUKrIZOu6{1-oD!M<)n*is literal 997 zcmbVLJ#W)M7&f9psG?%(Kv_<%#6;{nyZ$=Wv`!q;NOfDKL1g4&UmB~m&z!Hs?TA>| z`5pWL23YwAz;8feW#pX31*D1rOZI*EeV*t2e0y~8bZvEGRZ*0+!Cp9&>n-`N+`S{e zhhLsyxjYd4u{dT^F(;fVLCPi+403Wphm@ojFF(_5MY%oAMq@FK_i@5>Z{MK7{+Cf&a%BrPLD4SM#<%A;-%`&6R=%lNsv=P zK%Jiz6|Q}C!Hea-xz<&%FcGJ|dgatOJ_0?)DX=uyNuUjZjWlF#Igaxf7!W}n8agsM z$ib$8Aq2}um1;bl;$avqwdBcHXF`-%*XQ%OHa9iKPjuvYUc+G+9cj_2E($^FPEl>P z3?Z!&o|PhF1!x$_gq;gtm7ZROke6|MOj{}yTtr8oGHXR;{dEM&=fP75&zeO3O^(k#Ugxey^|3pxh0 zU4%RYy)caIC$wqiaV-5cI8n-*sB-pr`~X658r! zQg?~9{)xpsPKjWA#MoKe0Y@_?ST$oM=p9=iCP`K_=cYVY(T0>~uV@-^mV-rpadv|~ zbpMV!Fs&#+f$1UC-Et$SF0twV&HY%GdAB;0^i*;rs53*S`S3mMka$ diff --git a/AppKit/Themes/Aristo/Resources/textfield-bezel-square-disabled-8.png b/AppKit/Themes/Aristo/Resources/textfield-bezel-square-disabled-8.png index 9928549571bc20b104ed4617f802687d9cb3e334..7cacd441ee0e40381bf29c1141a2ce9a1c0fd45a 100644 GIT binary patch delta 127 zcmeC;n9Hcx8Q|y6%O%Cdz`(%k>ERLtq}f2214KSJ^WI~kqIxKUy{C&~NX4zBAN(x! z|Ns51e|>H3b_X?P9^=LietA0shJ!L}DhG<5pPT#Lp~_I;x{|j+Q%M4|503?dA7=vt aGsCj`N|h1iN4tP#GI+ZBxvX*mrj0muiX=$27DqRT_y1799K1SdD$gz7n?!s0aiz z>d=Y*0R8}mijj#G!GM^UP*+q$#W{^jk*W?@vhU&V`+o12t1GvrCTAu~rP5S$(Q2{v z0(&oBxy-&xm1h%dnWl{nT_Zg@bQ4@MebU9C8M^DZgr)!*f-oEo`Ju#H+pBGAHX5o@ zaGOy|-N?g*-GJF0bG381dOg7|B}to*LD2!LeL_jvCo!n6Re|GrL6o2K@*GEN;Usv3 zeLEo`80A+F&ae;Ff8#c#s%;`u(h#c6sW#-sT>pP^CNO7&yg5!aOL4_IFyEfEK0BNY z502QxBy2S9AGG$^Sm{m6Y-gXlKd)XYm&@Yv&7E&w_aBqp-QDTEqod!y4&OhWcy)Ve pNxMcV^}m07{r2$37iIbh8}Lu}W}Y7%zOeJ@Y&KS`H?;>le*n&CL+k(m diff --git a/AppKit/Themes/Aristo/Resources/textfield-bezel-square-focused-0.png b/AppKit/Themes/Aristo/Resources/textfield-bezel-square-focused-0.png index de125412849c1164aac3e16acee8f4d538704abb..45338f2076132daa6270b378eaa3564eaf7cb5ce 100644 GIT binary patch delta 187 zcmcb?af4B@Gr-TCmrII^fq{Y7)59eQNV9=32Z(%d=Do*6MfG}yDo+>3kcwMLZ*Kf- zdU$#I`7=B`JTeYv*pK{iICGXsl!a4+VI!YFHp500?hsXv3zO&e>dv0p8rs#_+1bdt zDztxYuWf(#T-P}dZ)dl~-?uk5a8xykh>SQQxqpA+kI$c_nF|7$4o}kD6GQuo9kA5R|*~-puaK&fuh@vy)q`*}9~WhsK$wPC9>@dA6&k zQi3`J9ivMTbP9s4qeMYMiA0C2Lr_F@?-10bus7;jfplnK=DqLD@Av!uyzjf(*L!4p z-R?SuVYcUbv;tkXMDNzk^gCY|ctw|Hk{u-d-Uulf0cKRo8^$2#7^Ap=4QuNB0&ZuR z*oa*mB!l_mvgtVqBf=!gj!)SP)80|`4Rah5FpNiSS7E=*J!XMzDeOQh5A%LE95{2J?NO+Y2yA zC1BiyX$aCNfrO+eifw?02y&3;5FbaPEbuafVC`Y4x4;^a3!1*>i&_dhMu;zST&Yw_ zl!SyAjB-elq)3D3;}j7Or(9x`<8HXGs-WS}3~Zm+o(m#HW7wM{3QHqhO~LW=`E_A8 zTq_hU8CN!Z4kaMxI8k0J=#Uif?=Ut*hs7x$a|IlFlYvR^V`N{IOl$XVM-h-lBcBLt zdMU<)=9!ZYc1ccCSo$Yn*_I4Z1|lRTp~%B@1|bPSNz?SSuBy6_*7&N%hTLQ-nd%a< zSwWN#()0{W^Id73SJiAPo6U$-Zq5yf;hMPW*N*(Iaa0>c62?f*=jhjFJMa#JO`}QSGG6w|99T1kkVD83N(?fWJZVV8rS-t znsGE3E^3ZHnx%R~J22X=w>~x2hX=cKVgfoE3V3mhj@6Z%rWVU@hkqtS`sANYg(*yUi*0I=#AQn(sZV_ zlB{29Yz3!cxgX2lxessd3X9^)TMu?w`}Zt0UO#z?8bjv}Jp20T^Lyvf^KT0^m8F}_ k@8p7(&d`k24;4?wJ2am43k^bF$p8QV diff --git a/AppKit/Themes/Aristo/Resources/textfield-bezel-square-focused-1.png b/AppKit/Themes/Aristo/Resources/textfield-bezel-square-focused-1.png index fbd78313eeb194fd421eb27fc761b9cf2f3b9651..b5425fd487239a56f7d1c134bf330e87eb142bbb 100644 GIT binary patch delta 83 zcmeyu-o`jVoQsWvje&uIN#Kj&L`8Kw1`SUa$B>F!Nh_kNZ_nv$Y+TsT+23y7^z!`d nXda&SbvA#`e~{;3VB%qzF3g+0RnO4@sF}gj)z4*}Q$iB}hqN3h literal 1012 zcmbVLJ#W)M7&b&|t4c*eOt5frK`g|+vlBbEYEm~B(@1rx(nth}0mr^1R%@SYUy0iZ z(FH~%*8T$KGY!4kc8BluImqh z0uhvGK2*LajxwSMHnqBP7ZSj*Oju}f#S)NQL(nOVLI+BrL7=?zSR5_xW z9mUMct8unkDqxcNX_&B(#-LF22K10wBKLF_LX^1fg>anB6U9>|=UyTs3CdAa#5F}{ ztV{m5aVa|M9VJBWl8hdvKCj1cwIuW0U2UiUa&OEhX~>J>?PKa6MkHn(Y>E7j6oi2Z zQ3E2R*PyOIt$~n%pnnh20sqbtTtqrNm=2?NPd4cEHYt R>zP!{VW+)~KWw~s{TpGiGqeBz diff --git a/AppKit/Themes/Aristo/Resources/textfield-bezel-square-focused-2.png b/AppKit/Themes/Aristo/Resources/textfield-bezel-square-focused-2.png index bb4be64f4de832e9683af2c919deea9e00d0a828..d0ed1884187b4f4392979ec7d0994ece9abd6224 100644 GIT binary patch delta 202 zcmV;*05$*Y2P!U|FQsy93XxU#5aKWG7vuiDPZB_;Z6AW?;peO zKfj;<{Pk-JP;fgC-(vdv?hXU%&({oG?5vXPY;3teL0ur`XEIWiV)*m(8w2Byw+yT- ztP(&$4X}iho*aXzrYytHub&v0AefkdVhoZ%%mol&0Nc(dnpNE0NdN!<07*qoM6N<$ Eg6a8GOaK4? literal 1132 zcmbVLO=#0l9M4v^sW2TVf`S+_bRKN;Ub;4ISY5NGaUFIWUBMkZm?f`m*z#fWX0s{o zn3uqmpm+p`sQ6k&P<6?HSgd|bTE(7Kjj4o9*eYo}02@11ne z&}4sJog7u;8qbx&qnz*DOOPf`nYv(QT|-ChaRKBi1-hFvQc<5DYt;T@yCl zTB1nGSWmH87y_(e_;FRyF3zFfZmf%T^Ak2=bI7&E9hKCh&|W8#-2K~-42>DLHb08XnFb+XnlH{l?igGwAadnM#xt-BSSWLro zn2$p!$uSV+dZIEXis?u?9pmfVjOk*6^mXn39k&>c$RZTOB#@rYm<*U2SNorw zvBVkHZ;n5jrG7;^(BH1LJ~^xn4>HNbIAk>DF9lDLvAUR%#Ju-%9j>FUfD)`=%QDrnmiQ$}|T)wbM(1%8i+?8}rY$%xO$pchmAp z^5k4YWAgsb!qSO%-vUZTmlgPMP?qoSPTu9g%K6=|ZeBn4_TJ}5#j9^_?Pd0SpthZ) zDoERLtq}hO&kpo2jJ$e7bL`8Kg1{F^i$B>F!No%62 zZ#OkIE}YQcZvN)|ZfhR7X;nOKpZ4%DFtRbEPGI{dI9>c1P$Pq-{=IVH?I(U*Wt{=rAtN>kDVE%r3^C}Y;V$msFg|?v5wA&7ZItu}Y!KYBBa$ki zuu;l1=V(b8xkbG= z%ve~~vtqSk@Nf~)Bxec9fM5)VwD{MC_ zSeQk)@|y_1Gi>8btlg$KWQ6t!*{>#GdrTN9#v}*rohAsvD9MB@+B3`6!!&t>W1o@~ zOzUeWr~3alZ&z>nE^>9A$VQ{(LwSyk|EFdu4@MQk@z=0aDn5bYdNTT4I9VQ?@r|Kk zHNL*E_*z}>dTzh`GQ3}Ydv>l?d*WQWA-!(DfBy3O@$vDb_W7c;uqe@=OTR9^aUHRT M-OiTxYU9D<-{`zG=Kufz diff --git a/AppKit/Themes/Aristo/Resources/textfield-bezel-square-focused-4.png b/AppKit/Themes/Aristo/Resources/textfield-bezel-square-focused-4.png index 6b4c7b191e8c65474c33093d80c03ab1a00b6595..b9d310c9103991a26764dacab462ca493ced76e7 100644 GIT binary patch delta 9 Qcmcc5o;$%~@-Ajo02F`&p#T5? literal 991 zcmbVLJ#W)M7v}v5*LuF4p_49!_V`)-xr4mPc}CmZYYYf+20QbVqKH(y>;<@ zJ0E@%%LCpU^C6w`Ic7u&QaT}^pW`DkAUHjH`I&4h%AIL88uM}d)JtftVTsY|ycBFj z+1{;7oE#GlCgdn9eD%l2Pb$b#Uwz(*VO(~}EZaY4WO#lsO3sfHH&u6cz;^8kft+v* z>indryxLb6x}Mm}Yh48k2tW4KrBmbh5OgUcprgT70xbwEq#?6y+x8=1Km>JY=*Vax z+cOOhLa=&NVU49zZxBW+TjJ!aGtNs-*XQ%OHa9iOj&$U@uGBD$mO!+svx4KgRa9Gz zLP)BFWhKvO0i+_H&{OWK!qa64c^Svo!bP=8lt`Ig<5EW&)bm`%wLn*VK>oOKBf1)$ zl|&zqik`AW)ML8UkVWopHza|=8}Av*L{acbNR!i?6uck$s`#U&S?WRLK!ofzv<+xE z2)PKlVHjCa5JaXG8jZ${+_q!5jvMq$+eIjh9B3JPR%8T0uhZ)}cEjx#6~{$F8oQaa zyX3mJa=k7im{T^Q^rY#4!x`nYn$Z$;haC{(BrD`umS-7lNLcoYq!FVzSmf8sZnpnV z+=1DN0u-1ckiE7OL3PDV|0idERLtq}hO&kpo2jJ$e7bL`8K=24znd$B>F!Nq_iR yp3Bvx-6;Gc#JqU|*Wu;*^TQ1d48Ab4NHCnJ=e3zC>fZ*`$KdJe=d#Wzp$Pyd0UZGV literal 1009 zcmbVLJ#W)M7sx(qFAsqYCSdD$gz7n@18$W0{82{THQ2tq7I`p%&|QcYNj@YgXl*rs=LbBIInHdZ&=w$&|;`oFJUSX_N~c=+S>uP@KPu6~~b54iX9bLSSh7u;oXBt5%b O4q@BbuwSk{eDVjLA~mf5 diff --git a/AppKit/Themes/Aristo/Resources/textfield-bezel-square-focused-6.png b/AppKit/Themes/Aristo/Resources/textfield-bezel-square-focused-6.png index 22aa9f17e82163d78e223300c43fe2dfb3dab01e..427e771b22bb2c48a3f0f83bb38d37cc1ce8b253 100644 GIT binary patch delta 200 zcmaFN@sv@qGr-TCmrII^fq{Y7)59eQNV9=32Z(%d=Do*6MfG}yc25__kcwMLYoe-e z&uDB^Z0~P3Z+v*!nJwE^l#M&pkxgvD19OGCkMHl>v+?oewHa@pXV}0XEKtw#NP7SO zKb1eH$96olXI4JE(YySC(DeF$zbwDrK5xIiZUdL`pXZa=rN1(F$TNHlTks@V;Tppx zRSD~|eF;ClJT*3+aG3LmT#dsS{v&r77}*$lI1G>096zrIbR2`HtDnm{r-UW|06$Hg literal 1123 zcmbVLO-$2J94`()5(grj~V;MTcZ8kr)&0+BayReYJhKg7E`A z=}kNs55}wUV2s9-8ZJwS;o!lOdLZHG#c-0uM0^E?nh*~*Y2QbGzu*7+?%=@bj`q%W zj^jFt{aTr=ZPB}Z8~ZlO=RdOL04)sDAyT7t!^fOzktzm7#~8t7Y*>?5-s4`5i`DGP zFdZ(PRZQXtMuZVU$75`c>pdBIhB<~QsNxaZ&GFyf%<{mta{T#J36{J(9<}?Yd^|KY zP%)>*%&f(qJOO$`g$X#A8X$DW-9QO*{Hm_P_R+P-gH;F}%kgVY4VMN%p7k z8iF(uP_jpsDwN)i3=h{qe>=dj%S{(h2VIl(uS}btS5@4 zObiWAL;@5YCyHwo9ndoV?Z&3)pfc%Uv5W&U;hU@;wZly^%iX^XML_0_a?ZC|QH*ho zm=g|mX;I7Z?2lmCmI6@*A|&@fS%T>dLRkc}nx?09Rn?PeO=@av%I(QW*^DX`l5!Ry zP0zrz)R)#JRV}0ng^b+f7Ttgvu8Es=?a1yL7yXl~OoOcE8*wr#qjI>Oe}WiSiCKErSFn) zd+t%}_`_E(UTl|Iw%*vXbPe3t)%cK?&RqZS__)0C{o4XjXJ&6LC*lh&i{{H`7wj+O zZSCb!`@LFg=Y0F#y{*-wPnUL|8sE{F={~h6#&1q{?%Z;4dbuk;KYe87(5D}5U6cE) r&YhK1|MxxMXGi17^zzpDtCrUNobpbXn|pm4Mq^(r3~0~$F5mtIb0%b6 diff --git a/AppKit/Themes/Aristo/Resources/textfield-bezel-square-focused-7.png b/AppKit/Themes/Aristo/Resources/textfield-bezel-square-focused-7.png index 474edf7ecfaec2136f32382b0d22de2d8eda6f98..cdc204445c82cfd58bf69d8818fa19e50f4590e5 100644 GIT binary patch delta 83 zcmaFQ-o`jVoQsWvje&uIN#Kj&L`8Kw1`SUa$B>F!Nk8~me4fkIr6t@d{iMY#ytqM$ n`SNo8`Qb)}1_nM190m-Zs(D=-)ASvHni)J@{an^LB{Ts5{+Jl$ literal 1007 zcmbVLyKmD#95zt#s3>d*SU9-@3$gF)#Ez|+%8hLrsV-3(iHvpZOJXJVne&yn9hqQf zXJbU{3<$PLj7^k1k7C%|yn6b>1<=Jc|%~Xldk&Fz(C^ZzN#u2srFl9ke zOY`+g!NGY*vfO&q+ z_*DD<#%-$&&qlV&1KFxKJt!`@(f{O3=FZ4vbNtmT)fMl+a(mMH{BSZnIOP*V`DnQB zf4$^mb*Jsvz2fuW$Muz+tDXH1Z@zt6hu?)~eL=i-e&wd{QNQx)hW+zPIf89>*Ll6Q G|MWLN>N6hz diff --git a/AppKit/Themes/Aristo/Resources/textfield-bezel-square-focused-8.png b/AppKit/Themes/Aristo/Resources/textfield-bezel-square-focused-8.png index e77d1c1ebee773d5344f779eadbc6546832ff1d6..0bfdb231cdb9d17765c9ab468f2e1c92871772be 100644 GIT binary patch delta 189 zcmaFDaf?y0Gr-TCmrII^fq{Y7)59eQNV9=32Z(%d=Do*6MfG}y8c!F;kcwM6y}P-Z z9RytSr};W?IPE(y{~PlsaC nY4z9sKWdUp+CTrYN-(es3)-;dT|4*@=pqJBS3j3^P6?a)r6MX6!3R1-4<6iPCi{-NwrR7`1-F*%LhD6Lli6-)lSz}Qn-*z( zAXGdk;=!9oPYND9sZ>x9@gTlX^q}m?i%1bgVXaQuZdE8A3?%c&_kI8STwm{j_3c~R zIgVRjIH;D`+7`ZR*Rbz{(!g`JY@zu<+D|I9rhAxEOfrN)!PbXy3G3#>*dv_fxJbn+ z57NQnA=x0dpobVCuwBOHxNK+O>c$ABUEZs# z-m)<{Vq{Fdb3e!iG83>d)j?p7I=&p__yt{=?Za!42MZ87lH(Vh8Z7pK9^zq;5Mb1R zNeGfiK(Tl#mD&p=h@c215lK;$l4Ft#Ay|5NX3aAza!J*eY_U_0uTtvDqFAfdgj!4> z-mr)=nM|l5Nl}J~`V$V-gQ(;0YAUGMH$2Ow7I8qRs1K2Gn&X+Liy_!M_Wf4i|F+AmMISS(?mjC%&FM`c%&%yRc{Lm`lPBOmrGRup|y zCC0do9a>OxJo_VHZewDbO zr#}ITx?wrtIV{g&v?}(jhBm*T(nH>&`qofA>_&lT+U|ZJceZUpuPMCnMOkP%ZJX3b1gF$R?R6F$GT2zn0a@z>toRRa%|ho&dA&_n19@IYrFYy v-<~yvMr(a~Z=W%xte!eUPwqZ>Wfi!`RVT9@*Du#Q!nrTxd(|7=$4>tO-;iyf diff --git a/AppKit/Themes/Aristo/Resources/token-center-disabled.png b/AppKit/Themes/Aristo/Resources/token-center-disabled.png new file mode 100644 index 0000000000000000000000000000000000000000..0fcdbc47a0ee4a35febf07c79c0279c2abdb6829 GIT binary patch literal 153 zcmeAS@N?(olHy`uVBq!ia0vp^j6f{R!3HD)xziF!Nft#;Fs4`1k*R z|J(y=++xWLOdKCyU)N___WAkwdbW=&3`{%>wXBBT74x+nfW|O*y85}Sb4q9e05>u- AD*ylh literal 0 HcmV?d00001 diff --git a/AppKit/Themes/Aristo/Resources/token-left-disabled.png b/AppKit/Themes/Aristo/Resources/token-left-disabled.png new file mode 100644 index 0000000000000000000000000000000000000000..c3ae314d9bbd8e3f2ff6f411a3c2466d499fa6f7 GIT binary patch literal 477 zcmV<30V4j1P)e@}{=HOTe#X`4!hzgDtcRxY9I=D(f6hsHL#N^WV!kxr4Z67?2 zTz>!mdw2Ip7=}tR2m~(8X47yS=T6hK2Bq|jrGOL+c)#DjHcj)TSS(fy!(bqwEDanC z2KUu!_0h5{Q`dFEIah)pP>5_pl%~C2@2Xa-y_U=60{+8o$;6!z)}XYT&*uy1h9TEI zEL=0)ZnpuY&lzI}&;cx5SuU5m$!4<|+(^5nIGlmFK-V-d4pWgQAov%K1b96Nru8cw z_p#gUK0VKi1Zf$E`DU|uU$57SJm7CI*5%Xb^lhXUu^gNkN=F8ky=t{uFO*UV@T>qf zO*4ZBB1sYnf*@NimoC_@o6Y7!*+GF6wii4rl?rV%8Yo z(e1rnub+V4!ut_M7t9!j2o;Wsq7YS8&vaeC0E~?6f51Xfs@1AotJN+sRl%<8>CkU6 zz%I-3IWqqX1|S}%7@cdHccU!4hKvKrLFPD)Ns=U1A+>#AEPlOS 0) + [_tableView selectRowIndexes:[CPIndexSet indexSetWithIndex:0] byExtendingSelection:NO]; + else + [_tableView setEnabled:NO]; + + [_scrollView scrollToBeginningOfDocument:nil]; + } + + return self; +} + +/*! @ignore */ +- (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; +} + +/*! @ignore */ +- (_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; +} + +/*! @ignore */ +- (void)removeTableViewObservers +{ + if (_tableView) + { + var defaultCenter = [CPNotificationCenter defaultCenter]; + + [defaultCenter removeObserver:self name:CPTableViewSelectionIsChangingNotification object:_tableView]; + [defaultCenter removeObserver:self name:CPTableViewSelectionDidChangeNotification object:_tableView]; + } +} + +/*! @ignore */ +- (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; +} + +/*! + 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)]; + [_tableView setEnabled:[_dataSource numberOfItemsInList:self] > 0]; + [self scrollItemAtIndexToTop:[_tableView selectedRow]]; + + [self listWillPopUp]; + + [_panel orderFront:nil]; +} + +#pragma mark Setting Display Attributes + +/*! + 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]; +} + +/*! + Returns whether the list is currently visible. +*/ +- (BOOL)isVisible +{ + return [_panel isVisible]; +} + +/*! + 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 the table view used by the list. +*/ +- (CPTableView)tableView +{ + return _tableView; +} + +/*! + Returns the single table column used by the list. +*/ +- (CPTableColumn)tableColumn +{ + return _tableColumn; +} + +/*! + Returns the scroll view used by the list. +*/ +- (CPScrollView)scrollView +{ + return _scrollView; +} + +/*! + Returns the panel in which the list appears. +*/ +- (CPPanel)panel +{ + return _panel; +} + +#pragma mark Setting a Data Source + +- (void)setDataSource:(_CPPopUpListDataSource)aDataSource +{ + if (_dataSource === aDataSource) + return; + + if (![_CPPopUpListDataSource protocolIsImplementedByObject:aDataSource]) + { + CPLog.warn("Illegal %s data source (%s). Must implement the methods in _CPPopUpListDataSource.", [self className], [aDataSource description]); + } + else + _dataSource = aDataSource; +} + +- (_CPPopUpListDataSource)dataSource +{ + return _dataSource; +} + +#pragma mark Manipulating the Selection + +/*! + 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 < ([_dataSource numberOfItemsInList:self] - 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; +} + +/*! + Returns the selected object value. If no value is selected, + returns nil. +*/ +- (id)selectedObjectValue +{ + var row = [_tableView selectedRow]; + + return (row >= 0) ? [_dataSource list:self objectValueForItemAtIndex:row] : nil; +} + +/*! + Returns the selected value as a single-line string. If no value is selected, + returns nil. +*/ +- (CPString)selectedStringValue +{ + var value = [self selectedObjectValue]; + + return value !== nil ? [_dataSource list:self stringValueForObjectValue:value] : nil; +} + +/*! + Returns the last selected row in the list. If no row has been selected, returns -1. +*/ +- (int)selectedRow +{ + return [_tableView selectedRow]; +} + +/*! + Selects a row and scrolls it to be visible. Returns YES if the selection actually changed. +*/ +- (BOOL)selectRow:(int)row +{ + if (row === [_tableView selectedRow]) + return NO; + + var validRow = (row >= 0 && row < [self numberOfRowsInTableView:_tableView]), + indexes = validRow ? [CPIndexSet indexSetWithIndex:row] : [CPIndexSet indexSet]; + + [_tableView selectRowIndexes:indexes byExtendingSelection:NO]; + + if (validRow) + { + [_tableView scrollRowToVisible:row]; + return YES; + } + else + return NO; +} + +#pragma mark Manipulating the Displayed List + +/*! + 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]; +} + +- (void)scrollItemAtIndexToTop:(int)row +{ + var rect = [_tableView rectOfRow:row]; + + [[_tableView superview] scrollToPoint:rect.origin]; +} + +/*! + 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]; +} + +#pragma mark Handling Events + +/*! + Handles standard key equivalents for moving the selection + and selecting an item. This method should be called by + the -performKeyEquivalent method of the field that is + controlling the list. +*/ +- (BOOL)performKeyEquivalent:(CPEvent)anEvent +{ + var key = [anEvent charactersIgnoringModifiers]; + + switch (key) + { + case CPDownArrowFunctionKey: + if ([self isVisible]) + { + [self selectNextItem]; + return YES; + } + break; + + case CPUpArrowFunctionKey: + if ([self isVisible]) + { + [self selectPreviousItem]; + return YES; + } + break; + + case CPEscapeFunctionKey: + if ([self isVisible]) + { + [self close]; + return YES; + } + break; + + case CPPageUpFunctionKey: + if ([self isVisible]) + { + [self scrollPageUp]; + return YES; + } + break; + + case CPPageDownFunctionKey: + if ([self isVisible]) + { + [self scrollPageDown]; + return YES; + } + break; + + case CPHomeFunctionKey: + if ([self isVisible]) + { + [self scrollToTop]; + return YES; + } + break; + + case CPEndFunctionKey: + if ([self isVisible]) + { + [self scrollToBottom]; + return YES; + } + break; + } + + return NO; +} + +/*! + 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 && ([_dataSource numberOfItemsInList:self] > 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 = ([_dataSource numberOfItemsInList:self] > 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 && ([_dataSource numberOfItemsInList:self] > 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 = ([_dataSource numberOfItemsInList:self] > 0) && flag; +} + +/*! + Returns whether a controlling view should resign. This should be called + from the controlling view's resignFirstResponder method. +*/ +- (BOOL)controllingViewShouldResign +{ + if ([self listWasClicked]) + { + /* + If an item was not clicked (probably the scrollbar), clear the click flag so that future + clicks outside the list will allow it to close. + */ + if ([self listWasClicked] && ![self itemWasClicked]) + [self setListWasClicked:NO]; + + return NO; + } + else + return YES; +} +#pragma mark Internal Helpers + +/*! @ignore */ +- (void)listWillPopUp +{ + [[CPNotificationCenter defaultCenter] postNotificationName:_CPPopUpListWillPopUpNotification object:self]; +} + +/*! + 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. + @ignore +*/ +- (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], [_dataSource numberOfVisibleItemsInList:self]), + + // 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; +} + +- (void)tableViewClickAction:(id)sender +{ + [self close]; +} + +@end + + +var _CPPopUpListDataSourceKey = @"_CPPopUpListDataSourceKey", + _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; + + _dataSource = [aCoder decodeObjectForKey:_CPPopUpListDataSourceKey]; + _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:_dataSource forKey:_CPPopUpListDataSourceKey]; + [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([_dataSource numberOfItemsInList:self], 1); +} + +- (id)tableView:(id)aTableView objectValueForTableColumn:(CPTableColumn)aColumn row:(int)aRow +{ + return [_dataSource list:self displayValueForObjectValue:[_dataSource list:self objectValueForItemAtIndex:aRow]]; +} + +@end + +@implementation _CPPopUpTableView : CPTableView +{ + BOOL _acceptFirstResponder; +} + +- (id)initWithFrame:(CGRect)aFrame +{ + if (self = [super initWithFrame:aFrame]) + { + // We want the autocomplete to remain first responder until we are clicked. + _acceptFirstResponder = NO; + } + + return self; +} + +- (void)trackMouse:(CPEvent)anEvent +{ + if (![self isEnabled]) + return; + + [[self delegate] setItemWasClicked:YES]; + + // CPTableView will not track the click if it is not first responder + _acceptFirstResponder = YES; + [[self window] makeFirstResponder:self]; + [super trackMouse:anEvent]; +} + +- (void)stopTracking:(CGPoint)lastPoint at:(CGPoint)aPoint mouseIsUp:(BOOL)mouseIsUp +{ + _acceptFirstResponder = NO; + [super stopTracking:lastPoint at:aPoint mouseIsUp:mouseIsUp]; +} + +- (BOOL)acceptsFirstResponder +{ + return _acceptFirstResponder; +} + +/*! + 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 diff --git a/AppKit/_CPPopUpListDataSource.j b/AppKit/_CPPopUpListDataSource.j new file mode 100644 index 000000000..cd413779d --- /dev/null +++ b/AppKit/_CPPopUpListDataSource.j @@ -0,0 +1,98 @@ +/* + * _CPPopUpListDataSource.j + * AppKit + * + * Created by Aparajita Fishman. + * Copyright (c) 2012, The Cappuccino Foundation + * + * 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 + */ + + +/*! + This abstract base class defines the methods that delegates of _CPPopUpList must implement. + You may either subclass this class to use the default implementation of + list:objectValueForItemAtIndex: and list:displayValueForObjectValue: or use your + own class and define these methods yourself. +*/ +@implementation _CPPopUpListDataSource : CPObject + +/*! + Returns whether the given object conforms to the minimum protocol defined by this class. +*/ ++ (BOOL)protocolIsImplementedByObject:(id)anObject +{ + return (anObject && + [anObject respondsToSelector:@selector(numberOfItemsInList:)] && + [anObject respondsToSelector:@selector(numberOfVisibleItemsInList:)] && + [anObject respondsToSelector:@selector(list:objectValueForItemAtIndex:)] && + [anObject respondsToSelector:@selector(list:displayValueForObjectValue:)] && + [anObject respondsToSelector:@selector(list:stringValueForObjectValue:)]); +} + +/*! + Returns the number of items managed by the list. +*/ +- (int)numberOfItemsInList:(_CPPopUpList)aList +{ + _CPRaiseInvalidAbstractInvocation(self, _cmd); +} + +/*! + Returns the number of items to display at one time. +*/ +- (int)numberOfVisibleItemsInList:(_CPPopUpList)aList +{ + _CPRaiseInvalidAbstractInvocation(self, _cmd); +} + +/*! + Returns the data for a given row index. +*/ +- (id)list:(_CPPopUpList)aList objectValueForItemAtIndex:(int)index +{ + _CPRaiseInvalidAbstractInvocation(self, _cmd); +} + +/*! + 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 your data source use a data representation other than CPStrings, you must override + this method and return the appropriate data when there are no search results. + + If the _CPPopUpList's 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 Data for the given row + @return A value to be displayed in the list +*/ +- (id)list:(_CPPopUpList)aList displayValueForObjectValue:(id)aValue +{ + return aValue || @""; +} + +/*! + Returns a single-line string representation for an object value. Subclasses should override + this if the object data is not convertible to a simple single-line string. + + @param aValue Table data to be converted to a string + @return A value to be displayed in the autocomplete field +*/ +- (CPString)list:(_CPPopUpList)aList stringValueForObjectValue:(id)aValue +{ + return String(aValue); +} + +@end diff --git a/Tests/Manual/CPComboBoxTest/AppController.j b/Tests/Manual/CPComboBoxTest/AppController.j new file mode 100644 index 000000000..87a40e1ef --- /dev/null +++ b/Tests/Manual/CPComboBoxTest/AppController.j @@ -0,0 +1,228 @@ +/* + * AppController.j + * CPComboBoxTest + * + * 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 + + +@implementation Companies : CPObject +{ + CPMutableArray items @accessors; +} + +- (id)init +{ + self = [super init]; + + if (self) + { + items = [CPMutableArray array]; + + var employees = "Tom,Dick,Harry,Ted,Sam,Fred,Ralph,Ed,Tim,John,Bill,Irving,Stan,Rodney".split(","); + + employees = [CPArray arrayWithObjects:employees count:employees.length]; + [items addObject:[CPDictionary dictionaryWithObjectsAndKeys:@"Spacely Sprockets", @"name", employees, @"employees"]]; + + employees = "Jane,Sally,Joan,Sara,Melissa,Beverly,Gillian,Sandra,Samantha,Mary,Kate".split(","); + employees = [CPArray arrayWithObjects:employees count:employees.length]; + [items addObject:[CPDictionary dictionaryWithObjectsAndKeys:@"Cogswell Cogs", @"name", employees, @"employees"]]; + } + + return self; +} + +@end + +@implementation AppController : CPObject +{ + @outlet CPWindow theWindow; + CPWindow testWindow; + CPString employee @accessors; + Companies companies @accessors; + CPArrayController companiesController; + CPArrayController employeesController; + CPComboBox combo; + @outlet CPComboBox cibCombo; + @outlet CPTextField comboTarget; + CPString fontName; + int nextCheckboxY; +} + +- (id)init +{ + if (self = [super init]) + { + fontName = [CPFont systemFontFace]; + companies = [Companies new]; + } + + return self; +} + +- (void)awakeFromCib +{ +} + +- (void)applicationDidFinishLaunching:(CPNotification)aNotification +{ + testWindow = [[CPWindow alloc] initWithContentRect:CGRectMake(30, 50, 500, 400) styleMask:CPTitledWindowMask | CPResizableWindowMask]; + + var contentView = [testWindow contentView], + companiesScrollView = [[CPScrollView alloc] initWithFrame:CGRectMake(30, 30, 200, 100)], + companiesTable = [[CPTableView alloc] initWithFrame:CGRectMake(0, 0, 100, 100)], + employeesScrollView = [[CPScrollView alloc] initWithFrame:CGRectMake(250, 30, 200, 200)], + employeesTable = [[CPTableView alloc] initWithFrame:CGRectMake(0, 0, 200, 200)]; + + [testWindow setTitle:@"CPComboBox (from code)"]; + + var column = [[CPTableColumn alloc] initWithIdentifier:@"name"]; + [column setResizingMask:CPTableColumnAutoresizingMask]; + [companiesTable addTableColumn:column]; + [companiesTable setAllowsMultipleSelection:YES]; + [companiesTable setColumnAutoresizingStyle:CPTableViewLastColumnOnlyAutoresizingStyle]; + [companiesScrollView setHasHorizontalScroller:NO]; + [companiesScrollView setHasVerticalScroller:YES]; + [companiesScrollView setDocumentView:companiesTable]; + [companiesScrollView setBorderType:CPBezelBorder]; + [companiesTable setHeaderView:nil]; + [companiesTable setAllowsEmptySelection:NO]; + + [contentView addSubview:companiesScrollView]; + + column = [[CPTableColumn alloc] initWithIdentifier:@"name"]; + [column setResizingMask:CPTableColumnAutoresizingMask]; + [employeesTable addTableColumn:column]; + [employeesTable setAllowsMultipleSelection:YES]; + [employeesTable setColumnAutoresizingStyle:CPTableViewLastColumnOnlyAutoresizingStyle]; + [employeesScrollView setHasHorizontalScroller:NO]; + [employeesScrollView setHasVerticalScroller:YES]; + [employeesScrollView setDocumentView:employeesTable]; + [employeesScrollView setBorderType:CPBezelBorder]; + [employeesTable setHeaderView:nil]; + [employeesTable setAllowsEmptySelection:YES]; + + [contentView addSubview:employeesScrollView]; + + combo = [[CPComboBox alloc] initWithFrame:CGRectMake(250, 240, 200, 29)]; + [combo setCompletes:YES]; + [contentView addSubview:combo]; + + var textfield = [CPTextField textFieldWithStringValue:@"" placeholder:@"" width:200]; + [textfield setFrameOrigin:CGPointMake(250, 290)]; + [contentView addSubview:textfield]; + + var center = [CPNotificationCenter defaultCenter]; + [center addObserver:self selector:@selector(comboNote:) name:CPComboBoxSelectionDidChangeNotification object:combo]; + [center addObserver:self selector:@selector(comboNote:) name:CPComboBoxSelectionIsChangingNotification object:combo]; + [center addObserver:self selector:@selector(comboNote:) name:CPComboBoxWillDismissNotification object:combo]; + [center addObserver:self selector:@selector(comboNote:) name:CPComboBoxWillPopUpNotification object:combo]; + [center addObserver:self selector:@selector(comboNote:) name:CPControlTextDidEndEditingNotification object:combo]; + + nextCheckboxY = 166; + [self makeCheckBoxWithTitle:@"Enabled" defaultState:CPOnState]; + [self makeCheckBoxWithTitle:@"Button bordered" defaultState:CPOnState]; + [self makeCheckBoxWithTitle:@"Bold" defaultState:CPOffState]; + [self makeCheckBoxWithTitle:@"Completes" defaultState:CPOnState]; + [self makeCheckBoxWithTitle:@"Force selection" defaultState:CPOffState]; + [self makeCheckBoxWithTitle:@"Vertical scrollbar" defaultState:CPOnState]; + [self makeCheckBoxWithTitle:@"Big item height" defaultState:CPOffState]; + [self makeCheckBoxWithTitle:@"More visible items" defaultState:CPOffState]; + + companiesController = [CPArrayController new]; + [companiesController bind:@"contentArray" toObject:companies withKeyPath:@"items" options:nil]; + + employeesController = [CPArrayController new]; + [employeesController bind:@"contentArray" toObject:companiesController withKeyPath:@"selection.employees" options:nil]; + + var employeeController = [CPObjectController new]; + [employeeController bind:@"content" toObject:employeesController withKeyPath:@"selection.self" options:nil]; + + [[companiesTable tableColumnWithIdentifier:@"name"] bind:@"value" toObject:companiesController withKeyPath:@"arrangedObjects.name" options:nil]; + [[employeesTable tableColumnWithIdentifier:@"name"] bind:@"value" toObject:employeesController withKeyPath:@"arrangedObjects" options:nil]; + [combo bind:@"contentValues" toObject:employeesController withKeyPath:@"arrangedObjects" options:nil]; + [combo bind:@"value" toObject:employeeController withKeyPath:@"content" options:nil]; + + [companiesController addObserver:self forKeyPath:@"selection" options:0 context:@"companies.selection"]; + [companiesController addObserver:self forKeyPath:@"selectionIndexes" options:0 context:@"companies.selectionIndexes"]; + [companiesController addObserver:self forKeyPath:@"arrangedObjects" options:0 context:@"companies.arrangedObjects"]; + [employeesController addObserver:self forKeyPath:@"selectionIndexes" options:0 context:@"employees.selectionIndexes"]; + [employeesController addObserver:self forKeyPath:@"selection" options:0 context:@"employees.selection"]; + [employeesController addObserver:self forKeyPath:@"arrangedObjects" options:0 context:@"employees.arrangedObjects"]; + [combo addObserver:self forKeyPath:@"value" options:0 context:@"combo.value"]; + + [testWindow setInitialFirstResponder:combo]; + [testWindow makeKeyAndOrderFront:self]; +} + +- (void)makeCheckBoxWithTitle:(CPString)aTitle defaultState:(BOOL)aState +{ + var checkbox = [CPCheckBox checkBoxWithTitle:aTitle]; + [checkbox setFrameOrigin:CGPointMake(55, nextCheckboxY)]; + [checkbox setState:aState]; + [checkbox setTarget:self]; + [checkbox setAction:@selector(setComboState:)]; + [[testWindow contentView] addSubview:checkbox]; + + nextCheckboxY += 25; +} + +- (void)observeValueForKeyPath:(CPString)keyPath ofObject:(id)object change:(CPDictionary)change context:(id)context +{ + console.log("\nkeyPath: %s\ncontext: %s\nnew: %s\nold: %s", keyPath, context, [[change valueForKey:CPKeyValueChangeNewKey] description], [[change valueForKey:CPKeyValueChangeOldKey] description]); +} + +- (void)setComboState:(id)sender +{ + var title = [sender title], + state = [sender state] === CPOnState; + + if (title === @"Enabled") + [combo setEnabled:state]; + else if (title === @"Button bordered") + [combo setButtonBordered:state]; + else if (title === @"Bold") + { + var font = [sender state] === CPOnState ? [CPFont boldFontWithName:fontName size:12] : [CPFont fontWithName:fontName size:12]; + [combo setFont:font]; + } + else if (title === @"Completes") + [combo setCompletes:state]; + else if (title === @"Force selection") + [combo setForceSelection:state]; + else if (title === @"Vertical scroller") + [combo setHasVerticalScroller:state]; + else if (title === @"Big item height") + [combo setItemHeight:state ? 47 : 23]; + else if (title === @"More visible items") + [combo setNumberOfVisibleItems:state ? 10 : 5]; +} + +- (void)comboNote:(CPNotification)aNote +{ + console.log([aNote name]); + + var object = [aNote object]; + + if ([aNote name] === CPComboBoxWillDismissNotification) + console.log("Selected: %d - %s", [object indexOfSelectedItem], [object objectValueOfSelectedItem]); +} + +@end diff --git a/Tests/Manual/CPComboBoxTest/Info.plist b/Tests/Manual/CPComboBoxTest/Info.plist new file mode 100644 index 000000000..eee5519b4 --- /dev/null +++ b/Tests/Manual/CPComboBoxTest/Info.plist @@ -0,0 +1,10 @@ + + + + + Main cib file base name + MainMenu.cib + CPBundleName + CPComboBoxTest + + diff --git a/Tests/Manual/CPComboBoxTest/Jakefile b/Tests/Manual/CPComboBoxTest/Jakefile new file mode 100644 index 000000000..a83c45d07 --- /dev/null +++ b/Tests/Manual/CPComboBoxTest/Jakefile @@ -0,0 +1,94 @@ +/* + * Jakefile + * test + * + * Created by aparajita on August 19, 2011. + * Copyright 2011, Victory-Heart Productions All rights reserved. + */ + +var ENV = require("system").env, + FILE = require("file"), + JAKE = require("jake"), + task = JAKE.task, + FileList = JAKE.FileList, + app = require("cappuccino/jake").app, + configuration = ENV["CONFIG"] || ENV["CONFIGURATION"] || ENV["c"] || "Debug", + OS = require("os"); + +app ("test", function(task) +{ + task.setBuildIntermediatesPath(FILE.join("Build", "test.build", configuration)); + task.setBuildPath(FILE.join("Build", configuration)); + + task.setProductName("test"); + task.setIdentifier("com.aparajita.test"); + task.setVersion("1.0"); + task.setAuthor("Victory-Heart Productions"); + task.setEmail("feedback @nospam@ yourcompany.com"); + task.setSummary("test"); + task.setSources((new FileList("**/*.j")).exclude(FILE.join("Build", "**"))); + task.setResources(new FileList("Resources/**")); + task.setIndexFilePath("index.html"); + task.setInfoPlistPath("Info.plist"); + task.setNib2CibFlags("-R Resources/"); + + if (configuration === "Debug") + task.setCompilerFlags("-DDEBUG -g"); + else + task.setCompilerFlags("-O"); +}); + +task ("default", ["test"], function() +{ + printResults(configuration); +}); + +task ("build", ["default"]); + +task ("debug", function() +{ + ENV["CONFIGURATION"] = "Debug"; + JAKE.subjake(["."], "build", ENV); +}); + +task ("release", function() +{ + ENV["CONFIGURATION"] = "Release"; + JAKE.subjake(["."], "build", ENV); +}); + +task ("run", ["debug"], function() +{ + OS.system(["open", FILE.join("Build", "Debug", "test", "index.html")]); +}); + +task ("run-release", ["release"], function() +{ + OS.system(["open", FILE.join("Build", "Release", "test", "index.html")]); +}); + +task ("deploy", ["release"], function() +{ + FILE.mkdirs(FILE.join("Build", "Deployment", "test")); + OS.system(["press", "-f", FILE.join("Build", "Release", "test"), FILE.join("Build", "Deployment", "test")]); + printResults("Deployment") +}); + +task ("desktop", ["release"], function() +{ + FILE.mkdirs(FILE.join("Build", "Desktop", "test")); + require("cappuccino/nativehost").buildNativeHost(FILE.join("Build", "Release", "test"), FILE.join("Build", "Desktop", "test", "test.app")); + printResults("Desktop") +}); + +task ("run-desktop", ["desktop"], function() +{ + OS.system([FILE.join("Build", "Desktop", "test", "test.app", "Contents", "MacOS", "NativeHost"), "-i"]); +}); + +function printResults(configuration) +{ + print("----------------------------"); + print(configuration+" app built at path: "+FILE.join("Build", configuration, "test")); + print("----------------------------"); +} diff --git a/Tests/Manual/CPComboBoxTest/Resources/MainMenu.cib b/Tests/Manual/CPComboBoxTest/Resources/MainMenu.cib new file mode 100644 index 000000000..0f50b6fc6 --- /dev/null +++ b/Tests/Manual/CPComboBoxTest/Resources/MainMenu.cib @@ -0,0 +1 @@ +280NPLIST;1.0;D;K;4;$topD;K;18;CPCibObjectDataKeyD;K;6;CP$UIDd;1;2E;E;K;8;$objectsA;S;5;$nullD;K;10;$classnameS;16;_CPCibObjectDataK;8;$classesA;S;16;_CPCibObjectDataS;8;CPObjectE;E;D;K;6;$classD;K;6;CP$UIDd;1;1E;K;28;_CPCibObjectDataNamesKeysKeyD;K;6;CP$UIDd;1;0E;K;30;_CPCibObjectDataNamesValuesKeyD;K;6;CP$UIDd;1;0E;K;30;_CPCibObjectDataClassesKeysKeyD;K;6;CP$UIDd;1;0E;K;32;_CPCibObjectDataClassesValuesKeyD;K;6;CP$UIDd;1;0E;K;30;_CPCibObjectDataConnectionsKeyD;K;6;CP$UIDd;1;4E;K;28;_CPCibObjectDataFrameworkKeyD;K;6;CP$UIDd;1;0E;K;26;_CPCibObjectDataNextOidKeyD;K;6;CP$UIDd;1;5E;K;30;_CPCibObjectDataObjectsKeysKeyD;K;6;CP$UIDd;1;6E;K;32;_CPCibObjectDataObjectsValuesKeyD;K;6;CP$UIDd;1;7E;K;26;_CPCibObjectDataOidKeysKeyD;K;6;CP$UIDd;1;8E;K;28;_CPCibObjectDataOidValuesKeyD;K;6;CP$UIDd;1;9E;K;28;_CPCibObjectDataFileOwnerKeyD;K;6;CP$UIDd;2;11E;K;33;_CPCibObjectDataVisibleWindowsKeyD;K;6;CP$UIDd;2;13E;E;D;K;10;$classnameS;7;CPArrayK;8;$classesA;S;7;CPArrayS;8;CPObjectE;E;D;K;6;$classD;K;6;CP$UIDd;1;3E;K;10;CP.objectsA;D;K;6;CP$UIDd;2;15E;D;K;6;CP$UIDd;2;16E;D;K;6;CP$UIDd;2;17E;D;K;6;CP$UIDd;2;18E;D;K;6;CP$UIDd;2;20E;D;K;6;CP$UIDd;2;22E;D;K;6;CP$UIDd;2;23E;D;K;6;CP$UIDd;2;24E;D;K;6;CP$UIDd;2;25E;D;K;6;CP$UIDd;2;26E;D;K;6;CP$UIDd;2;27E;D;K;6;CP$UIDd;2;28E;E;E;D;K;6;$classD;K;6;CP$UIDd;1;3E;K;10;CP.objectsA;E;E;D;K;6;$classD;K;6;CP$UIDd;1;3E;K;10;CP.objectsA;D;K;6;CP$UIDd;2;29E;D;K;6;CP$UIDd;2;30E;D;K;6;CP$UIDd;2;32E;D;K;6;CP$UIDd;2;34E;D;K;6;CP$UIDd;2;36E;D;K;6;CP$UIDd;2;38E;D;K;6;CP$UIDd;1;0E;D;K;6;CP$UIDd;2;40E;D;K;6;CP$UIDd;1;0E;D;K;6;CP$UIDd;2;41E;D;K;6;CP$UIDd;1;0E;D;K;6;CP$UIDd;2;42E;D;K;6;CP$UIDd;1;0E;D;K;6;CP$UIDd;2;43E;D;K;6;CP$UIDd;1;0E;D;K;6;CP$UIDd;2;44E;D;K;6;CP$UIDd;1;0E;D;K;6;CP$UIDd;2;46E;D;K;6;CP$UIDd;1;0E;E;E;D;K;6;$classD;K;6;CP$UIDd;1;3E;K;10;CP.objectsA;D;K;6;CP$UIDd;2;11E;D;K;6;CP$UIDd;2;11E;D;K;6;CP$UIDd;2;11E;D;K;6;CP$UIDd;2;11E;D;K;6;CP$UIDd;2;34E;D;K;6;CP$UIDd;2;36E;D;K;6;CP$UIDd;2;38E;D;K;6;CP$UIDd;2;36E;D;K;6;CP$UIDd;2;40E;D;K;6;CP$UIDd;2;36E;D;K;6;CP$UIDd;2;41E;D;K;6;CP$UIDd;2;36E;D;K;6;CP$UIDd;2;42E;D;K;6;CP$UIDd;2;36E;D;K;6;CP$UIDd;2;43E;D;K;6;CP$UIDd;2;36E;D;K;6;CP$UIDd;2;44E;D;K;6;CP$UIDd;2;36E;D;K;6;CP$UIDd;2;46E;E;E;D;K;6;$classD;K;6;CP$UIDd;1;3E;K;10;CP.objectsA;E;E;D;K;6;$classD;K;6;CP$UIDd;1;3E;K;10;CP.objectsA;E;E;D;K;10;$classnameS;18;_CPCibCustomObjectK;8;$classesA;S;18;_CPCibCustomObjectS;8;CPObjectE;E;D;K;6;$classD;K;6;CP$UIDd;2;10E;K;27;_CPCibCustomObjectClassNameD;K;6;CP$UIDd;2;47E;E;D;K;10;$classnameS;5;CPSetK;8;$classesA;S;5;CPSetS;8;CPObjectE;E;D;K;6;$classD;K;6;CP$UIDd;2;12E;K;15;CPSetObjectsKeyD;K;6;CP$UIDd;2;48E;E;D;K;10;$classnameS;20;CPCibOutletConnectorK;8;$classesA;S;20;CPCibOutletConnectorS;14;CPCibConnectorS;8;CPObjectE;E;D;K;6;$classD;K;6;CP$UIDd;2;14E;K;24;_CPCibConnectorSourceKeyD;K;6;CP$UIDd;2;11E;K;29;_CPCibConnectorDestinationKeyD;K;6;CP$UIDd;2;30E;K;23;_CPCibConnectorLabelKeyD;K;6;CP$UIDd;2;49E;E;D;K;6;$classD;K;6;CP$UIDd;2;14E;K;24;_CPCibConnectorSourceKeyD;K;6;CP$UIDd;2;30E;K;29;_CPCibConnectorDestinationKeyD;K;6;CP$UIDd;2;38E;K;23;_CPCibConnectorLabelKeyD;K;6;CP$UIDd;2;50E;E;D;K;6;$classD;K;6;CP$UIDd;2;14E;K;24;_CPCibConnectorSourceKeyD;K;6;CP$UIDd;2;30E;K;29;_CPCibConnectorDestinationKeyD;K;6;CP$UIDd;2;46E;K;23;_CPCibConnectorLabelKeyD;K;6;CP$UIDd;2;51E;E;D;K;6;$classD;K;6;CP$UIDd;2;14E;K;24;_CPCibConnectorSourceKeyD;K;6;CP$UIDd;2;30E;K;29;_CPCibConnectorDestinationKeyD;K;6;CP$UIDd;2;34E;K;23;_CPCibConnectorLabelKeyD;K;6;CP$UIDd;2;52E;E;D;K;10;$classnameS;21;CPCibControlConnectorK;8;$classesA;S;21;CPCibControlConnectorS;14;CPCibConnectorS;8;CPObjectE;E;D;K;6;$classD;K;6;CP$UIDd;2;19E;K;24;_CPCibConnectorSourceKeyD;K;6;CP$UIDd;2;38E;K;29;_CPCibConnectorDestinationKeyD;K;6;CP$UIDd;2;46E;K;23;_CPCibConnectorLabelKeyD;K;6;CP$UIDd;2;53E;E;D;K;10;$classnameS;21;CPCibBindingConnectorK;8;$classesA;S;21;CPCibBindingConnectorS;14;CPCibConnectorS;8;CPObjectE;E;D;K;6;$classD;K;6;CP$UIDd;2;21E;K;24;_CPCibConnectorSourceKeyD;K;6;CP$UIDd;2;44E;K;29;_CPCibConnectorDestinationKeyD;K;6;CP$UIDd;2;30E;K;23;_CPCibConnectorLabelKeyD;K;6;CP$UIDd;2;54E;K;31;CPCibBindingConnectorBindingKeyD;K;6;CP$UIDd;2;55E;K;31;CPCibBindingConnectorKeyPathKeyD;K;6;CP$UIDd;2;56E;K;31;CPCibBindingConnectorOptionsKeyD;K;6;CP$UIDd;2;58E;E;D;K;6;$classD;K;6;CP$UIDd;2;21E;K;24;_CPCibConnectorSourceKeyD;K;6;CP$UIDd;2;43E;K;29;_CPCibConnectorDestinationKeyD;K;6;CP$UIDd;2;30E;K;23;_CPCibConnectorLabelKeyD;K;6;CP$UIDd;2;59E;K;31;CPCibBindingConnectorBindingKeyD;K;6;CP$UIDd;2;55E;K;31;CPCibBindingConnectorKeyPathKeyD;K;6;CP$UIDd;2;60E;K;31;CPCibBindingConnectorOptionsKeyD;K;6;CP$UIDd;2;61E;E;D;K;6;$classD;K;6;CP$UIDd;2;21E;K;24;_CPCibConnectorSourceKeyD;K;6;CP$UIDd;2;42E;K;29;_CPCibConnectorDestinationKeyD;K;6;CP$UIDd;2;30E;K;23;_CPCibConnectorLabelKeyD;K;6;CP$UIDd;2;62E;K;31;CPCibBindingConnectorBindingKeyD;K;6;CP$UIDd;2;55E;K;31;CPCibBindingConnectorKeyPathKeyD;K;6;CP$UIDd;2;63E;K;31;CPCibBindingConnectorOptionsKeyD;K;6;CP$UIDd;2;64E;E;D;K;6;$classD;K;6;CP$UIDd;2;21E;K;24;_CPCibConnectorSourceKeyD;K;6;CP$UIDd;2;41E;K;29;_CPCibConnectorDestinationKeyD;K;6;CP$UIDd;2;30E;K;23;_CPCibConnectorLabelKeyD;K;6;CP$UIDd;2;65E;K;31;CPCibBindingConnectorBindingKeyD;K;6;CP$UIDd;2;55E;K;31;CPCibBindingConnectorKeyPathKeyD;K;6;CP$UIDd;2;66E;K;31;CPCibBindingConnectorOptionsKeyD;K;6;CP$UIDd;2;67E;E;D;K;6;$classD;K;6;CP$UIDd;2;21E;K;24;_CPCibConnectorSourceKeyD;K;6;CP$UIDd;2;32E;K;29;_CPCibConnectorDestinationKeyD;K;6;CP$UIDd;2;30E;K;23;_CPCibConnectorLabelKeyD;K;6;CP$UIDd;2;68E;K;31;CPCibBindingConnectorBindingKeyD;K;6;CP$UIDd;2;69E;K;31;CPCibBindingConnectorKeyPathKeyD;K;6;CP$UIDd;2;70E;K;31;CPCibBindingConnectorOptionsKeyD;K;6;CP$UIDd;2;71E;E;D;K;6;$classD;K;6;CP$UIDd;2;21E;K;24;_CPCibConnectorSourceKeyD;K;6;CP$UIDd;2;40E;K;29;_CPCibConnectorDestinationKeyD;K;6;CP$UIDd;2;30E;K;23;_CPCibConnectorLabelKeyD;K;6;CP$UIDd;2;72E;K;31;CPCibBindingConnectorBindingKeyD;K;6;CP$UIDd;2;55E;K;31;CPCibBindingConnectorKeyPathKeyD;K;6;CP$UIDd;2;73E;K;31;CPCibBindingConnectorOptionsKeyD;K;6;CP$UIDd;2;74E;E;D;K;6;$classD;K;6;CP$UIDd;2;21E;K;24;_CPCibConnectorSourceKeyD;K;6;CP$UIDd;2;38E;K;29;_CPCibConnectorDestinationKeyD;K;6;CP$UIDd;2;32E;K;23;_CPCibConnectorLabelKeyD;K;6;CP$UIDd;2;75E;K;31;CPCibBindingConnectorBindingKeyD;K;6;CP$UIDd;2;76E;K;31;CPCibBindingConnectorKeyPathKeyD;K;6;CP$UIDd;2;77E;K;31;CPCibBindingConnectorOptionsKeyD;K;6;CP$UIDd;2;78E;E;D;K;6;$classD;K;6;CP$UIDd;2;10E;K;27;_CPCibCustomObjectClassNameD;K;6;CP$UIDd;2;47E;E;D;K;6;$classD;K;6;CP$UIDd;2;10E;K;27;_CPCibCustomObjectClassNameD;K;6;CP$UIDd;2;79E;E;D;K;10;$classnameS;18;CPObjectControllerK;8;$classesA;S;18;CPObjectControllerS;12;CPControllerS;8;CPObjectE;E;D;K;6;$classD;K;6;CP$UIDd;2;31E;K;28;CPObjectControllerContentKeyD;K;6;CP$UIDd;1;0E;K;36;CPObjectControllerObjectClassNameKeyD;K;6;CP$UIDd;2;80E;K;31;CPObjectControllerIsEditableKeyD;K;6;CP$UIDd;2;81E;K;49;CPObjectControllerAutomaticallyPreparesContentKeyD;K;6;CP$UIDd;2;82E;E;D;K;10;$classnameS;20;_CPCibWindowTemplateK;8;$classesA;S;20;_CPCibWindowTemplateS;8;CPObjectE;E;D;K;6;$classD;K;6;CP$UIDd;2;33E;K;30;_CPCibWindowTemplateMaxSizeKeyD;K;6;CP$UIDd;2;83E;K;32;_CPCibWindowTemplateViewClassKeyD;K;6;CP$UIDd;1;0E;K;34;_CPCibWindowTemplateWindowClassKeyD;K;6;CP$UIDd;2;84E;K;33;_CPCibWindowTemplateWindowRectKeyD;K;6;CP$UIDd;2;85E;K;30;_CPCibWindowTempatStyleMaskKeyD;K;6;CP$UIDd;2;86E;K;34;_CPCibWindowTemplateWindowTitleKeyD;K;6;CP$UIDd;2;87E;K;33;_CPCibWindowTemplateWindowViewKeyD;K;6;CP$UIDd;2;36E;E;D;K;10;$classnameS;6;CPViewK;8;$classesA;S;6;CPViewS;11;CPResponderS;8;CPObjectE;E;D;K;6;$classD;K;6;CP$UIDd;2;35E;K;18;CPResponderMenuKeyD;K;6;CP$UIDd;1;0E;K;12;CPViewTagKeyD;K;6;CP$UIDd;2;88E;K;14;CPViewFrameKeyD;K;6;CP$UIDd;2;89E;K;15;CPViewBoundsKeyD;K;6;CP$UIDd;2;89E;K;17;CPViewSubviewsKeyD;K;6;CP$UIDd;2;90E;K;19;CPViewThemeClassKeyD;K;6;CP$UIDd;1;0E;K;19;CPViewThemeStateKeyD;K;6;CP$UIDd;2;91E;E;D;K;10;$classnameS;10;CPComboBoxK;8;$classesA;S;10;CPComboBoxS;11;CPTextFieldS;9;CPControlS;6;CPViewS;11;CPResponderS;8;CPObjectE;E;D;K;6;$classD;K;6;CP$UIDd;2;37E;K;27;CPResponderNextResponderKeyD;K;6;CP$UIDd;2;36E;K;18;CPResponderMenuKeyD;K;6;CP$UIDd;1;0E;K;12;CPViewTagKeyD;K;6;CP$UIDd;2;88E;K;14;CPViewFrameKeyD;K;6;CP$UIDd;2;92E;K;15;CPViewBoundsKeyD;K;6;CP$UIDd;2;93E;K;18;CPViewSuperviewKeyD;K;6;CP$UIDd;2;36E;K;22;CPViewAutoresizingMaskD;K;6;CP$UIDd;2;94E;K;19;CPViewThemeClassKeyD;K;6;CP$UIDd;2;95E;K;19;CPViewThemeStateKeyD;K;6;CP$UIDd;2;96E;K;6;$afontD;K;6;CP$UIDd;2;98E;K;17;$aline-break-modeD;K;6;CP$UIDd;2;99E;K;11;$aalignmentD;K;6;CP$UIDd;3;100E;K;35;CPControlSendsActionOnEndEditingKeyD;K;6;CP$UIDd;2;81E;K;17;CPControlValueKeyD;K;6;CP$UIDd;3;101E;K;24;CPControlSendActionOnKeyD;K;6;CP$UIDd;3;102E;K;24;CPTextFieldIsEditableKeyD;K;6;CP$UIDd;2;81E;K;26;CPTextFieldIsSelectableKeyD;K;6;CP$UIDd;2;81E;K;29;CPTextFieldDrawsBackgroundKeyD;K;6;CP$UIDd;2;81E;K;29;CPTextFieldBackgroundColorKeyD;K;6;CP$UIDd;3;104E;K;27;CPTextFieldLineBreakModeKeyD;K;6;CP$UIDd;2;99E;K;23;CPTextFieldAlignmentKeyD;K;6;CP$UIDd;3;100E;K;31;CPTextFieldPlaceholderStringKeyD;K;6;CP$UIDd;1;0E;K;18;CPComboBoxItemsKeyD;K;6;CP$UIDd;3;105E;K;17;CPComboBoxListKeyD;K;6;CP$UIDd;1;0E;K;21;CPComboBoxDelegateKeyD;K;6;CP$UIDd;1;0E;K;23;CPComboBoxDataSourceKeyD;K;6;CP$UIDd;1;0E;K;27;CPComboBoxUsesDataSourceKeyD;K;6;CP$UIDd;2;82E;K;22;CPComboBoxCompletesKeyD;K;6;CP$UIDd;2;81E;K;33;CPComboBoxNumberOfVisibleItemsKeyD;K;6;CP$UIDd;3;106E;K;32;CPComboBoxHasVerticalScrollerKeyD;K;6;CP$UIDd;2;81E;K;27;CPComboBoxButtonBorderedKeyD;K;6;CP$UIDd;2;81E;E;D;K;10;$classnameS;10;CPCheckBoxK;8;$classesA;S;10;CPCheckBoxS;8;CPButtonS;9;CPControlS;6;CPViewS;11;CPResponderS;8;CPObjectE;E;D;K;6;$classD;K;6;CP$UIDd;2;39E;K;27;CPResponderNextResponderKeyD;K;6;CP$UIDd;2;36E;K;18;CPResponderMenuKeyD;K;6;CP$UIDd;1;0E;K;12;CPViewTagKeyD;K;6;CP$UIDd;2;88E;K;14;CPViewFrameKeyD;K;6;CP$UIDd;3;107E;K;15;CPViewBoundsKeyD;K;6;CP$UIDd;3;108E;K;18;CPViewSuperviewKeyD;K;6;CP$UIDd;2;36E;K;22;CPViewAutoresizingMaskD;K;6;CP$UIDd;2;94E;K;19;CPViewThemeClassKeyD;K;6;CP$UIDd;3;109E;K;19;CPViewThemeStateKeyD;K;6;CP$UIDd;3;110E;K;16;$aimage-positionD;K;6;CP$UIDd;2;99E;K;6;$afontD;K;6;CP$UIDd;2;98E;K;17;$aline-break-modeD;K;6;CP$UIDd;2;88E;K;11;$aalignmentD;K;6;CP$UIDd;2;88E;K;17;CPControlValueKeyD;K;6;CP$UIDd;3;111E;K;24;CPControlSendActionOnKeyD;K;6;CP$UIDd;3;100E;K;16;CPButtonTitleKeyD;K;6;CP$UIDd;3;112E;K;25;CPButtonAlternateTitleKeyD;K;6;CP$UIDd;1;0E;K;27;CPButtonAllowsMixedStateKeyD;K;6;CP$UIDd;2;82E;K;23;CPButtonHighlightsByKeyD;K;6;CP$UIDd;3;111E;K;23;CPButtonShowsStateByKeyD;K;6;CP$UIDd;3;111E;K;32;CPButtonImageDimsWhenDisabledKeyD;K;6;CP$UIDd;2;81E;K;24;CPButtonImagePositionKeyD;K;6;CP$UIDd;2;99E;K;28;CPButtonKeyEquivalentMaskKeyD;K;6;CP$UIDd;2;88E;K;24;CPButtonPeriodicDelayKeyD;K;6;CP$UIDd;1;0E;K;27;CPButtonPeriodicIntervalKeyD;K;6;CP$UIDd;1;0E;E;D;K;6;$classD;K;6;CP$UIDd;2;39E;K;27;CPResponderNextResponderKeyD;K;6;CP$UIDd;2;36E;K;18;CPResponderMenuKeyD;K;6;CP$UIDd;1;0E;K;12;CPViewTagKeyD;K;6;CP$UIDd;2;88E;K;14;CPViewFrameKeyD;K;6;CP$UIDd;3;113E;K;15;CPViewBoundsKeyD;K;6;CP$UIDd;3;114E;K;18;CPViewSuperviewKeyD;K;6;CP$UIDd;2;36E;K;22;CPViewAutoresizingMaskD;K;6;CP$UIDd;2;94E;K;19;CPViewThemeClassKeyD;K;6;CP$UIDd;3;109E;K;19;CPViewThemeStateKeyD;K;6;CP$UIDd;3;110E;K;16;$aimage-positionD;K;6;CP$UIDd;2;99E;K;6;$afontD;K;6;CP$UIDd;2;98E;K;17;$aline-break-modeD;K;6;CP$UIDd;2;88E;K;11;$aalignmentD;K;6;CP$UIDd;2;88E;K;17;CPControlValueKeyD;K;6;CP$UIDd;3;111E;K;24;CPControlSendActionOnKeyD;K;6;CP$UIDd;3;100E;K;16;CPButtonTitleKeyD;K;6;CP$UIDd;3;115E;K;25;CPButtonAlternateTitleKeyD;K;6;CP$UIDd;1;0E;K;27;CPButtonAllowsMixedStateKeyD;K;6;CP$UIDd;2;82E;K;23;CPButtonHighlightsByKeyD;K;6;CP$UIDd;3;111E;K;23;CPButtonShowsStateByKeyD;K;6;CP$UIDd;3;111E;K;32;CPButtonImageDimsWhenDisabledKeyD;K;6;CP$UIDd;2;81E;K;24;CPButtonImagePositionKeyD;K;6;CP$UIDd;2;99E;K;28;CPButtonKeyEquivalentMaskKeyD;K;6;CP$UIDd;2;88E;K;24;CPButtonPeriodicDelayKeyD;K;6;CP$UIDd;1;0E;K;27;CPButtonPeriodicIntervalKeyD;K;6;CP$UIDd;1;0E;E;D;K;6;$classD;K;6;CP$UIDd;2;39E;K;27;CPResponderNextResponderKeyD;K;6;CP$UIDd;2;36E;K;18;CPResponderMenuKeyD;K;6;CP$UIDd;1;0E;K;12;CPViewTagKeyD;K;6;CP$UIDd;2;88E;K;14;CPViewFrameKeyD;K;6;CP$UIDd;3;116E;K;15;CPViewBoundsKeyD;K;6;CP$UIDd;3;117E;K;18;CPViewSuperviewKeyD;K;6;CP$UIDd;2;36E;K;22;CPViewAutoresizingMaskD;K;6;CP$UIDd;2;94E;K;19;CPViewThemeClassKeyD;K;6;CP$UIDd;3;109E;K;19;CPViewThemeStateKeyD;K;6;CP$UIDd;2;91E;K;16;$aimage-positionD;K;6;CP$UIDd;2;99E;K;6;$afontD;K;6;CP$UIDd;2;98E;K;17;$aline-break-modeD;K;6;CP$UIDd;2;88E;K;11;$aalignmentD;K;6;CP$UIDd;2;88E;K;17;CPControlValueKeyD;K;6;CP$UIDd;2;88E;K;24;CPControlSendActionOnKeyD;K;6;CP$UIDd;3;100E;K;16;CPButtonTitleKeyD;K;6;CP$UIDd;3;118E;K;25;CPButtonAlternateTitleKeyD;K;6;CP$UIDd;1;0E;K;27;CPButtonAllowsMixedStateKeyD;K;6;CP$UIDd;2;82E;K;23;CPButtonHighlightsByKeyD;K;6;CP$UIDd;3;111E;K;23;CPButtonShowsStateByKeyD;K;6;CP$UIDd;3;111E;K;32;CPButtonImageDimsWhenDisabledKeyD;K;6;CP$UIDd;2;81E;K;24;CPButtonImagePositionKeyD;K;6;CP$UIDd;2;99E;K;28;CPButtonKeyEquivalentMaskKeyD;K;6;CP$UIDd;2;88E;K;24;CPButtonPeriodicDelayKeyD;K;6;CP$UIDd;1;0E;K;27;CPButtonPeriodicIntervalKeyD;K;6;CP$UIDd;1;0E;E;D;K;6;$classD;K;6;CP$UIDd;2;39E;K;27;CPResponderNextResponderKeyD;K;6;CP$UIDd;2;36E;K;18;CPResponderMenuKeyD;K;6;CP$UIDd;1;0E;K;12;CPViewTagKeyD;K;6;CP$UIDd;2;88E;K;14;CPViewFrameKeyD;K;6;CP$UIDd;3;119E;K;15;CPViewBoundsKeyD;K;6;CP$UIDd;3;120E;K;18;CPViewSuperviewKeyD;K;6;CP$UIDd;2;36E;K;22;CPViewAutoresizingMaskD;K;6;CP$UIDd;2;94E;K;19;CPViewThemeClassKeyD;K;6;CP$UIDd;3;109E;K;19;CPViewThemeStateKeyD;K;6;CP$UIDd;3;110E;K;16;$aimage-positionD;K;6;CP$UIDd;2;99E;K;6;$afontD;K;6;CP$UIDd;2;98E;K;17;$aline-break-modeD;K;6;CP$UIDd;2;88E;K;11;$aalignmentD;K;6;CP$UIDd;2;88E;K;17;CPControlValueKeyD;K;6;CP$UIDd;3;111E;K;24;CPControlSendActionOnKeyD;K;6;CP$UIDd;3;100E;K;16;CPButtonTitleKeyD;K;6;CP$UIDd;3;121E;K;25;CPButtonAlternateTitleKeyD;K;6;CP$UIDd;1;0E;K;27;CPButtonAllowsMixedStateKeyD;K;6;CP$UIDd;2;82E;K;23;CPButtonHighlightsByKeyD;K;6;CP$UIDd;3;111E;K;23;CPButtonShowsStateByKeyD;K;6;CP$UIDd;3;111E;K;32;CPButtonImageDimsWhenDisabledKeyD;K;6;CP$UIDd;2;81E;K;24;CPButtonImagePositionKeyD;K;6;CP$UIDd;2;99E;K;28;CPButtonKeyEquivalentMaskKeyD;K;6;CP$UIDd;2;88E;K;24;CPButtonPeriodicDelayKeyD;K;6;CP$UIDd;1;0E;K;27;CPButtonPeriodicIntervalKeyD;K;6;CP$UIDd;1;0E;E;D;K;6;$classD;K;6;CP$UIDd;2;39E;K;27;CPResponderNextResponderKeyD;K;6;CP$UIDd;2;36E;K;18;CPResponderMenuKeyD;K;6;CP$UIDd;1;0E;K;12;CPViewTagKeyD;K;6;CP$UIDd;2;88E;K;14;CPViewFrameKeyD;K;6;CP$UIDd;3;122E;K;15;CPViewBoundsKeyD;K;6;CP$UIDd;3;123E;K;18;CPViewSuperviewKeyD;K;6;CP$UIDd;2;36E;K;22;CPViewAutoresizingMaskD;K;6;CP$UIDd;2;94E;K;19;CPViewThemeClassKeyD;K;6;CP$UIDd;3;109E;K;19;CPViewThemeStateKeyD;K;6;CP$UIDd;3;110E;K;16;$aimage-positionD;K;6;CP$UIDd;2;99E;K;6;$afontD;K;6;CP$UIDd;2;98E;K;17;$aline-break-modeD;K;6;CP$UIDd;2;88E;K;11;$aalignmentD;K;6;CP$UIDd;2;88E;K;17;CPControlValueKeyD;K;6;CP$UIDd;3;111E;K;24;CPControlSendActionOnKeyD;K;6;CP$UIDd;3;100E;K;16;CPButtonTitleKeyD;K;6;CP$UIDd;3;124E;K;25;CPButtonAlternateTitleKeyD;K;6;CP$UIDd;1;0E;K;27;CPButtonAllowsMixedStateKeyD;K;6;CP$UIDd;2;82E;K;23;CPButtonHighlightsByKeyD;K;6;CP$UIDd;3;111E;K;23;CPButtonShowsStateByKeyD;K;6;CP$UIDd;3;111E;K;32;CPButtonImageDimsWhenDisabledKeyD;K;6;CP$UIDd;2;81E;K;24;CPButtonImagePositionKeyD;K;6;CP$UIDd;2;99E;K;28;CPButtonKeyEquivalentMaskKeyD;K;6;CP$UIDd;2;88E;K;24;CPButtonPeriodicDelayKeyD;K;6;CP$UIDd;1;0E;K;27;CPButtonPeriodicIntervalKeyD;K;6;CP$UIDd;1;0E;E;D;K;10;$classnameS;11;CPTextFieldK;8;$classesA;S;11;CPTextFieldS;9;CPControlS;6;CPViewS;11;CPResponderS;8;CPObjectE;E;D;K;6;$classD;K;6;CP$UIDd;2;45E;K;27;CPResponderNextResponderKeyD;K;6;CP$UIDd;2;36E;K;18;CPResponderMenuKeyD;K;6;CP$UIDd;1;0E;K;12;CPViewTagKeyD;K;6;CP$UIDd;2;88E;K;14;CPViewFrameKeyD;K;6;CP$UIDd;3;125E;K;15;CPViewBoundsKeyD;K;6;CP$UIDd;3;126E;K;18;CPViewSuperviewKeyD;K;6;CP$UIDd;2;36E;K;22;CPViewAutoresizingMaskD;K;6;CP$UIDd;2;94E;K;19;CPViewThemeClassKeyD;K;6;CP$UIDd;3;127E;K;19;CPViewThemeStateKeyD;K;6;CP$UIDd;3;128E;K;6;$afontD;K;6;CP$UIDd;2;98E;K;17;$aline-break-modeD;K;6;CP$UIDd;2;99E;K;11;$aalignmentD;K;6;CP$UIDd;3;100E;K;35;CPControlSendsActionOnEndEditingKeyD;K;6;CP$UIDd;2;81E;K;17;CPControlValueKeyD;K;6;CP$UIDd;3;101E;K;24;CPControlSendActionOnKeyD;K;6;CP$UIDd;3;102E;K;24;CPTextFieldIsEditableKeyD;K;6;CP$UIDd;2;81E;K;26;CPTextFieldIsSelectableKeyD;K;6;CP$UIDd;2;81E;K;29;CPTextFieldDrawsBackgroundKeyD;K;6;CP$UIDd;2;81E;K;29;CPTextFieldBackgroundColorKeyD;K;6;CP$UIDd;3;104E;K;27;CPTextFieldLineBreakModeKeyD;K;6;CP$UIDd;2;99E;K;23;CPTextFieldAlignmentKeyD;K;6;CP$UIDd;3;100E;K;31;CPTextFieldPlaceholderStringKeyD;K;6;CP$UIDd;3;101E;E;S;13;CPApplicationD;K;6;$classD;K;6;CP$UIDd;1;3E;K;10;CP.objectsA;D;K;6;CP$UIDd;2;34E;E;E;S;8;delegateS;8;cibComboS;11;comboTargetS;9;theWindowS;20;takeStringValueFrom:S;30;value: cibCombo.buttonBorderedS;5;valueS;23;cibCombo.buttonBorderedD;K;10;$classnameS;12;CPDictionaryK;8;$classesA;S;12;CPDictionaryS;8;CPObjectE;E;D;K;6;$classD;K;6;CP$UIDd;2;57E;K;10;CP.objectsD;E;E;S;35;value: cibCombo.hasVerticalScrollerS;28;cibCombo.hasVerticalScrollerD;K;6;$classD;K;6;CP$UIDd;2;57E;K;10;CP.objectsD;E;E;S;30;value: cibCombo.forceSelectionS;23;cibCombo.forceSelectionD;K;6;$classD;K;6;CP$UIDd;2;57E;K;10;CP.objectsD;E;E;S;25;value: cibCombo.completesS;18;cibCombo.completesD;K;6;$classD;K;6;CP$UIDd;2;57E;K;10;CP.objectsD;E;E;S;20;contentObject: comboS;13;contentObjectS;5;comboD;K;6;$classD;K;6;CP$UIDd;2;57E;K;10;CP.objectsD;E;E;S;23;value: cibCombo.enabledS;16;cibCombo.enabledD;K;6;$classD;K;6;CP$UIDd;2;57E;K;10;CP.objectsD;E;E;S;18;enabled: selectionS;7;enabledS;9;selectionD;K;6;$classD;K;6;CP$UIDd;2;57E;K;10;CP.objectsD;E;E;S;13;AppControllerS;10;CPComboBoxT;F;S;32;{10000000000000, 10000000000000}S;8;CPWindowS;23;{{583, 51}, {394, 166}}d;2;15S;21;CPComboBox (from cib)d;1;0S;20;{{0, 0}, {394, 166}}D;K;6;$classD;K;6;CP$UIDd;1;3E;K;10;CP.objectsA;D;K;6;CP$UIDd;2;38E;D;K;6;CP$UIDd;2;40E;D;K;6;CP$UIDd;2;44E;D;K;6;CP$UIDd;2;41E;D;K;6;CP$UIDd;2;42E;D;K;6;CP$UIDd;2;43E;D;K;6;CP$UIDd;2;46E;E;E;S;6;normalS;21;{{14, 25}, {199, 29}}S;19;{{0, 0}, {199, 29}}d;2;36S;8;comboboxS;35;bezeled+placeholder+button-borderedD;K;10;$classnameS;6;CPFontK;8;$classesA;S;6;CPFontS;8;CPObjectE;E;D;K;6;$classD;K;6;CP$UIDd;2;97E;K;13;CPFontNameKeyD;K;6;CP$UIDd;3;129E;K;13;CPFontSizeKeyD;K;6;CP$UIDd;3;130E;K;15;CPFontIsBoldKeyD;K;6;CP$UIDd;2;82E;K;17;CPFontIsItalicKeyD;K;6;CP$UIDd;2;82E;E;d;1;2d;1;4S;0;d;4;3072D;K;10;$classnameS;7;CPColorK;8;$classesA;S;7;CPColorS;8;CPObjectE;E;D;K;6;$classD;K;6;CP$UIDd;3;103E;K;20;CPColorComponentsKeyD;K;6;CP$UIDd;3;131E;E;D;K;6;$classD;K;6;CP$UIDd;1;3E;K;10;CP.objectsA;D;K;6;CP$UIDd;3;132E;D;K;6;CP$UIDd;3;133E;D;K;6;CP$UIDd;3;134E;D;K;6;CP$UIDd;3;135E;D;K;6;CP$UIDd;3;136E;D;K;6;CP$UIDd;3;137E;D;K;6;CP$UIDd;3;138E;D;K;6;CP$UIDd;3;139E;D;K;6;CP$UIDd;3;140E;E;E;d;1;7S;21;{{247, 30}, {72, 18}}S;18;{{0, 0}, {72, 18}}S;9;check-boxS;8;selectedd;1;1S;7;EnabledS;21;{{247, 80}, {89, 18}}S;18;{{0, 0}, {89, 18}}S;9;CompletesS;23;{{247, 105}, {117, 18}}S;19;{{0, 0}, {117, 18}}S;15;Force selectionS;23;{{247, 130}, {129, 18}}S;19;{{0, 0}, {129, 18}}S;18;Vertical scrollbarS;22;{{247, 55}, {125, 18}}S;19;{{0, 0}, {125, 18}}S;15;Button borderedS;21;{{14, 74}, {196, 29}}S;19;{{0, 0}, {196, 29}}S;9;textfieldS;19;bezeled+placeholderS;17;Arial, sans-serifd;2;12D;K;6;$classD;K;6;CP$UIDd;1;3E;K;10;CP.objectsA;D;K;6;CP$UIDd;3;111E;D;K;6;CP$UIDd;3;111E;D;K;6;CP$UIDd;3;111E;D;K;6;CP$UIDd;3;111E;E;E;S;3;MoeS;5;LarryS;6;CheeseS;5;CurlyS;5;ShempS;7;GrouchoS;5;HarpoS;5;ChicoS;5;ZeppoE;K;9;$archiverS;15;CPKeyedArchiverK;8;$versionS;6;100000E; \ No newline at end of file diff --git a/Tests/Manual/CPComboBoxTest/Resources/MainMenu.xib b/Tests/Manual/CPComboBoxTest/Resources/MainMenu.xib new file mode 100644 index 000000000..265203b64 --- /dev/null +++ b/Tests/Manual/CPComboBoxTest/Resources/MainMenu.xib @@ -0,0 +1,828 @@ + + + + 1050 + 11E53 + 2182 + 1138.47 + 569.00 + + com.apple.InterfaceBuilder.CocoaPlugin + 2182 + + + YES + NSView + NSComboBox + NSWindowTemplate + NSObjectController + NSTextField + NSTextFieldCell + NSButtonCell + NSComboBoxCell + NSButton + NSCustomObject + + + YES + com.apple.InterfaceBuilder.CocoaPlugin + + + PluginDependencyRecalculationVersion + + + + YES + + NSApplication + + + FirstResponder + + + NSApplication + + + AppController + + + NSComboBox + YES + + + + 15 + 2 + {{583, 961}, {394, 166}} + 544735232 + CPComboBox (from cib) + NSWindow + + + + + 256 + + YES + + + 268 + {{20, 115}, {191, 26}} + + + + YES + + 343014976 + 272630784 + + + LucidaGrande + 13 + 1044 + + + YES + + 6 + System + textBackgroundColor + + 3 + MQA + + + + 6 + System + controlTextColor + + 3 + MAA + + + 7 + YES + YES + + YES + Moe + Larry + Cheese + Curly + Shemp + Groucho + Harpo + Chico + Zeppo + + + + + 274 + {13, 189} + + + YES + + YES + + 10 + 10 + 1000 + + 75628032 + 0 + + + LucidaGrande + 12 + 16 + + + 3 + MC4zMzMzMzI5ODU2AA + + + + + 338820672 + 268436480 + + + YES + + 6 + System + controlBackgroundColor + + 3 + MC42NjY2NjY2NjY3AA + + + + + 3 + YES + + + + 3 + 2 + + + 6 + System + gridColor + + 3 + MC41AA + + + 19 + tableViewAction: + -765427712 + + + + 1 + 15 + 0 + YES + 0 + 1 + + + + + + 268 + {{247, 118}, {72, 18}} + + + + YES + + -2080244224 + 0 + Enabled + + + 1211912703 + 2 + + NSImage + NSSwitch + + + NSSwitch + + + + 200 + 25 + + + + + 268 + {{247, 93}, {125, 18}} + + + + YES + + -2080244224 + 0 + Button bordered + + + 1211912703 + 2 + + + + + 200 + 25 + + + + + 268 + {{247, 68}, {89, 18}} + + + + YES + + -2080244224 + 0 + Completes + + + 1211912703 + 2 + + + + + 200 + 25 + + + + + 268 + {{247, 43}, {117, 18}} + + + + YES + + 67239424 + 0 + Force selection + + + 1211912703 + 2 + + + + + 200 + 25 + + + + + 268 + {{247, 18}, {129, 18}} + + + + YES + + -2080244224 + 0 + Vertical scrollbar + + + 1211912703 + 2 + + + + + 200 + 25 + + + + + 268 + {{20, 66}, {188, 22}} + + + + YES + + -1804468671 + 272630784 + + + + + YES + + + 6 + System + textColor + + + + + + {394, 166} + + + + + {{0, 0}, {1920, 1178}} + {10000000000000, 10000000000000} + YES + + + + + YES + + + delegate + + + + 451 + + + + theWindow + + + + 464 + + + + cibCombo + + + + 529 + + + + comboTarget + + + + 577 + + + + enabled: selection + + + + + + enabled: selection + enabled + selection + 2 + + + 522 + + + + value: cibCombo.enabled + + + + + + value: cibCombo.enabled + value + cibCombo.enabled + 2 + + + 531 + + + + contentObject: combo + + + + + + contentObject: combo + contentObject + combo + 2 + + + 521 + + + + value: cibCombo.completes + + + + + + value: cibCombo.completes + value + cibCombo.completes + 2 + + + 535 + + + + value: cibCombo.forceSelection + + + + + + value: cibCombo.forceSelection + value + cibCombo.forceSelection + 2 + + + 548 + + + + value: cibCombo.hasVerticalScroller + + + + + + value: cibCombo.hasVerticalScroller + value + cibCombo.hasVerticalScroller + 2 + + + 546 + + + + value: cibCombo.buttonBordered + + + + + + value: cibCombo.buttonBordered + value + cibCombo.buttonBordered + 2 + + + 552 + + + + takeStringValueFrom: + + + + 578 + + + + + YES + + 0 + + YES + + + + + + -2 + + + File's Owner + + + -1 + + + First Responder + + + -3 + + + Application + + + 450 + + + + + 460 + + + YES + + + + + + 461 + + + YES + + + + + + + + + + + + 462 + + + YES + + + + + + 463 + + + + + 515 + + + YES + + + + + + 516 + + + + + 517 + + + + + 532 + + + YES + + + + + + 533 + + + + + 536 + + + YES + + + + + + 537 + + + + + 539 + + + YES + + + + + + 540 + + + + + 549 + + + YES + + + + + + 550 + + + + + 573 + + + YES + + + + + + 574 + + + + + + + YES + + YES + -1.IBPluginDependency + -2.IBPluginDependency + -3.IBPluginDependency + 450.IBPluginDependency + 460.IBPluginDependency + 460.IBWindowTemplateEditedContentRect + 460.NSWindowTemplate.visibleAtLaunch + 461.IBPluginDependency + 462.IBPluginDependency + 463.IBComboBoxObjectValuesKey.objectValues + 463.IBPluginDependency + 515.IBPluginDependency + 516.IBPluginDependency + 517.IBPluginDependency + 532.IBPluginDependency + 533.IBPluginDependency + 536.IBPluginDependency + 537.IBPluginDependency + 539.IBPluginDependency + 540.IBPluginDependency + 549.IBPluginDependency + 550.IBPluginDependency + 573.IBPluginDependency + 574.IBPluginDependency + + + YES + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + {{357, 418}, {480, 270}} + + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + + YES + Moe + Larry + Cheese + Curly + Shemp + Groucho + Harpo + Chico + Zeppo + + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + + + + YES + + + + + + YES + + + + + 578 + + + + YES + + AppController + NSObject + + YES + + YES + cibCombo + comboTarget + theWindow + + + YES + NSComboBox + NSTextField + NSWindow + + + + YES + + YES + cibCombo + comboTarget + theWindow + + + YES + + cibCombo + NSComboBox + + + comboTarget + NSTextField + + + theWindow + NSWindow + + + + + IBProjectSource + ./Classes/AppController.h + + + + + 0 + IBCocoaFramework + + com.apple.InterfaceBuilder.CocoaPlugin.macosx + + + + com.apple.InterfaceBuilder.CocoaPlugin.InterfaceBuilder3 + + + YES + 3 + + NSSwitch + {15, 15} + + + diff --git a/Tests/Manual/CPComboBoxTest/Resources/spinner.gif b/Tests/Manual/CPComboBoxTest/Resources/spinner.gif new file mode 100644 index 0000000000000000000000000000000000000000..06dbc2bc21dddcf0e09b566d5b211aee89570f52 GIT binary patch literal 1849 zcma*odr(tX9tZHtz31lM+(&Y`A`Ou`NeG&R#DrIfV%?hng21vs6v>ooRQQFbk7E_K!V( z{?5!fpZWgIZ%*d6t%i*j24bL}AZUJm9)h6R*;%L4IWse3G#VWaN1#$zSSXcBhlYlH zJ|D}n{r&w2f+Qp)SS*&n?*G4}{}!h?td_mjU6Kad-rW*QwWYCUk7d^e+sjpZAn6kT z5rM;`{~_}-wm+L@%+E;JphLm}C3WzQAQD0wBoY|rOTQX{(@pp-WAA8Iw0HKl|15j) zhGh(SFWu#5zUCw^T!}C~eC}~?{xG-r7ugQC>taC+|L^xr&a%{#cgUOZXIM&v?)k^2 z1i5%0!U00wq)r4vlAwXBA_m5J5WNeuBm-XJQ5pG4GD%vc|K){+TJ{AkHqN@SJKczX zU}QRd9n*_bf^h94)6Ctv{CUfz_;qs#RDuQ$DR%y1&5G-a6rhf*4Y zl+UOD1*GE{GQ7vv;c-tTIMkz0ovO>9j%b5hpa@a*CBJ#W!0@ndSwF|%hMkdFtXiU) z`BEp+yhkt8ZY>tg&uyH@%^%K4jDrbA;et&vnnzZ3z22@e6<27z2Vk13kb7OtISyxv z(XoO-LNQCZe3lfzc%*pNqU<9T+p~teThOEB+~e&U0mC|zS{Q)dJZ)!^1f7L(zg*L> z*vSW%?dR~@@0(}x6-V^A`~ImD;)NaBUnP8;RH=bS2@pk`wp>>8r&jGjmGPy%1BW}v zoPo}ca$~bze@efc3kapuEVW1!%teOZT3j2Tw5=hjiAf02d}7dL0oFC%@=RXp5Ow#% z@a>+AM|YWt$n&e`>sB-32gBcuTi>R>*|8@lp`y6thc7ydyqDsuUn~YzZf|{-R@-3y zL#wx{Ii}xxL_csiW*LBn0-A$>zp4WOmkf6=ilrjlW?-l9+bCd7|i?*b5NTmy<<6NZ0T8$SN@mwdC2f z6jqK=N@bS@!=YSj%>h0}*4p+%0HbTIrE$w7UMT6+AZZ&DAo*qZAAi(OtNbIfl#Dw^ zJWeiCp~zi#&t6x}m9)O^eR4HiLV3QA<<0>HZ8%$^lrSE94Wb}=+MM^!b>n#5&-JQR zkr-CEu9C;_F*7DqDisulV6Pmg$nFL0TPn%~*m^-`Z3^BgU(sNpnx%nW(!eV9A&FvI zHL3X3lw8Wji^6=8KbQDE-e%b?svdFxxdh$8r97@7$ojeI`6AL8Ob6QC$qh&>ZWVDX1F{0vJnT%%mE;GveKWR%C} zM&4d;Jf3s9|HAA)yVUPo`Aq;0do#)uHSXi5*QF*)x@MVVHr+cN)uMZ__F|&Ta#p8d z53TOKtce!PJUuie8UWol-S(`c2nH?UGqJP{!4RR4u$LCfn)q-hj0^f=h(VYy)T6eN zhRO!ja-aDBTcgeyP(8Ua4IdiOog^*CQa?R(cP#9AgL9`j>EX-6Yf1lzX(!~``M1XC zNmM<4<6d~wWZ$Xrk0K}UteTrq@LBBk#MsjkK;pbuVhe)NI7(7Pf(l?lxC7=1Z7Pzl zMbS;nV4NI5_N{1$P)&XC)huOGQ+h^zpYUZfb*1n6>!`#*b3y52LGmi+<4sY5jyD#- zw&$d}DTguLAfnRtjrM*JfqtHqUu6rQoU=g%1E9xk%;)TDm^2<8n-0IhTsQFaek)MY}>PK4;nBk=ow4pF>vzkO& gna%Org-kgQCf=+BeMi^RbuY;YE~rTjend;_cdi8t>i_@% literal 0 HcmV?d00001 diff --git a/Tests/Manual/CPComboBoxTest/index-debug.html b/Tests/Manual/CPComboBoxTest/index-debug.html new file mode 100644 index 000000000..052bcacac --- /dev/null +++ b/Tests/Manual/CPComboBoxTest/index-debug.html @@ -0,0 +1,103 @@ + + + + + + + + + + + + + + + CPComboBoxTest + + + + + + + + + + + + + + +
+
+ + + +
+
+ + + diff --git a/Tests/Manual/CPComboBoxTest/index.html b/Tests/Manual/CPComboBoxTest/index.html new file mode 100644 index 000000000..bf35f355e --- /dev/null +++ b/Tests/Manual/CPComboBoxTest/index.html @@ -0,0 +1,78 @@ + + + + + + + + + + + + + + + CPComboBoxTest + + + + + + + + + + + + +
+
+ + + +
+
+ + + + diff --git a/Tests/Manual/CPComboBoxTest/main.j b/Tests/Manual/CPComboBoxTest/main.j new file mode 100644 index 000000000..e2cfd7a56 --- /dev/null +++ b/Tests/Manual/CPComboBoxTest/main.j @@ -0,0 +1,18 @@ +/* + * AppController.j + * test + * + * Created by aparajita on August 19, 2011. + * Copyright 2011, Victory-Heart Productions All rights reserved. + */ + +@import +@import + +@import "AppController.j" + + +function main(args, namedArgs) +{ + CPApplicationMain(args, namedArgs); +} diff --git a/Tests/Manual/NewTextFieldBezel/AppController.j b/Tests/Manual/NewTextFieldBezel/AppController.j new file mode 100644 index 000000000..fb92db10c --- /dev/null +++ b/Tests/Manual/NewTextFieldBezel/AppController.j @@ -0,0 +1,121 @@ +/* + * AppController.j + * NewTextField + * + * 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 + + +@implementation AppController : CPObject +{ + CPWindow theWindow; + CPMutableArray fields; +} + +- (void)applicationDidFinishLaunching:(CPNotification)aNotification +{ + theWindow = [[CPWindow alloc] initWithContentRect:CGRectMakeZero() styleMask:CPBorderlessBridgeWindowMask]; + fields = [CPMutableArray array]; + + var field = [CPTextField textFieldWithStringValue:@"" placeholder:@"Text field" width:200]; + [fields addObject:field]; + [self configureField:field at:50]; + + field = [CPTextField roundedTextFieldWithStringValue:@"" placeholder:@"Text field" width:200]; + [fields addObject:field]; + [self configureField:field at:100]; + + field = [CPTextField textFieldWithStringValue:@"" placeholder:@"Big text field" width:200]; + [field setFont:[CPFont systemFontOfSize:16]]; + [fields addObject:field]; + [self configureField:field at:150]; + + field = [[CPSearchField alloc] initWithFrame:CPMakeRect(0, 0, 200, 30)]; + [fields addObject:field]; + [self configureField:field at:200]; + + field = [[CPTokenField alloc] initWithFrame:CPMakeRect(0, 0, 200, 30)]; + [field setEditable:YES]; + [field setPlaceholderString:"Type in a token!"]; + [field setTokenizingCharacterSet:[CPCharacterSet characterSetWithCharactersInString:@" "]]; + [fields addObject:field]; + [self configureField:field at:250]; + + [self makeTableAt:300]; + [theWindow orderFront:self]; +} + +- (void)configureField:(CPTextField)aField at:(int)yCoord +{ + var contentView = [theWindow contentView]; + + [aField setFrameOrigin:CGPointMake(50, yCoord)]; + [aField sizeToFit]; + [contentView addSubview:aField]; + + var enabler = [CPCheckBox checkBoxWithTitle:@"Enabled"]; + + [enabler setFrameOrigin:CGPointMake(50 + 200 + 10, yCoord + 7)]; + [enabler setTarget:self]; + [enabler setAction:@selector(enableField:)]; + [enabler setState:CPOnState]; + [enabler setTag:[fields count] - 1]; + [contentView addSubview:enabler]; +} + +- (void)makeTableAt:(int)yCoord +{ + var scrollView = [[CPScrollView alloc] initWithFrame:CGRectMake(50, yCoord, 200, 200)], + table = [[CPTableView alloc] initWithFrame:CGRectMake(0, 0, 200, 200)], + column = [[CPTableColumn alloc] initWithIdentifier:@"1"]; + + [scrollView setBorderType:CPBezelBorder]; + [table setDataSource:self]; + [table setVerticalMotionCanBeginDrag:NO]; + [column setResizingMask:CPTableColumnAutoresizingMask]; + [column setEditable:YES]; + [table setColumnAutoresizingStyle:CPTableViewLastColumnOnlyAutoresizingStyle]; + [table addTableColumn:column]; + [[theWindow contentView] addSubview:scrollView]; + [scrollView setDocumentView:table]; +} + +- (void)enableField:(id)sender +{ + var field = [fields objectAtIndex:[sender tag]]; + [field setEnabled:[sender state] === CPOnState]; +} + +- (int)numberOfRowsInTableView:(CPTableView)aTableView +{ + return 7; +} + +- (id)tableView:(CPTableView)aTableView objectValueForTableColumn:(CPTableColumn)column row:(int)row +{ + return "Double-click to edit"; +} + +- (void)tableView:(CPTableView)aTableView setObjectValue:(id)anObject forTableColumn:(CPTableColumn)aTableColumn row:(int)rowIndex +{ + +} + +@end diff --git a/Tests/Manual/NewTextFieldBezel/Info.plist b/Tests/Manual/NewTextFieldBezel/Info.plist new file mode 100644 index 000000000..19de2f81c --- /dev/null +++ b/Tests/Manual/NewTextFieldBezel/Info.plist @@ -0,0 +1,12 @@ + + + + + CPApplicationDelegateClass + AppController + CPBundleName + NewTextField + CPPrincipalClass + CPApplication + + diff --git a/Tests/Manual/NewTextFieldBezel/Jakefile b/Tests/Manual/NewTextFieldBezel/Jakefile new file mode 100644 index 000000000..684e5113f --- /dev/null +++ b/Tests/Manual/NewTextFieldBezel/Jakefile @@ -0,0 +1,93 @@ +/* + * Jakefile + * NewTextField + * + * Created by aparajita on August 10, 2011. + * Copyright 2011, Victory-Heart Productions All rights reserved. + */ + +var ENV = require("system").env, + FILE = require("file"), + JAKE = require("jake"), + task = JAKE.task, + FileList = JAKE.FileList, + app = require("cappuccino/jake").app, + configuration = ENV["CONFIG"] || ENV["CONFIGURATION"] || ENV["c"] || "Debug", + OS = require("os"); + +app ("NewTextField", function(task) +{ + task.setBuildIntermediatesPath(FILE.join("Build", "NewTextField.build", configuration)); + task.setBuildPath(FILE.join("Build", configuration)); + + task.setProductName("NewTextField"); + task.setIdentifier("com.aparajita.NewTextField"); + task.setVersion("1.0"); + task.setAuthor("Victory-Heart Productions"); + task.setEmail("feedback @nospam@ yourcompany.com"); + task.setSummary("NewTextField"); + task.setSources((new FileList("**/*.j")).exclude(FILE.join("Build", "**"))); + task.setResources(new FileList("Resources/**")); + task.setIndexFilePath("index.html"); + task.setInfoPlistPath("Info.plist"); + + if (configuration === "Debug") + task.setCompilerFlags("-DDEBUG -g"); + else + task.setCompilerFlags("-O"); +}); + +task ("default", ["NewTextField"], function() +{ + printResults(configuration); +}); + +task ("build", ["default"]); + +task ("debug", function() +{ + ENV["CONFIGURATION"] = "Debug"; + JAKE.subjake(["."], "build", ENV); +}); + +task ("release", function() +{ + ENV["CONFIGURATION"] = "Release"; + JAKE.subjake(["."], "build", ENV); +}); + +task ("run", ["debug"], function() +{ + OS.system(["open", FILE.join("Build", "Debug", "NewTextField", "index.html")]); +}); + +task ("run-release", ["release"], function() +{ + OS.system(["open", FILE.join("Build", "Release", "NewTextField", "index.html")]); +}); + +task ("deploy", ["release"], function() +{ + FILE.mkdirs(FILE.join("Build", "Deployment", "NewTextField")); + OS.system(["press", "-f", FILE.join("Build", "Release", "NewTextField"), FILE.join("Build", "Deployment", "NewTextField")]); + printResults("Deployment") +}); + +task ("desktop", ["release"], function() +{ + FILE.mkdirs(FILE.join("Build", "Desktop", "NewTextField")); + require("cappuccino/nativehost").buildNativeHost(FILE.join("Build", "Release", "NewTextField"), FILE.join("Build", "Desktop", "NewTextField", "NewTextField.app")); + printResults("Desktop") +}); + +task ("run-desktop", ["desktop"], function() +{ + OS.system([FILE.join("Build", "Desktop", "NewTextField", "NewTextField.app", "Contents", "MacOS", "NativeHost"), "-i"]); +}); + +function printResults(configuration) +{ + print("----------------------------"); + print(configuration+" app built at path: "+FILE.join("Build", configuration, "NewTextField")); + print("----------------------------"); +} diff --git a/Tests/Manual/NewTextFieldBezel/Resources/spinner.gif b/Tests/Manual/NewTextFieldBezel/Resources/spinner.gif new file mode 100644 index 0000000000000000000000000000000000000000..06dbc2bc21dddcf0e09b566d5b211aee89570f52 GIT binary patch literal 1849 zcma*odr(tX9tZHtz31lM+(&Y`A`Ou`NeG&R#DrIfV%?hng21vs6v>ooRQQFbk7E_K!V( z{?5!fpZWgIZ%*d6t%i*j24bL}AZUJm9)h6R*;%L4IWse3G#VWaN1#$zSSXcBhlYlH zJ|D}n{r&w2f+Qp)SS*&n?*G4}{}!h?td_mjU6Kad-rW*QwWYCUk7d^e+sjpZAn6kT z5rM;`{~_}-wm+L@%+E;JphLm}C3WzQAQD0wBoY|rOTQX{(@pp-WAA8Iw0HKl|15j) zhGh(SFWu#5zUCw^T!}C~eC}~?{xG-r7ugQC>taC+|L^xr&a%{#cgUOZXIM&v?)k^2 z1i5%0!U00wq)r4vlAwXBA_m5J5WNeuBm-XJQ5pG4GD%vc|K){+TJ{AkHqN@SJKczX zU}QRd9n*_bf^h94)6Ctv{CUfz_;qs#RDuQ$DR%y1&5G-a6rhf*4Y zl+UOD1*GE{GQ7vv;c-tTIMkz0ovO>9j%b5hpa@a*CBJ#W!0@ndSwF|%hMkdFtXiU) z`BEp+yhkt8ZY>tg&uyH@%^%K4jDrbA;et&vnnzZ3z22@e6<27z2Vk13kb7OtISyxv z(XoO-LNQCZe3lfzc%*pNqU<9T+p~teThOEB+~e&U0mC|zS{Q)dJZ)!^1f7L(zg*L> z*vSW%?dR~@@0(}x6-V^A`~ImD;)NaBUnP8;RH=bS2@pk`wp>>8r&jGjmGPy%1BW}v zoPo}ca$~bze@efc3kapuEVW1!%teOZT3j2Tw5=hjiAf02d}7dL0oFC%@=RXp5Ow#% z@a>+AM|YWt$n&e`>sB-32gBcuTi>R>*|8@lp`y6thc7ydyqDsuUn~YzZf|{-R@-3y zL#wx{Ii}xxL_csiW*LBn0-A$>zp4WOmkf6=ilrjlW?-l9+bCd7|i?*b5NTmy<<6NZ0T8$SN@mwdC2f z6jqK=N@bS@!=YSj%>h0}*4p+%0HbTIrE$w7UMT6+AZZ&DAo*qZAAi(OtNbIfl#Dw^ zJWeiCp~zi#&t6x}m9)O^eR4HiLV3QA<<0>HZ8%$^lrSE94Wb}=+MM^!b>n#5&-JQR zkr-CEu9C;_F*7DqDisulV6Pmg$nFL0TPn%~*m^-`Z3^BgU(sNpnx%nW(!eV9A&FvI zHL3X3lw8Wji^6=8KbQDE-e%b?svdFxxdh$8r97@7$ojeI`6AL8Ob6QC$qh&>ZWVDX1F{0vJnT%%mE;GveKWR%C} zM&4d;Jf3s9|HAA)yVUPo`Aq;0do#)uHSXi5*QF*)x@MVVHr+cN)uMZ__F|&Ta#p8d z53TOKtce!PJUuie8UWol-S(`c2nH?UGqJP{!4RR4u$LCfn)q-hj0^f=h(VYy)T6eN zhRO!ja-aDBTcgeyP(8Ua4IdiOog^*CQa?R(cP#9AgL9`j>EX-6Yf1lzX(!~``M1XC zNmM<4<6d~wWZ$Xrk0K}UteTrq@LBBk#MsjkK;pbuVhe)NI7(7Pf(l?lxC7=1Z7Pzl zMbS;nV4NI5_N{1$P)&XC)huOGQ+h^zpYUZfb*1n6>!`#*b3y52LGmi+<4sY5jyD#- zw&$d}DTguLAfnRtjrM*JfqtHqUu6rQoU=g%1E9xk%;)TDm^2<8n-0IhTsQFaek)MY}>PK4;nBk=ow4pF>vzkO& gna%Org-kgQCf=+BeMi^RbuY;YE~rTjend;_cdi8t>i_@% literal 0 HcmV?d00001 diff --git a/Tests/Manual/NewTextFieldBezel/index-debug.html b/Tests/Manual/NewTextFieldBezel/index-debug.html new file mode 100644 index 000000000..4c283399a --- /dev/null +++ b/Tests/Manual/NewTextFieldBezel/index-debug.html @@ -0,0 +1,107 @@ + + + + + + + + + + + + + + + NewTextField + + + + + + + + + + + + + + +
+
+ + + +
+
+ + + diff --git a/Tests/Manual/NewTextFieldBezel/index.html b/Tests/Manual/NewTextFieldBezel/index.html new file mode 100644 index 000000000..d288174a1 --- /dev/null +++ b/Tests/Manual/NewTextFieldBezel/index.html @@ -0,0 +1,78 @@ + + + + + + + + + + + + + + + NewTextField + + + + + + + + + + + + +
+
+ + + +
+
+ + + + diff --git a/Tests/Manual/NewTextFieldBezel/main.j b/Tests/Manual/NewTextFieldBezel/main.j new file mode 100644 index 000000000..c5515727b --- /dev/null +++ b/Tests/Manual/NewTextFieldBezel/main.j @@ -0,0 +1,18 @@ +/* + * AppController.j + * NewTextField + * + * Created by aparajita on August 10, 2011. + * Copyright 2011, Victory-Heart Productions All rights reserved. + */ + +@import +@import + +@import "AppController.j" + + +function main(args, namedArgs) +{ + CPApplicationMain(args, namedArgs); +} diff --git a/Tools/nib2cib/NSAppKit.j b/Tools/nib2cib/NSAppKit.j index f26db332a..227d47fbd 100644 --- a/Tools/nib2cib/NSAppKit.j +++ b/Tools/nib2cib/NSAppKit.j @@ -31,6 +31,7 @@ @import "NSColorWell.j" @import "NSCollectionView.j" @import "NSCollectionViewItem.j" +@import "NSComboBox.j" @import "NSControl.j" @import "NSCustomObject.j" @import "NSCustomResource.j" diff --git a/Tools/nib2cib/NSComboBox.j b/Tools/nib2cib/NSComboBox.j new file mode 100644 index 000000000..16ed5ba49 --- /dev/null +++ b/Tools/nib2cib/NSComboBox.j @@ -0,0 +1,105 @@ +/* + * NSComboBox.j + * nib2cib + * + * Created by Aparajita Fishman. + * Copyright (c) 2012, The Cappuccino Foundation + * + * 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 +@import + +@import "NSTextField.j" + + +@implementation CPComboBox (NSCoding) + +- (id)NS_initWithCoder:(CPCoder)aCoder +{ + self = [super NS_initWithCoder:aCoder]; + + if (self) + { + var cell = [aCoder decodeObjectForKey:@"NSCell"]; + + _items = [cell itemList]; + _usesDataSource = [cell usesDataSource]; + _completes = [cell completes]; + _numberOfVisibleItems = [cell visibleItemCount]; + _hasVerticalScroller = [cell hasVerticalScroller]; + [self setButtonBordered:[cell borderedButton]]; + + // Make sure the height is clipped to the max given by the theme + var maxSize = [[[Converter sharedConverter] themes][0] valueForAttributeWithName:@"max-size" forClass:[CPComboBox class]], + size = [self frameSize]; + + [self setFrameSize:CGSizeMake(size.width, MIN(size.height, maxSize.height))]; + } + + return self; +} + +@end + +@implementation NSComboBox : CPComboBox + +- (id)initWithCoder:(CPCoder)aCoder +{ + return [self NS_initWithCoder:aCoder]; +} + +- (Class)classForKeyedArchiver +{ + return [CPComboBox class]; +} + +@end + +@implementation NSComboBoxCell : NSTextFieldCell +{ + int _visibleItemCount @accessors(readonly, getter=visibleItemCount); + BOOL _hasVerticalScroller @accessors(readonly, getter=hasVerticalScroller); + BOOL _usesDataSource @accessors(readonly, getter=usesDataSource); + BOOL _completes @accessors(readonly, getter=completes); + CPArray _itemList @accessors(readonly, getter=itemList); + BOOL _borderedButton @accessors(readonly, getter=borderedButton); +} + +- (id)initWithCoder:(CPCoder)aCoder +{ + self = [super initWithCoder:aCoder]; + + if (self) + { + _visibleItemCount = [aCoder decodeIntForKey:@"NSVisibleItemCount"]; + _hasVerticalScroller = [aCoder decodeBoolForKey:@"NSHasVerticalScroller"]; + _usesDataSource = [aCoder decodeBoolForKey:@"NSUsesDataSource"]; + _completes = [aCoder decodeBoolForKey:@"NSCompletes"]; + + if (!_usesDataSource) + _itemList = [aCoder decodeObjectForKey:@"NSPopUpListData"] || []; + else + _itemList = []; + + // NSButtonBordered key is present only if the value is NO, go figure + _borderedButton = [aCoder containsValueForKey:@"NSButtonBordered"] ? [aCoder decodeBoolForKey:@"NSButtonBordered"] : YES; + } + + return self; +} + +@end