24 @
typedef CPTabViewType
46 - (void)tabViewDidChangeNumberOfTabViewItems:(
CPTabView)tabView;
62 _CPSegmentedControl _tabs;
71 id <CPTabViewDelegate> _delegate;
72 unsigned _delegateSelectors;
75 - (id)initWithFrame:(CGRect)aFrame
77 if (
self = [super initWithFrame:aFrame])
80 _selectedTabViewItem = nil;
89 _tabs = [[_CPSegmentedControl alloc] initWithFrame:CGRectMakeZero()];
90 [_tabs setTabView:self];
91 [_tabs setSegments:[CPArray array]];
93 var height = [_tabs valueForThemeAttribute:@"min-size"].height;
94 [_tabs setFrameSize:CGSizeMake(0, height)];
96 _box = [[_CPTabViewBox alloc] initWithFrame:[
self bounds]];
97 [_box setTabView:self];
100 [
self addSubview:_box];
101 [
self addSubview:_tabs];
103 _placeholderView = nil;
108 return [_tabs segments];
126 - (void)insertTabViewItem:(
CPTabViewItem)aTabViewItem atIndex:(CPUInteger)anIndex
131 - (void)_insertTabViewItems:(CPArray)tabViewItems atIndexes:(
CPIndexSet)indexes canUpdateSelectedTab:(BOOL)canUpdateSelectedTab
133 var prevItemsCount = [
self numberOfTabViewItems];
135 [_tabs insertSegments:tabViewItems atIndexes:indexes];
136 [tabViewItems makeObjectsPerformSelector:@selector(_setTabView:) withObject:self];
138 [
self tileWithChangedItem:[tabViewItems firstObject]];
139 [
self _reverseSetContent];
141 [
self _sendDelegateTabViewDidChangeNumberOfTabViewItems];
144 if (prevItemsCount == 0 && [
self numberOfTabViewItems] > 0 && ![
self _isSelectionBinded] && canUpdateSelectedTab)
145 [
self _selectTabViewItemAtIndex:0];
154 var idx = [[
self items] indexOfObjectIdenticalTo:aTabViewItem];
160 [aTabViewItem _setTabView:nil];
163 [
self _didRemoveTabViewItem:aTabViewItem atIndex:idx];
164 [
self _reverseSetContent];
166 [
self _sendDelegateTabViewDidChangeNumberOfTabViewItems];
169 - (void)_didRemoveTabViewItem:(
CPTabViewItem)aTabViewItem atIndex:(CPInteger)idx
172 if ([
self _isSelectionBinded])
175 if (_selectedTabViewItem == aTabViewItem)
180 didSelect = [
self selectTabViewItemAtIndex:idx - 1];
181 else if ([
self numberOfTabViewItems] > 0)
182 didSelect = [
self selectTabViewItemAtIndex:0];
185 _selectedTabViewItem == nil;
197 return [[
self items] indexOfObjectIdenticalTo:aTabViewItem];
205 - (int)indexOfTabViewItemWithIdentifier:(
CPString)anIdentifier
207 return [[
self items] indexOfObjectPassingTest:function(item, idx, stop)
209 return [[item identifier] isEqual:anIdentifier];
217 - (unsigned)numberOfTabViewItems
219 return [[
self items] count];
228 return [[
self items] objectAtIndex:anIndex];
235 - (CPArray)tabViewItems
237 return [[
self items] copy];
245 - (void)selectFirstTabViewItem:(
id)aSender
247 if ([
self numberOfTabViewItems] === 0)
257 - (void)selectLastTabViewItem:(
id)aSender
259 if ([
self numberOfTabViewItems] === 0)
269 - (void)selectNextTabViewItem:(
id)aSender
271 if (_selectedTabViewItem === nil)
276 if (nextIndex === [
self numberOfTabViewItems])
287 - (void)selectPreviousTabViewItem:(
id)aSender
289 if (_selectedTabViewItem === nil)
294 if (previousIndex < 0)
313 - (BOOL)selectTabViewItemAtIndex:(CPUInteger)anIndex
315 if (![
self _selectTabViewItemAtIndex:anIndex])
318 [
self _reverseSetSelectedIndex];
324 - (BOOL)_selectTabViewItemAtIndex:(CPUInteger)anIndex
326 var aTabViewItem = [
self tabViewItemAtIndex:anIndex];
328 if (aTabViewItem == _selectedTabViewItem)
331 if (![
self _sendDelegateShouldSelectTabViewItem:aTabViewItem])
334 [
self _sendDelegateWillSelectTabViewItem:aTabViewItem];
336 [_tabs setSelectedSegment:anIndex];
337 _selectedTabViewItem = aTabViewItem;
338 [
self _loadTabViewItem:aTabViewItem];
340 [
self _sendDelegateDidSelectTabViewItem:aTabViewItem];
349 if (controller !== nil && ![controller isViewLoaded])
351 [controller loadViewWithCompletionHandler:function(view, error)
355 CPLog.warn("Could not load the view for item " + aTabViewItem + ". " + error);
357 else if (view !== nil)
361 if ([
self selectedTabViewItem] == aTabViewItem)
362 [
self _displayItemView:view];
368 [
self _displayItemView:[aTabViewItem
view]];
378 return _selectedTabViewItem;
401 [_tabs setFont:_font];
409 - (void)setTabViewType:(CPTabViewType)aTabViewType
411 if (_type === aTabViewType)
414 _type = aTabViewType;
417 [_tabs removeFromSuperview];
426 [_box setBorderType:CPBezelBorder];
429 [_box setBorderType:CPLineBorder];
432 [_box setBorderType:CPNoBorder];
442 [_tabs tileWithChangedSegment:segment];
447 - (void)layoutSubviews
453 [_box setFrame:[
self bounds]];
457 var aFrame = [
self frame],
458 segmentedHeight = CGRectGetHeight([_tabs
frame]),
461 [_box setFrame:CGRectMake(0, origin, CGRectGetWidth(aFrame),
462 CGRectGetHeight(aFrame) - segmentedHeight / 2)];
464 [
self _repositionTabs];
472 - (CPTabViewType)tabViewType
490 - (void)setDelegate:(
id <CPTabViewDelegate>)aDelegate
492 if (_delegate == aDelegate)
495 _delegate = aDelegate;
497 _delegateSelectors = 0;
499 if ([_delegate respondsToSelector:
@selector(tabView:shouldSelectTabViewItem:)])
502 if ([_delegate respondsToSelector:
@selector(tabView:willSelectTabViewItem:)])
505 if ([_delegate respondsToSelector:
@selector(tabView:didSelectTabViewItem:)])
508 if ([_delegate respondsToSelector:
@selector(tabViewDidChangeNumberOfTabViewItems:)])
514 [_box setBackgroundColor:aColor];
519 return [_box backgroundColor];
522 - (void)_repositionTabs
524 var horizontalCenterOfSelf = CGRectGetWidth([
self bounds]) / 2,
525 verticalCenterOfTabs = CGRectGetHeight([_tabs
bounds]) / 2;
528 [_tabs setCenter:CGPointMake(horizontalCenterOfSelf, CGRectGetHeight([
self bounds]) - verticalCenterOfTabs)];
530 [_tabs setCenter:CGPointMake(horizontalCenterOfSelf, verticalCenterOfTabs)];
533 - (void)_displayItemView:(
CPView)aView
535 [_box setContentView:aView];
540 - (BOOL)_sendDelegateShouldSelectTabViewItem:(
CPTabViewItem)aTabViewItem
543 return [_delegate tabView:self shouldSelectTabViewItem:aTabViewItem];
548 - (void)_sendDelegateWillSelectTabViewItem:(
CPTabViewItem)aTabViewItem
551 [_delegate tabView:self willSelectTabViewItem:aTabViewItem];
554 - (void)_sendDelegateDidSelectTabViewItem:(
CPTabViewItem)aTabViewItem
557 [_delegate tabView:self didSelectTabViewItem:aTabViewItem];
560 - (void)_sendDelegateTabViewDidChangeNumberOfTabViewItems
563 [_delegate tabViewDidChangeNumberOfTabViewItems:self];
570 + (Class)_binderClassForBinding:(
CPString)aBinding
572 if (aBinding == CPContentBinding)
573 return [_CPTabViewContentBinder class];
574 else if (aBinding == CPSelectionIndexesBinding || aBinding == CPSelectedIndexBinding)
575 return [_CPTabViewSelectionBinder class];
577 return [
super _binderClassForBinding:aBinding];
582 return (aBinding == CPSelectionIndexesBinding || aBinding == CPSelectedIndexBinding);
585 - (void)_reverseSetContent
587 var theBinder = [
self binderForBinding:CPContentBinding];
588 [theBinder reverseSetValueFor:@"items"];
591 - (void)_reverseSetSelectedIndex
593 var theBinder = [
self binderForBinding:CPSelectionIndexesBinding];
595 if (theBinder !== nil)
596 [theBinder reverseSetValueFor:@"selectionIndexes"];
599 theBinder = [
self binderForBinding:CPSelectedIndexBinding];
600 [theBinder reverseSetValueFor:@"selectedIndex"];
606 var cls = [[
self class] _binderClassForBinding:aBinding];
607 return [cls getBinding:aBinding forObject:self];
610 - (BOOL)_isSelectionBinded
612 return [
self binderForBinding:CPSelectionIndexesBinding] || [
self binderForBinding:CPSelectedIndexBinding];
615 - (void)setItems:(CPArray)tabViewItems
617 if ([tabViewItems isEqualToArray:[_tabs segments]])
620 [[
self items] makeObjectsPerformSelector:@selector(_setTabView:) withObject:nil];
621 [_tabs setSegments:tabViewItems];
622 [
tabViewItems makeObjectsPerformSelector:@selector(_setTabView:) withObject:self];
635 [_tabs setSelectedSegment:-1];
636 _selectedTabViewItem = nil;
639 - (void)_displayPlaceholder:(
CPString)aPlaceholder
641 if (_placeholderView == nil)
643 _placeholderView = [[
CPView alloc] initWithFrame:CGRectMakeZero()];
644 var textField = [[
CPTextField alloc] initWithFrame:CGRectMakeZero()];
645 [textField setTag:1000];
648 [_placeholderView addSubview:textField];
651 var textField = [_placeholderView viewWithTag:1000];
652 [textField setStringValue:aPlaceholder];
653 [textField sizeToFit];
655 var boxBounds = [_box bounds],
656 textFieldBounds = [textField bounds],
657 origin = CGPointMake(CGRectGetWidth(boxBounds)/2 - CGRectGetWidth(textFieldBounds)/2, CGRectGetHeight(boxBounds)/2 - CGRectGetHeight(textFieldBounds));
659 [textField setFrameOrigin:origin];
661 [
self _displayItemView:_placeholderView];
665 #pragma mark Override 677 var _CPTabViewContentBinderNull =
@"NO CONTENT";
678 @implementation _CPTabViewContentBinder :
CPBinder 683 - (void)_updatePlaceholdersWithOptions:(
CPDictionary)options
685 [
super _updatePlaceholdersWithOptions:options];
686 [
self _setPlaceholder:_CPTabViewContentBinderNull forMarker:CPNullMarker isDefault:YES];
689 - (void)setPlaceholderValue:(
id)aValue withMarker:(
CPString)aMarker forBinding:(
CPString)aBinding
691 [_source setItems:@[]];
692 [_source _setPlaceholderView:aValue];
695 - (void)setValue:(
id)aValue forBinding:(
CPString)aBinding
697 [_source setItems:aValue];
700 - (id)valueForBinding:(
CPString)aBinding
702 return [_source items];
707 var _CPTabViewSelectionBinderMultipleValues =
@"Multiple Selection",
708 _CPTabViewSelectionBinderNoSelection =
@"No Selection";
709 @implementation _CPTabViewSelectionBinder :
CPBinder 714 - (void)_updatePlaceholdersWithOptions:(
CPDictionary)options
716 [
super _updatePlaceholdersWithOptions:options];
718 [
self _setPlaceholder:_CPTabViewSelectionBinderMultipleValues forMarker:CPMultipleValuesMarker isDefault:YES];
719 [
self _setPlaceholder:_CPTabViewSelectionBinderNoSelection forMarker:CPNoSelectionMarker isDefault:YES];
722 - (void)setPlaceholderValue:(
id)aValue withMarker:(
CPString)aMarker forBinding:(
CPString)aBinding
724 if (aMarker == CPNoSelectionMarker || aMarker == CPNullMarker)
725 [_source _deselectAll];
727 [_source _displayPlaceholder:aValue];
730 - (void)setValue:(
id)aValue forBinding:(
CPString)aBinding
732 if (aBinding == CPSelectionIndexesBinding)
734 if (aValue == nil || [aValue count] == 0)
736 [_source _deselectAll];
737 [_source _displayPlaceholder:_CPTabViewSelectionBinderNoSelection];
739 else if ([aValue count] > 1)
740 [_source _displayPlaceholder:_CPTabViewSelectionBinderMultipleValues];
741 else if ([aValue firstIndex] < [_source numberOfTabViewItems])
742 [_source _selectTabViewItemAtIndex:[aValue firstIndex]];
744 else if (aBinding == CPSelectedIndexBinding)
748 [_source _deselectAll];
749 [_source _displayPlaceholder:_CPTabViewSelectionBinderNoSelection];
751 else if (aValue < [_source numberOfTabViewItems])
752 [_source _selectTabViewItemAtIndex:aValue];
756 - (id)valueForBinding:(
CPString)aBinding
758 if (aBinding == CPSelectionIndexesBinding)
761 idx = [_source indexOfTabViewItem:[_source selectedTabViewItem]];
764 [result addIndex:idx];
768 else if (aBinding == CPSelectedIndexBinding)
769 return [_source indexOfTabViewItem:[_source selectedTabViewItem]];
784 if (
self = [super initWithCoder:aCoder])
788 _font = [aCoder decodeObjectForKey:CPTabViewFontKey];
789 [_tabs setFont:_font];
791 var items = [aCoder decodeObjectForKey:CPTabViewItemsKey] || [CPArray array];
794 [
self setDelegate:[aCoder decodeObjectForKey:CPTabViewDelegateKey]];
796 _selectedTabViewItem = [aCoder decodeObjectForKey:CPTabViewSelectedItemKey];
798 _type = [aCoder decodeIntForKey:CPTabViewTypeKey];
806 [
super awakeFromCib];
811 if (_selectedTabViewItem)
819 _selectedTabViewItem = nil;
838 [_box removeFromSuperview];
842 [aCoder encodeObject:_items forKey:CPTabViewItemsKey];
844 [aCoder encodeConditionalObject:_selectedTabViewItem forKey:CPTabViewSelectedItemKey];
846 [aCoder encodeInt:_type forKey:CPTabViewTypeKey];
847 [aCoder encodeObject:_font forKey:CPTabViewFontKey];
849 [aCoder encodeConditionalObject:_delegate forKey:CPTabViewDelegateKey];
854 @implementation _CPTabViewBox :
CPBox 861 #pragma mark Override 863 - (
CPView)hitTest:(CGPoint)aPoint
867 var segmentIndex = [_tabView._tabs testSegment:[_tabView._tabs convertPoint:aPoint fromView:[
self superview]]];
872 return [
super hitTest:aPoint];
892 - (void)trackSegment:(
CPEvent)anEvent
894 var type = [anEvent
type],
896 currentSegment = [
self testSegment:location];
905 if ((_trackingSegment !== _selectedSegment) &&
906 [_tabView _sendDelegateShouldSelectTabViewItem:[_tabView tabViewItemAtIndex:_trackingSegment]])
908 [
self setSelected:YES forSegment:_trackingSegment];
909 _selectedSegment = _trackingSegment;
910 [_tabView selectTabViewItemAtIndex:_selectedSegment];
913 [
self drawSegmentBezel:_trackingSegment highlight:NO];
923 _trackingSegment = currentSegment;
924 [
self drawSegmentBezel:_trackingSegment highlight:YES];
931 if (_trackingSegment !== currentSegment)
934 [
self drawSegmentBezel:_trackingSegment highlight:NO];
936 _trackingSegment = currentSegment;
939 [
self drawSegmentBezel:_trackingSegment highlight:YES];
945 [CPApp setTarget:self selector:@selector(trackSegment:) forNextEventMatchingMask:CPLeftMouseDraggedMask | CPLeftMouseUpMask untilDate:nil inMode:nil dequeue:YES];
void setView:(CPView aView)
var CPTabViewWillSelectTabViewItemSelector
void addSubview:(CPView aSubview)
int indexOfTabViewItem:(CPTabViewItem aTabViewItem)
CPViewController viewController()
CPFont boldFontWithName:size:italic:(CPString aName, [size] float aSize, [italic] BOOL italic)
CGPoint locationInWindow()
A collection of unique integers.
A mutable key-value pair collection.
CPTabViewType CPTopTabsBezelBorder
An immutable string (collection of characters).
CPColor colorWithCalibratedWhite:alpha:(float white, [alpha] float alpha)
void encodeWithCoder:(CPCoder aCoder)
var CPTabViewDidChangeNumberOfTabViewItemsSelector
void setSubviews:(CPArray newSubviews)
void setTabViewType:(CPTabViewType aTabViewType)
CPColor backgroundColor()
Defines methods for use when archiving & restoring (enc/decoding).
var CPTabViewSelectedItemKey
BOOL selectTabViewItemAtIndex:(CPUInteger anIndex)
void tileWithChangedItem:(CPTabViewItem aTabViewItem)
var CPTabViewDidSelectTabViewItemSelector
void setDelegate:(id< CPTabViewDelegate > aDelegate)
id indexSetWithIndexesInRange:(CPRange aRange)
id indexSetWithIndex:(int anIndex)
void insertTabViewItem:atIndex:(CPTabViewItem aTabViewItem, [atIndex] CPUInteger anIndex)
var CPTabViewShouldSelectTabViewItemSelector
unsigned numberOfTabViewItems()