API  0.9.10
CPTabView.j
Go to the documentation of this file.
1 /*
2  * CPTabView.j
3  * AppKit
4  *
5  * Created by Derek Hammer.
6  * Copyright 2010, Derek Hammer.
7  *
8  * This library is free software; you can redistribute it and/or
9  * modify it under the terms of the GNU Lesser General Public
10  * License as published by the Free Software Foundation; either
11  * version 2.1 of the License, or (at your option) any later version.
12  *
13  * This library is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16  * Lesser General Public License for more details.
17  *
18  * You should have received a copy of the GNU Lesser General Public
19  * License along with this library; if not, write to the Free Software
20  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
21  */
22 
23 
24 @typedef CPTabViewType
26 //CPLeftTabsBezelBorder = 1;
28 //CPRightTabsBezelBorder = 3;
29 CPNoTabsBezelBorder = 4; //Displays no tabs and has a bezeled border.
30 CPNoTabsLineBorder = 5; //Has no tabs and displays a line border.
31 CPNoTabsNoBorder = 6; //Displays no tabs and no border.
32 
33 
38 
39 
40 @protocol CPTabViewDelegate <CPObject>
41 
42 @optional
43 - (BOOL)tabView:(CPTabView)tabView shouldSelectTabViewItem:(CPTabViewItem)tabViewItem;
44 - (void)tabView:(CPTabView)tabView didSelectTabViewItem:(CPTabViewItem)tabViewItem;
45 - (void)tabView:(CPTabView)tabView willSelectTabViewItem:(CPTabViewItem)tabViewItem;
46 - (void)tabViewDidChangeNumberOfTabViewItems:(CPTabView)tabView;
47 
48 @end
49 
50 
58 @implementation CPTabView : CPView
59 {
60  CPArray _items;
61 
62  CPSegmentedControl _tabs;
63  _CPTabViewBox _box;
64  CPView _placeHolderView;
65 
66  CPTabViewItem _selectedTabViewItem;
67 
68  CPTabViewType _type;
69  CPFont _font;
70 
71  id <CPTabViewDelegate> _delegate;
72  unsigned _delegateSelectors;
73 }
74 
75 - (id)initWithFrame:(CGRect)aFrame
76 {
77  if (self = [super initWithFrame:aFrame])
78  {
79  [self _init];
80  _selectedTabViewItem = nil;
81  [self setTabViewType:CPTopTabsBezelBorder];
82  }
83 
84  return self;
85 }
86 
87 - (void)_init
88 {
89  _tabs = [[CPSegmentedControl alloc] initWithFrame:CGRectMakeZero()];
90  [_tabs setHitTests:NO];
91  [_tabs setSegments:[CPArray array]];
92 
93  var height = [_tabs valueForThemeAttribute:@"min-size"].height;
94  [_tabs setFrameSize:CGSizeMake(0, height)];
95 
96  _box = [[_CPTabViewBox alloc] initWithFrame:[self bounds]];
97  [_box setTabView:self];
99 
100  [self addSubview:_box];
101  [self addSubview:_tabs];
102 
103  _placeHolderView = nil;
104 }
105 
106 - (CPArray)items
107 {
108  return [_tabs segments];
109 }
110 
111 // Adding and Removing Tabs
116 - (void)addTabViewItem:(CPTabViewItem)aTabViewItem
117 {
118  [self insertTabViewItem:aTabViewItem atIndex:[self numberOfTabViewItems]];
119 }
120 
126 - (void)insertTabViewItem:(CPTabViewItem)aTabViewItem atIndex:(CPUInteger)anIndex
127 {
128  [self _insertTabViewItems:[aTabViewItem] atIndexes:[CPIndexSet indexSetWithIndex:anIndex]];
129 }
130 
131 - (void)_insertTabViewItems:(CPArray)tabViewItems atIndexes:(CPIndexSet)indexes
132 {
133  var prevItemsCount = [self numberOfTabViewItems];
134 
135  [_tabs insertSegments:tabViewItems atIndexes:indexes];
136  [tabViewItems makeObjectsPerformSelector:@selector(_setTabView:) withObject:self];
137 
138  [self tileWithChangedItem:[tabViewItems firstObject]];
139  [self _reverseSetContent];
140 
141  [self _sendDelegateTabViewDidChangeNumberOfTabViewItems];
142 
143  // Do not allow empty selection if selection bindings are not enabled.
144  if (prevItemsCount == 0 && [self numberOfTabViewItems] > 0 && ![self _isSelectionBinded])
145  [self _selectTabViewItemAtIndex:0];
146 }
147 
152 - (void)removeTabViewItem:(CPTabViewItem)aTabViewItem
153 {
154  var idx = [[self items] indexOfObjectIdenticalTo:aTabViewItem];
155 
156  if (idx == CPNotFound)
157  return;
158 
159  [_tabs removeSegmentsAtIndexes:[CPIndexSet indexSetWithIndex:idx]];
160  [aTabViewItem _setTabView:nil];
161 
162  [self tileWithChangedItem:nil];
163  [self _didRemoveTabViewItem:aTabViewItem atIndex:idx];
164  [self _reverseSetContent];
165 
166  [self _sendDelegateTabViewDidChangeNumberOfTabViewItems];
167 }
168 
169 - (void)_didRemoveTabViewItem:(CPTabViewItem)aTabViewItem atIndex:(CPInteger)idx
170 {
171  // If the selection is managed by bindings, let the binder do that.
172  if ([self _isSelectionBinded])
173  return;
174 
175  if (_selectedTabViewItem == aTabViewItem)
176  {
177  var didSelect = NO;
178 
179  if (idx > 0)
180  didSelect = [self selectTabViewItemAtIndex:idx - 1];
181  else if ([self numberOfTabViewItems] > 0)
182  didSelect = [self selectTabViewItemAtIndex:0];
183 
184  if (didSelect == NO)
185  _selectedTabViewItem == nil;
186  }
187 }
188 
189 // Accessing Tabs
195 - (int)indexOfTabViewItem:(CPTabViewItem)aTabViewItem
196 {
197  return [[self items] indexOfObjectIdenticalTo:aTabViewItem];
198 }
199 
205 - (int)indexOfTabViewItemWithIdentifier:(CPString)anIdentifier
206 {
207  return [[self items] indexOfObjectPassingTest:function(item, idx, stop)
208  {
209  return [[item identifier] isEqual:anIdentifier];
210  }];
211 }
212 
218 {
219  return [[self items] count];
220 }
221 
226 - (CPTabViewItem)tabViewItemAtIndex:(CPUInteger)anIndex
227 {
228  return [[self items] objectAtIndex:anIndex];
229 }
230 
235 - (CPArray)tabViewItems
236 {
237  return [[self items] copy]; // Copy?
238 }
239 
240 // Selecting a Tab
245 - (void)selectFirstTabViewItem:(id)aSender
246 {
247  if ([self numberOfTabViewItems] === 0)
248  return; // throw?
249 
250  [self selectTabViewItemAtIndex:0];
251 }
252 
257 - (void)selectLastTabViewItem:(id)aSender
258 {
259  if ([self numberOfTabViewItems] === 0)
260  return; // throw?
261 
263 }
264 
269 - (void)selectNextTabViewItem:(id)aSender
270 {
271  if (_selectedTabViewItem === nil)
272  return;
273 
274  var nextIndex = [self indexOfTabViewItem:_selectedTabViewItem] + 1;
275 
276  if (nextIndex === [self numberOfTabViewItems])
277  // does nothing. According to spec at (http://developer.apple.com/mac/library/DOCUMENTATION/Cocoa/Reference/ApplicationKit/Classes/NSTabView_Class/Reference/Reference.html#//apple_ref/occ/instm/NSTabView/selectNextTabViewItem:)
278  return;
279 
280  [self selectTabViewItemAtIndex:nextIndex];
281 }
282 
287 - (void)selectPreviousTabViewItem:(id)aSender
288 {
289  if (_selectedTabViewItem === nil)
290  return;
291 
292  var previousIndex = [self indexOfTabViewItem:_selectedTabViewItem] - 1;
293 
294  if (previousIndex < 0)
295  return; // does nothing. See above.
296 
297  [self selectTabViewItemAtIndex:previousIndex];
298 }
299 
304 - (void)selectTabViewItem:(CPTabViewItem)aTabViewItem
305 {
306  [self selectTabViewItemAtIndex:[self indexOfTabViewItem:aTabViewItem]];
307 }
308 
313 - (BOOL)selectTabViewItemAtIndex:(CPUInteger)anIndex
314 {
315  if (![self _selectTabViewItemAtIndex:anIndex])
316  return NO;
317 
318  [self _reverseSetSelectedIndex];
319 
320  return YES;
321 }
322 
323 // Like selectTabViewItemAtIndex: but without bindings interaction
324 - (BOOL)_selectTabViewItemAtIndex:(CPUInteger)anIndex
325 {
326  var aTabViewItem = [self tabViewItemAtIndex:anIndex];
327 
328  if (aTabViewItem == _selectedTabViewItem)
329  return NO;
330 
331  if (![self _sendDelegateShouldSelectTabViewItem:aTabViewItem])
332  return NO;
333 
334  [self _sendDelegateWillSelectTabViewItem:aTabViewItem];
335 
336  [_tabs setSelectedSegment:anIndex];
337  _selectedTabViewItem = aTabViewItem;
338  [self _loadTabViewItem:aTabViewItem];
339 
340  [self _sendDelegateDidSelectTabViewItem:aTabViewItem];
341 
342  return YES;
343 }
344 
345 - (void)_loadTabViewItem:(CPTabViewItem)aTabViewItem
346 {
347  var controller = [aTabViewItem viewController];
348 
349  if (controller !== nil && ![controller isViewLoaded])
350  {
351  [controller loadViewWithCompletionHandler:function(view, error)
352  {
353  if (error !== nil)
354  {
355  CPLog.warn("Could not load the view for item " + aTabViewItem + ". " + error);
356  }
357  else if (view !== nil)
358  {
359  [aTabViewItem setView:view];
360 
361  if ([self selectedTabViewItem] == aTabViewItem)
362  [self _displayItemView:view];
363  }
364  }];
365  }
366  else
367  {
368  [self _displayItemView:[aTabViewItem view]];
369  }
370 }
371 
377 {
378  return _selectedTabViewItem;
379 }
380 
381 // Modifying the font
387 {
388  return _font;
389 }
390 
395 - (void)setFont:(CPFont)font
396 {
397  if ([_font isEqual:font])
398  return;
399 
400  _font = font;
401  [_tabs setFont:_font];
402 }
403 
404 //
409 - (void)setTabViewType:(CPTabViewType)aTabViewType
410 {
411  if (_type === aTabViewType)
412  return;
413 
414  _type = aTabViewType;
415 
416  if (_type !== CPTopTabsBezelBorder && _type !== CPBottomTabsBezelBorder)
417  [_tabs removeFromSuperview];
418  else
419  [self addSubview:_tabs];
420 
421  switch (_type)
422  {
425  case CPNoTabsBezelBorder:
426  [_box setBorderType:CPBezelBorder];
427  break;
428  case CPNoTabsLineBorder:
429  [_box setBorderType:CPLineBorder];
430  break;
431  case CPNoTabsNoBorder:
432  [_box setBorderType:CPNoBorder];
433  break;
434  }
435 
436  [self setNeedsLayout];
437 }
438 
439 - (void)tileWithChangedItem:(CPTabViewItem)aTabViewItem
440 {
441  var segment = aTabViewItem ? [self indexOfTabViewItem:aTabViewItem] : 0;
442  [_tabs tileWithChangedSegment:segment];
443 
444  [self setNeedsLayout];
445 }
446 
448 {
449  // Even if CPTabView's autoresizesSubviews is NO, _tabs and _box has to be laid out.
450  // This means we can't rely on autoresize masks.
451  if (_type !== CPTopTabsBezelBorder && _type !== CPBottomTabsBezelBorder)
452  {
453  [_box setFrame:[self bounds]];
454  }
455  else
456  {
457  var aFrame = [self frame],
458  segmentedHeight = CGRectGetHeight([_tabs frame]),
459  origin = _type === CPTopTabsBezelBorder ? segmentedHeight / 2 : 0;
460 
461  [_box setFrame:CGRectMake(0, origin, CGRectGetWidth(aFrame),
462  CGRectGetHeight(aFrame) - segmentedHeight / 2)];
463 
464  [self _repositionTabs];
465  }
466 }
467 
472 - (CPTabViewType)tabViewType
473 {
474  return _type;
475 }
476 
481 - (id)delegate
482 {
483  return _delegate;
484 }
485 
490 - (void)setDelegate:(id <CPTabViewDelegate>)aDelegate
491 {
492  if (_delegate == aDelegate)
493  return;
494 
495  _delegate = aDelegate;
496 
497  _delegateSelectors = 0;
498 
499  if ([_delegate respondsToSelector:@selector(tabView:shouldSelectTabViewItem:)])
500  _delegateSelectors |= CPTabViewShouldSelectTabViewItemSelector;
501 
502  if ([_delegate respondsToSelector:@selector(tabView:willSelectTabViewItem:)])
503  _delegateSelectors |= CPTabViewWillSelectTabViewItemSelector;
504 
505  if ([_delegate respondsToSelector:@selector(tabView:didSelectTabViewItem:)])
506  _delegateSelectors |= CPTabViewDidSelectTabViewItemSelector;
507 
508  if ([_delegate respondsToSelector:@selector(tabViewDidChangeNumberOfTabViewItems:)])
510 }
511 
512 - (void)setBackgroundColor:(CPColor)aColor
513 {
514  [_box setBackgroundColor:aColor];
515 }
516 
518 {
519  return [_box backgroundColor];
520 }
521 
522 - (void)mouseDown:(CPEvent)anEvent
523 {
524  var segmentIndex = [_tabs testSegment:[_tabs convertPoint:[anEvent locationInWindow] fromView:nil]];
525 
526  if (segmentIndex != CPNotFound && [self selectTabViewItemAtIndex:segmentIndex])
527  [_tabs trackSegment:anEvent];
528 }
529 
530 - (void)_repositionTabs
531 {
532  var horizontalCenterOfSelf = CGRectGetWidth([self bounds]) / 2,
533  verticalCenterOfTabs = CGRectGetHeight([_tabs bounds]) / 2;
534 
535  if (_type === CPBottomTabsBezelBorder)
536  [_tabs setCenter:CGPointMake(horizontalCenterOfSelf, CGRectGetHeight([self bounds]) - verticalCenterOfTabs)];
537  else
538  [_tabs setCenter:CGPointMake(horizontalCenterOfSelf, verticalCenterOfTabs)];
539 }
540 
541 - (void)_displayItemView:(CPView)aView
542 {
543  [_box setContentView:aView];
544 }
545 
546 // DELEGATE METHODS
547 
548 - (BOOL)_sendDelegateShouldSelectTabViewItem:(CPTabViewItem)aTabViewItem
549 {
550  if (_delegateSelectors & CPTabViewShouldSelectTabViewItemSelector)
551  return [_delegate tabView:self shouldSelectTabViewItem:aTabViewItem];
552 
553  return YES;
554 }
555 
556 - (void)_sendDelegateWillSelectTabViewItem:(CPTabViewItem)aTabViewItem
557 {
558  if (_delegateSelectors & CPTabViewWillSelectTabViewItemSelector)
559  [_delegate tabView:self willSelectTabViewItem:aTabViewItem];
560 }
561 
562 - (void)_sendDelegateDidSelectTabViewItem:(CPTabViewItem)aTabViewItem
563 {
564  if (_delegateSelectors & CPTabViewDidSelectTabViewItemSelector)
565  [_delegate tabView:self didSelectTabViewItem:aTabViewItem];
566 }
567 
568 - (void)_sendDelegateTabViewDidChangeNumberOfTabViewItems
569 {
570  if (_delegateSelectors & CPTabViewDidChangeNumberOfTabViewItemsSelector)
571  [_delegate tabViewDidChangeNumberOfTabViewItems:self];
572 }
573 
574 @end
575 
577 
578 + (Class)_binderClassForBinding:(CPString)aBinding
579 {
580  if (aBinding == CPContentBinding)
581  return [_CPTabViewContentBinder class];
582  else if (aBinding == CPSelectionIndexesBinding || aBinding == CPSelectedIndexBinding)
583  return [_CPTabViewSelectionBinder class];
584 
585  return [super _binderClassForBinding:aBinding];
586 }
587 
588 + (BOOL)isBindingExclusive:(CPString)aBinding
589 {
590  return (aBinding == CPSelectionIndexesBinding || aBinding == CPSelectedIndexBinding);
591 }
592 
593 - (void)_reverseSetContent
594 {
595  var theBinder = [self binderForBinding:CPContentBinding];
596  [theBinder reverseSetValueFor:@"items"];
597 }
598 
599 - (void)_reverseSetSelectedIndex
600 {
601  var theBinder = [self binderForBinding:CPSelectionIndexesBinding];
602 
603  if (theBinder !== nil)
604  [theBinder reverseSetValueFor:@"selectionIndexes"];
605  else
606  {
607  theBinder = [self binderForBinding:CPSelectedIndexBinding];
608  [theBinder reverseSetValueFor:@"selectedIndex"];
609  }
610 }
611 
612 - (CPBinder)binderForBinding:(CPString)aBinding
613 {
614  var cls = [[self class] _binderClassForBinding:aBinding]
615  return [cls getBinding:aBinding forObject:self];
616 }
617 
618 - (BOOL)_isSelectionBinded
619 {
620  return [self binderForBinding:CPSelectionIndexesBinding] || [self binderForBinding:CPSelectedIndexBinding];
621 }
622 
623 - (void)setItems:(CPArray)tabViewItems
624 {
625  if ([tabViewItems isEqualToArray:[_tabs segments]])
626  return;
627 
628  [[self items] makeObjectsPerformSelector:@selector(_setTabView:) withObject:nil];
629  [_tabs setSegments:tabViewItems];
630  [tabViewItems makeObjectsPerformSelector:@selector(_setTabView:) withObject:self];
631 
632  [self tileWithChangedItem:nil];
633 
634  // Update the selection because setSegments: did remove all previous segments AND the selection.
635  [_tabs setSelectedSegment:[self indexOfTabViewItem:_selectedTabViewItem]];
636 
637  // should we send delegate methods in bindings mode ?
638  //[self _delegateTabViewDidChangeNumberOfTabViewItems:self];
639 }
640 
641 - (void)_deselectAll
642 {
643  [_tabs setSelectedSegment:-1];
644  _selectedTabViewItem = nil;
645 }
646 
647 - (void)_displayPlaceholder:(CPString)aPlaceholder
648 {
649  if (_placeHolderView == nil)
650  {
651  _placeHolderView = [[CPView alloc] initWithFrame:CGRectMakeZero()];
652  var textField = [[CPTextField alloc] initWithFrame:CGRectMakeZero()];
653  [textField setTag:1000];
654  [textField setTextColor:[CPColor whiteColor]];
655  [textField setFont:[CPFont boldFontWithName:@"Geneva" size:18 italic:YES]];
656  [_placeHolderView addSubview:textField];
657  }
658 
659  var textField = [_placeHolderView viewWithTag:1000];
660  [textField setStringValue:aPlaceholder];
661  [textField sizeToFit];
662 
663  var boxBounds = [_box bounds],
664  textFieldBounds = [textField bounds],
665  origin = CGPointMake(CGRectGetWidth(boxBounds)/2 - CGRectGetWidth(textFieldBounds)/2, CGRectGetHeight(boxBounds)/2 - CGRectGetHeight(textFieldBounds));
666 
667  [textField setFrameOrigin:origin];
668 
669  [self _displayItemView:_placeHolderView];
670 }
671 
672 #pragma mark -
673 #pragma mark Override
674 
678 - (BOOL)acceptsFirstMouse:(CPEvent)anEvent
679 {
680  return YES;
681 }
682 
683 @end
684 
685 var _CPTabViewContentBinderNull = @"NO CONTENT";
686 @implementation _CPTabViewContentBinder : CPBinder
687 {
688  id __doxygen__;
689 }
690 
691 - (void)_updatePlaceholdersWithOptions:(CPDictionary)options
692 {
693  [super _updatePlaceholdersWithOptions:options];
694  [self _setPlaceholder:_CPTabViewContentBinderNull forMarker:CPNullMarker isDefault:YES];
695 }
696 
697 - (void)setPlaceholderValue:(id)aValue withMarker:(CPString)aMarker forBinding:(CPString)aBinding
698 {
699  [_source setItems:@[]];
700  [_source _setPlaceholderView:aValue];
701 }
702 
703 - (void)setValue:(id)aValue forBinding:(CPString)aBinding
704 {
705  [_source setItems:aValue];
706 }
707 
708 - (id)valueForBinding:(CPString)aBinding
709 {
710  return [_source items];
711 }
712 
713 @end
714 
715 var _CPTabViewSelectionBinderMultipleValues = @"Multiple Selection",
716  _CPTabViewSelectionBinderNoSelection = @"No Selection";
717 @implementation _CPTabViewSelectionBinder : CPBinder
718 {
719  id __doxygen__;
720 }
721 
722 - (void)_updatePlaceholdersWithOptions:(CPDictionary)options
723 {
724  [super _updatePlaceholdersWithOptions:options];
725 
726  [self _setPlaceholder:_CPTabViewSelectionBinderMultipleValues forMarker:CPMultipleValuesMarker isDefault:YES];
727  [self _setPlaceholder:_CPTabViewSelectionBinderNoSelection forMarker:CPNoSelectionMarker isDefault:YES];
728 }
729 
730 - (void)setPlaceholderValue:(id)aValue withMarker:(CPString)aMarker forBinding:(CPString)aBinding
731 {
732  if (aMarker == CPNoSelectionMarker || aMarker == CPNullMarker)
733  [_source _deselectAll];
734 
735  [_source _displayPlaceholder:aValue];
736 }
737 
738 - (void)setValue:(id)aValue forBinding:(CPString)aBinding
739 {
740  if (aBinding == CPSelectionIndexesBinding)
741  {
742  if (aValue == nil || [aValue count] == 0)
743  {
744  [_source _deselectAll];
745  [_source _displayPlaceholder:_CPTabViewSelectionBinderNoSelection];
746  }
747  else if ([aValue count] > 1)
748  [_source _displayPlaceholder:_CPTabViewSelectionBinderMultipleValues];
749  else if ([aValue firstIndex] < [_source numberOfTabViewItems])
750  [_source _selectTabViewItemAtIndex:[aValue firstIndex]];
751  }
752  else if (aBinding == CPSelectedIndexBinding)
753  {
754  if (aValue == CPNotFound)
755  {
756  [_source _deselectAll];
757  [_source _displayPlaceholder:_CPTabViewSelectionBinderNoSelection];
758  }
759  else if (aValue < [_source numberOfTabViewItems])
760  [_source _selectTabViewItemAtIndex:aValue];
761  }
762 }
763 
764 - (id)valueForBinding:(CPString)aBinding
765 {
766  if (aBinding == CPSelectionIndexesBinding)
767  {
768  var result = [CPIndexSet indexSet],
769  idx = [_source indexOfTabViewItem:[_source selectedTabViewItem]];
770 
771  if (idx !== CPNotFound)
772  [result addIndex:idx];
773 
774  return result;
775  }
776  else if (aBinding == CPSelectedIndexBinding)
777  return [_source indexOfTabViewItem:[_source selectedTabViewItem]];
778 }
779 
780 @end
781 
782 var CPTabViewItemsKey = "CPTabViewItemsKey",
783  CPTabViewSelectedItemKey = "CPTabViewSelectedItemKey",
784  CPTabViewTypeKey = "CPTabViewTypeKey",
785  CPTabViewFontKey = "CPTabViewFontKey",
786  CPTabViewDelegateKey = "CPTabViewDelegateKey";
787 
788 @implementation CPTabView (CPCoding)
789 
790 - (id)initWithCoder:(CPCoder)aCoder
791 {
792  if (self = [super initWithCoder:aCoder])
793  {
794  [self _init];
795 
796  _font = [aCoder decodeObjectForKey:CPTabViewFontKey];
797  [_tabs setFont:_font];
798 
799  var items = [aCoder decodeObjectForKey:CPTabViewItemsKey] || [CPArray array];
800  [self _insertTabViewItems:items atIndexes:[CPIndexSet indexSetWithIndexesInRange:CPMakeRange(0, [items count])]];
801 
802  [self setDelegate:[aCoder decodeObjectForKey:CPTabViewDelegateKey]];
803 
804  _selectedTabViewItem = [aCoder decodeObjectForKey:CPTabViewSelectedItemKey];
805 
806  _type = [aCoder decodeIntForKey:CPTabViewTypeKey];
807  }
808 
809  return self;
810 }
811 
813 {
814  [super awakeFromCib];
815 
816  // This cannot be run in initWithCoder because it might call selectTabViewItem:, which is
817  // not safe to call before the views of the tab views items are fully decoded.
818 
819  if (_selectedTabViewItem)
820  {
821  var idx = [self indexOfTabViewItem:_selectedTabViewItem];
822 
823  if (idx !== CPNotFound)
824  {
825  // Temporarily set the selected item to not selected.
826  // It allows the initial selection to be made correctly.
827  _selectedTabViewItem = nil;
828 
829  [self selectTabViewItemAtIndex:idx];
830  }
831  }
832 
833  var type = _type;
834  _type = nil;
835  [self setTabViewType:type];
836 
837  [self setNeedsLayout];
838 }
839 
840 - (void)encodeWithCoder:(CPCoder)aCoder
841 {
842  // Don't bother to encode the CPBox. We will recreate it on decode and its content view is already
843  // stored by the tab view item. Not encoding _box makes the resulting archive smaller and reduces
844  // the surface for decoding bugs (of which we've had many in tab view).
845  var subviews = [self subviews];
846  [_box removeFromSuperview];
847  [super encodeWithCoder:aCoder];
848  [self setSubviews:subviews];
849 
850  [aCoder encodeObject:_items forKey:CPTabViewItemsKey];
851 
852  [aCoder encodeConditionalObject:_selectedTabViewItem forKey:CPTabViewSelectedItemKey];
853 
854  [aCoder encodeInt:_type forKey:CPTabViewTypeKey];
855  [aCoder encodeObject:_font forKey:CPTabViewFontKey];
856 
857  [aCoder encodeConditionalObject:_delegate forKey:CPTabViewDelegateKey];
858 }
859 
860 @end
861 
862 @implementation _CPTabViewBox : CPBox
863 {
864  CPTabView _tabView;
865 }
866 
867 
868 #pragma mark -
869 #pragma mark Override
870 
871 - (CPView)hitTest:(CGPoint)aPoint
872 {
873  // Here we check if we have clicked on the segmentedControl of the tabView or not
874  // If YES, the CPBox should not handle the click
875  var segmentIndex = [_tabView._tabs testSegment:[_tabView._tabs convertPoint:aPoint fromView:[self superview]]];
876 
877  if (segmentIndex != CPNotFound)
878  return nil;
879 
880  return [super hitTest:aPoint];
881 }
882 
883 @end
Definition: CPFont.h:2
void setView:(CPView aView)
var CPTabViewWillSelectTabViewItemSelector
Definition: CPTabView.j:36
void addSubview:(CPView aSubview)
Definition: CPView.j:512
A CALayer is similar to a CPView
Definition: CALayer.j:46
int indexOfTabViewItem:(CPTabViewItem aTabViewItem)
Definition: CPTabView.j:195
var CPTabViewItemsKey
Definition: CPTabView.j:782
CPFont font()
Definition: CPTabView.j:386
var isEqual
void setBackgroundColor:(CPColor aColor)
Definition: CPTabView.j:512
CPViewController viewController()
CPFont boldFontWithName:size:italic:(CPString aName, [size] float aSize, [italic] BOOL italic)
Definition: CPFont.j:262
CGPoint locationInWindow()
Definition: CPEvent.j:290
CPColor whiteColor()
Definition: CPColor.j:360
void layoutSubviews()
Definition: CPTabView.j:447
CGRect bounds()
Definition: CPView.j:1302
A collection of unique integers.
Definition: CPIndexSet.h:2
CPView hitTest:(CGPoint aPoint)
Definition: CPView.j:1833
CPNoTabsNoBorder
Definition: CPTabView.j:31
CPContentBinding
A mutable key-value pair collection.
Definition: CPDictionary.h:2
id delegate()
Definition: CPTabView.j:481
CPTabViewType CPTopTabsBezelBorder
Definition: CPTabView.j:25
CPBottomTabsBezelBorder
Definition: CPTabView.j:27
An immutable string (collection of characters).
Definition: CPString.h:2
CPArray items()
Definition: CPTabView.j:106
CPColor colorWithCalibratedWhite:alpha:(float white, [alpha] float alpha)
Definition: CPColor.j:172
var CPTabViewDelegateKey
Definition: CPTabView.j:786
CPTabViewItem selectedTabViewItem()
Definition: CPTabView.j:376
void encodeWithCoder:(CPCoder aCoder)
Definition: CPView.j:3770
var CPTabViewDidChangeNumberOfTabViewItemsSelector
Definition: CPTabView.j:37
CPNoTabsBezelBorder
Definition: CPTabView.j:29
void setSubviews:(CPArray newSubviews)
Definition: CPView.j:708
void setTabViewType:(CPTabViewType aTabViewType)
Definition: CPTabView.j:409
CPSelectedIndexBinding
CPArray subviews()
Definition: CPView.j:495
void setNeedsLayout()
Definition: CPView.j:2707
Defines methods for use when archiving & restoring (enc/decoding).
Definition: CPCoder.h:2
var CPTabViewSelectedItemKey
Definition: CPTabView.j:783
BOOL selectTabViewItemAtIndex:(CPUInteger anIndex)
Definition: CPTabView.j:313
CPTabViewType tabViewType()
Definition: CPTabView.j:472
CPNotFound
Definition: CPObjJRuntime.j:62
void tileWithChangedItem:(CPTabViewItem aTabViewItem)
Definition: CPTabView.j:439
var CPTabViewDidSelectTabViewItemSelector
Definition: CPTabView.j:34
CPBinder binderForBinding:(CPString aBinding)
Definition: CPTabView.j:612
void setDelegate:(id< CPTabViewDelegate > aDelegate)
Definition: CPTabView.j:490
CPColor backgroundColor()
Definition: CPTabView.j:517
var CPTabViewFontKey
Definition: CPTabView.j:785
CPNoSelectionMarker
CPArray tabViewItems()
Definition: CPTabView.j:235
id indexSetWithIndexesInRange:(CPRange aRange)
Definition: CPIndexSet.j:60
Definition: CPBox.h:2
CPTabViewItem tabViewItemAtIndex:(CPUInteger anIndex)
Definition: CPTabView.j:226
Definition: CPEvent.h:2
CPView superview()
Definition: CPView.j:486
CGRect frame()
Definition: CPView.j:1022
CPNoTabsLineBorder
Definition: CPTabView.j:30
id indexSetWithIndex:(int anIndex)
Definition: CPIndexSet.j:51
void insertTabViewItem:atIndex:(CPTabViewItem aTabViewItem, [atIndex] CPUInteger anIndex)
Definition: CPTabView.j:126
CPSelectionIndexesBinding
id indexSet()
Definition: CPIndexSet.j:43
var CPTabViewShouldSelectTabViewItemSelector
Definition: CPTabView.j:35
unsigned numberOfTabViewItems()
Definition: CPTabView.j:217
CPNullMarker
Definition: CPView.j:136
var CPTabViewTypeKey
Definition: CPTabView.j:784