Merge branch 'master' of git://github.com/280north/cappuccino
@@ -48,7 +48,7 @@ var HEIGHT_OF_SEGMENTED_CONTROL = 24;
|
||||
CPNumber selectedIndex;
|
||||
|
||||
CPTabViewType type;
|
||||
|
||||
|
||||
id delegate;
|
||||
unsigned delegateSelectors;
|
||||
}
|
||||
@@ -59,20 +59,23 @@ var HEIGHT_OF_SEGMENTED_CONTROL = 24;
|
||||
if (self)
|
||||
{
|
||||
items = [CPArray array];
|
||||
|
||||
|
||||
tabs = [[CPSegmentedControl alloc] initWithFrame:CGRectMake(0, 0, 0, HEIGHT_OF_SEGMENTED_CONTROL)];
|
||||
[tabs setHitTests:NO];
|
||||
|
||||
|
||||
box = [[CPBox alloc] initWithFrame:CGRectMake(0, HEIGHT_OF_SEGMENTED_CONTROL / 2, CGRectGetWidth(aFrame),
|
||||
CGRectGetHeight(aFrame) - HEIGHT_OF_SEGMENTED_CONTROL)];
|
||||
|
||||
|
||||
selectedIndex = CPNotFound;
|
||||
|
||||
|
||||
[self setTabViewType:CPTopTabsBezelBorder];
|
||||
[self setBackgroundColor:[CPColor colorWithCalibratedWhite:0.95 alpha:1.0]];
|
||||
|
||||
|
||||
[self addSubview:box];
|
||||
[self addSubview:tabs];
|
||||
|
||||
[box setAutoresizingMask:CPViewWidthSizable];
|
||||
[tabs setAutoresizingMask:CPViewMinXMargin | CPViewMaxXMargin];
|
||||
}
|
||||
return self;
|
||||
}
|
||||
@@ -96,7 +99,7 @@ var HEIGHT_OF_SEGMENTED_CONTROL = 24;
|
||||
- (void)insertTabViewItem:(CPTabViewItem)aTabViewItem atIndex:(unsigned)anIndex
|
||||
{
|
||||
[items insertObject:aTabViewItem atIndex:anIndex];
|
||||
|
||||
|
||||
[self _updateItems];
|
||||
[self _repositionTabs];
|
||||
|
||||
@@ -120,7 +123,7 @@ var HEIGHT_OF_SEGMENTED_CONTROL = 24;
|
||||
|
||||
[self _updateItems];
|
||||
[self _repositionTabs];
|
||||
|
||||
|
||||
if (delegateSelectors & CPTabViewDidChangeNumberOfTabViewItemsSelector)
|
||||
[delegate tabViewDidChangeNumberOfTabViewItems:self];
|
||||
}
|
||||
@@ -181,7 +184,7 @@ var HEIGHT_OF_SEGMENTED_CONTROL = 24;
|
||||
{
|
||||
if ([items count] === 0)
|
||||
return; // throw?
|
||||
|
||||
|
||||
[self selectTabViewItemAtIndex:0];
|
||||
}
|
||||
|
||||
@@ -193,7 +196,7 @@ var HEIGHT_OF_SEGMENTED_CONTROL = 24;
|
||||
{
|
||||
if ([items count] === 0)
|
||||
return; // throw?
|
||||
|
||||
|
||||
[self selectTabViewItemAtIndex:[items count] - 1];
|
||||
}
|
||||
|
||||
@@ -205,12 +208,13 @@ var HEIGHT_OF_SEGMENTED_CONTROL = 24;
|
||||
{
|
||||
if (selectedIndex === CPNotFound)
|
||||
return;
|
||||
|
||||
|
||||
var nextIndex = selectedIndex + 1;
|
||||
|
||||
|
||||
if (nextIndex === [items count])
|
||||
return; // 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:)
|
||||
|
||||
// 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:)
|
||||
return;
|
||||
|
||||
[self selectTabViewItemAtIndex:nextIndex];
|
||||
}
|
||||
|
||||
@@ -222,12 +226,12 @@ var HEIGHT_OF_SEGMENTED_CONTROL = 24;
|
||||
{
|
||||
if (selectedIndex === CPNotFound)
|
||||
return;
|
||||
|
||||
|
||||
var previousIndex = selectedIndex - 1;
|
||||
|
||||
if (previousIndex < 0)
|
||||
return; // does nothing. See above.
|
||||
|
||||
|
||||
[self selectTabViewItemAtIndex:previousIndex];
|
||||
}
|
||||
|
||||
@@ -250,16 +254,18 @@ var HEIGHT_OF_SEGMENTED_CONTROL = 24;
|
||||
|
||||
if (anIndex === selectedIndex)
|
||||
return;
|
||||
|
||||
|
||||
var aTabViewItem = [self tabViewItemAtIndex:anIndex];
|
||||
|
||||
if ((delegateSelectors & CPTabViewShouldSelectTabViewItemSelector) && ![delegate tabView:self shouldSelectTabViewItem:aTabViewItem])
|
||||
return;
|
||||
|
||||
if (delegateSelectors & CPTabViewWillSelectTabViewItemSelector)
|
||||
[delegate tabView:self willSelectTabViewItem:aTabViewItem];
|
||||
|
||||
|
||||
[tabs selectSegmentWithTag:anIndex];
|
||||
[self _setSelectedIndex:anIndex];
|
||||
|
||||
|
||||
if (delegateSelectors & CPTabViewDidSelectTabViewItemSelector)
|
||||
[delegate tabView:self didSelectTabViewItem:aTabViewItem];
|
||||
}
|
||||
@@ -281,18 +287,19 @@ var HEIGHT_OF_SEGMENTED_CONTROL = 24;
|
||||
{
|
||||
if (type === aTabViewType)
|
||||
return;
|
||||
|
||||
|
||||
if ((type === CPTopTabsBezelBorder || type === CPBottomTabsBezelBorder)
|
||||
&& (aTabViewType !== CPTopTabsBezelBorder && aTabViewType !== CPBottomTabsBezelBorder))
|
||||
[tabs removeFromSuperview];
|
||||
|
||||
|
||||
if ((type === CPNoTabsBezelBorder || type === CPNoTabsLineBorder || type === CPNoTabsNoBorder)
|
||||
&& (aTabViewType !== CPNoTabsBezelBorder && aTabViewType !== CPNoTabsBezelBorder && aTabViewType !== CPNoTabsNoBorder))
|
||||
[self addSubview:tabs];
|
||||
|
||||
|
||||
type = aTabViewType;
|
||||
|
||||
switch (type) {
|
||||
|
||||
switch (type)
|
||||
{
|
||||
case CPTopTabsBezelBorder:
|
||||
case CPBottomTabsBezelBorder:
|
||||
case CPNoTabsBezelBorder:
|
||||
@@ -357,7 +364,7 @@ var HEIGHT_OF_SEGMENTED_CONTROL = 24;
|
||||
- (void)mouseDown:(CPEvent)anEvent
|
||||
{
|
||||
var segmentIndex = [tabs testSegment:[tabs convertPoint:[anEvent locationInWindow] fromView:nil]];
|
||||
|
||||
|
||||
if (segmentIndex != CPNotFound)
|
||||
{
|
||||
[self selectTabViewItemAtIndex:segmentIndex];
|
||||
@@ -369,7 +376,7 @@ var HEIGHT_OF_SEGMENTED_CONTROL = 24;
|
||||
{
|
||||
var horizontalCenterOfSelf = CGRectGetWidth([self bounds]) / 2,
|
||||
verticalCenterOfTabs = CGRectGetHeight([tabs bounds]) / 2;
|
||||
|
||||
|
||||
if (type === CPBottomTabsBezelBorder)
|
||||
[tabs setCenter:CGPointMake(horizontalCenterOfSelf, CGRectGetHeight([self bounds]) - verticalCenterOfTabs)];
|
||||
else
|
||||
@@ -379,7 +386,7 @@ var HEIGHT_OF_SEGMENTED_CONTROL = 24;
|
||||
- (void)_setSelectedIndex:(CPNumber)index
|
||||
{
|
||||
selectedIndex = index;
|
||||
|
||||
|
||||
[box setContentView:[[items objectAtIndex:selectedIndex] view]];
|
||||
}
|
||||
|
||||
@@ -432,7 +439,7 @@ var CPTabViewItemsKey = "CPTabViewItemsKey",
|
||||
- (void)encodeWithCoder:(CPCoder)aCoder
|
||||
{
|
||||
[super encodeWithCoder:aCoder];
|
||||
|
||||
|
||||
[aCoder encodeObject:items forKey:CPTabViewItemsKey];;
|
||||
[aCoder encodeObject:[self selectedTabViewItem] forKey:CPTabViewSelectedItemKey];
|
||||
|
||||
|
||||
@@ -491,31 +491,48 @@ var CPThemeStateAutoCompleting = @"CPThemeStateAutoCompleting",
|
||||
if (aValue === superValue || [aValue isEqualToArray:superValue])
|
||||
return;
|
||||
|
||||
var objectValue = [aValue copy],
|
||||
contentView = [_tokenScrollView documentView];
|
||||
var contentView = [_tokenScrollView documentView];
|
||||
|
||||
// Because we do not know for sure which tokens are removed we remove them all
|
||||
for (var i = 0, count = [[self _tokens] count]; i < count; i++)
|
||||
[[[self _tokens] objectAtIndex:i] removeFromSuperview];
|
||||
|
||||
objectValue = [];
|
||||
// Preserve as many existing tokens as possible to reduce redraw flickering.
|
||||
var oldTokens = [self _tokens],
|
||||
newTokens = [];
|
||||
|
||||
if (aValue !== nil)
|
||||
{
|
||||
// Re-add all tokens
|
||||
for (var i = 0, count = [aValue count]; i < count; i++)
|
||||
{
|
||||
var token = [aValue objectAtIndex:i],
|
||||
tokenView = [[_CPTokenFieldToken alloc] init];
|
||||
// Do we have this token among the old ones?
|
||||
var tokenValue = aValue[i],
|
||||
newToken = nil;
|
||||
|
||||
[tokenView setTokenField:self];
|
||||
[tokenView setStringValue:token];
|
||||
[objectValue addObject:tokenView];
|
||||
for (var j = 0, oldCount = [oldTokens count]; j < oldCount; j++)
|
||||
{
|
||||
var oldToken = oldTokens[j];
|
||||
if ([oldToken stringValue] == tokenValue)
|
||||
{
|
||||
// Yep. Reuse it.
|
||||
[oldTokens removeObjectAtIndex:j];
|
||||
newToken = oldToken;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
[contentView addSubview:tokenView];
|
||||
if (newToken === nil)
|
||||
{
|
||||
newToken = [[_CPTokenFieldToken alloc] init];
|
||||
[newToken setTokenField:self];
|
||||
[newToken setStringValue:tokenValue];
|
||||
[contentView addSubview:newToken];
|
||||
}
|
||||
|
||||
newTokens.push(newToken);
|
||||
}
|
||||
}
|
||||
|
||||
// Remove any now unused tokens.
|
||||
for (var j = 0, oldCount = [oldTokens count]; j < oldCount; j++)
|
||||
[oldTokens[j] removeFromSuperview];
|
||||
|
||||
/*
|
||||
[CPTextField setObjectValue] will try to set the _inputElement.value to
|
||||
the new objectValue, if the _inputElement exists. This is wrong for us
|
||||
@@ -524,7 +541,7 @@ var CPThemeStateAutoCompleting = @"CPThemeStateAutoCompleting",
|
||||
|
||||
Instead do what CPControl setObjectValue would.
|
||||
*/
|
||||
_value = objectValue;
|
||||
_value = newTokens;
|
||||
|
||||
// Reset the selection.
|
||||
[self _selectToken:nil byExtendingSelection:NO];
|
||||
|
||||
|
Before Width: | Height: | Size: 150 B After Width: | Height: | Size: 151 B |
|
Before Width: | Height: | Size: 245 B After Width: | Height: | Size: 242 B |
|
Before Width: | Height: | Size: 158 B After Width: | Height: | Size: 151 B |
|
Before Width: | Height: | Size: 530 B After Width: | Height: | Size: 532 B |
|
Before Width: | Height: | Size: 537 B After Width: | Height: | Size: 524 B |
|
Before Width: | Height: | Size: 512 B After Width: | Height: | Size: 522 B |
|
Before Width: | Height: | Size: 524 B After Width: | Height: | Size: 520 B |
@@ -824,8 +824,8 @@ var themedButtonValues = nil,
|
||||
[@"content-inset", CGInsetMake(7.0, 0.0, 4.0, 0.0)],
|
||||
// Placeholder is displayed as regular text, not tokens; requires a different inset.
|
||||
[@"content-inset", CGInsetMake(9.0, 0.0, 5.0, 2.0), CPTextFieldStatePlaceholder],
|
||||
[@"content-inset", CGInsetMake(7.0, 5.0, 4.0, 6.0), CPThemeStateBezeled],
|
||||
[@"content-inset", CGInsetMake(9.0, 7.0, 5.0, 8.0), CPThemeStateBezeled | CPTextFieldStatePlaceholder],
|
||||
[@"content-inset", CGInsetMake(7.0, 5.0, 5.0, 6.0), CPThemeStateBezeled],
|
||||
[@"content-inset", CGInsetMake(9.0, 7.0, 6.0, 8.0), CPThemeStateBezeled | CPTextFieldStatePlaceholder],
|
||||
];
|
||||
|
||||
[self registerThemeValues:overrides forView:tokenfield inherit:themedTextFieldValues];
|
||||
@@ -835,21 +835,21 @@ var themedButtonValues = nil,
|
||||
|
||||
+ (_CPTokenFieldToken)themedTokenFieldToken
|
||||
{
|
||||
var token = [[_CPTokenFieldToken alloc] initWithFrame:CGRectMake(0.0, 0.0, 60.0, 19.0)],
|
||||
var token = [[_CPTokenFieldToken alloc] initWithFrame:CGRectMake(0.0, 0.0, 60.0, 18.0)],
|
||||
|
||||
bezelColor = PatternColor(
|
||||
[
|
||||
["token-left.png", 11.0, 19.0],
|
||||
["token-center.png", 1.0, 19.0],
|
||||
["token-right.png", 11.0, 19.0]
|
||||
["token-left.png", 11.0, 18.0],
|
||||
["token-center.png", 1.0, 18.0],
|
||||
["token-right.png", 11.0, 18.0]
|
||||
],
|
||||
PatternIsHorizontal),
|
||||
|
||||
bezelHighlightedColor = PatternColor(
|
||||
[
|
||||
["token-highlighted-left.png", 11.0, 19.0],
|
||||
["token-highlighted-center.png", 1.0, 19.0],
|
||||
["token-highlighted-right.png", 11.0, 19.0]
|
||||
["token-highlighted-left.png", 11.0, 18.0],
|
||||
["token-highlighted-center.png", 1.0, 18.0],
|
||||
["token-highlighted-right.png", 11.0, 18.0]
|
||||
],
|
||||
PatternIsHorizontal),
|
||||
|
||||
@@ -865,11 +865,11 @@ var themedButtonValues = nil,
|
||||
[@"text-color", textHighlightedColor, CPThemeStateHighlighted],
|
||||
|
||||
[@"bezel-inset", CGInsetMake(0.0, 0.0, 0.0, 0.0), CPThemeStateBezeled],
|
||||
[@"content-inset", CGInsetMake(1.0, 24.0, 2.0, 16.0), CPThemeStateBezeled],
|
||||
[@"content-inset", CGInsetMake(2.0, 24.0, 2.0, 16.0), CPThemeStateBezeled],
|
||||
|
||||
// Minimum height == maximum height since tokens are fixed height.
|
||||
[@"min-size", CGSizeMake(0.0, 19.0)],
|
||||
[@"max-size", CGSizeMake(-1.0, 19.0)],
|
||||
[@"min-size", CGSizeMake(0.0, 18.0)],
|
||||
[@"max-size", CGSizeMake(-1.0, 18.0)],
|
||||
|
||||
[@"vertical-alignment", CPCenterTextAlignment],
|
||||
];
|
||||
|
||||
@@ -0,0 +1,65 @@
|
||||
@import <Foundation/Foundation.j>
|
||||
@import <AppKit/AppKit.j>
|
||||
|
||||
|
||||
|
||||
@implementation CPTabView (TEST)
|
||||
|
||||
- (CPSegmentedControl)tabs
|
||||
{
|
||||
return tabs;
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
|
||||
@implementation CPTabViewTest : OJTestCase
|
||||
{
|
||||
CPTabView _tableView;
|
||||
CPTabViewItem _tabItem1;
|
||||
CPTabViewItem _tabItem2;
|
||||
}
|
||||
|
||||
- (void)setUp
|
||||
{
|
||||
_tabView = [[CPTabView alloc] initWithFrame:CGRectMake(0, 0, 800, 600)];
|
||||
|
||||
_tabItem1 = [[CPTabViewItem alloc] initWithIdentifier:@"id1"];
|
||||
[_tabItem1 setLabel:@"Item A"];
|
||||
[_tabItem1 setView:[[CPView alloc] initWithFrame:CGRectMake(0, 0, 100, 100)]]
|
||||
|
||||
_tabItem2 = [[CPTabViewItem alloc] initWithIdentifier:@"id2"];
|
||||
[_tabItem2 setLabel:@"Item B"];
|
||||
[_tabItem2 setView:[[CPView alloc] initWithFrame:CGRectMake(0, 0, 100, 100)]]
|
||||
|
||||
[_tabView addTabViewItem:_tabItem1];
|
||||
[_tabView addTabViewItem:_tabItem2];
|
||||
}
|
||||
|
||||
- (void)testCreate
|
||||
{
|
||||
[self assertNotNull:_tabView];
|
||||
|
||||
}
|
||||
|
||||
- (void)testMiddle
|
||||
{
|
||||
var tabs = [_tabView tabs];
|
||||
[self assert:([_tabView frameSize].width / 2) equals:CPRectGetMidX([tabs frame])];
|
||||
}
|
||||
|
||||
- (void)testMiddleAfterMoveFrame
|
||||
{
|
||||
var tabs = [_tabView tabs];
|
||||
[_tabView setFrame:CPRectMake(10, 100, 1000, 200)];
|
||||
[self assert:([_tabView frameSize].width / 2) equals:CPRectGetMidX([tabs frame])];
|
||||
}
|
||||
|
||||
- (void)testMiddleAfterMoveBound
|
||||
{
|
||||
var tabs = [_tabView tabs];
|
||||
[_tabView setBounds:CPRectMake(100, 100, 20, 300)];
|
||||
[self assert:([tabs boundsSize].width / 2) equals:CPRectGetMidX([tabs bounds])];
|
||||
}
|
||||
|
||||
@end
|
||||