diff --git a/AppKit/CPTableColumn.j b/AppKit/CPTableColumn.j index 993acd22d..4b7f9a03f 100644 --- a/AppKit/CPTableColumn.j +++ b/AppKit/CPTableColumn.j @@ -71,8 +71,7 @@ CPTableColumnUserResizingMask = 2; [self setIdentifier:anIdentifier]; - var header = [CPTextField new]; - [header setBackgroundColor:[CPColor colorWithPatternImage:CPAppKitImage("tableview-headerview.png", CGSizeMake(1.0, 23.0))]]; + var header = [[_CPTableColumnHeaderView alloc] initWithFrame:CGRectMakeZero()]; [self setHeaderView:header]; var textDataView = [CPTextField new]; diff --git a/AppKit/CPTableHeaderView.j b/AppKit/CPTableHeaderView.j index 061a3b2eb..62ba593ce 100644 --- a/AppKit/CPTableHeaderView.j +++ b/AppKit/CPTableHeaderView.j @@ -23,12 +23,150 @@ @import "CPTableColumn.j" @import "CPTableView.j" @import "CPView.j" +@import +var _headerGradient = nil, + _selectedHeaderGradient = nil, + _pressedHeaderGradient = nil, + _selectedPressedHeaderGradient = nil, + + supportsCanvasGradient = NO; + +@implementation _CPTableColumnHeaderView : CPView +{ + BOOL _isPressed; + CPTextField _textField; +} + ++ (void)initialize +{ + supportsCanvasGradient = CPFeatureIsCompatible(CPHTMLCanvasFeature); +} + ++ (CGGradient)headerGradient +{ + if (!_headerGradient) + _headerGradient = CGGradientCreateWithColorComponents(CGColorSpaceCreateDeviceRGB(),[1.0,1.0,1.0,1.0,0.929,0.929,0.929,1.0], [0.3,1], 2); + + return _headerGradient; +} + ++ (CGGradient)selectedHeaderGradient +{ + if (!_selectedHeaderGradient) + _selectedHeaderGradient = CGGradientCreateWithColorComponents(CGColorSpaceCreateDeviceRGB(), [0.804,0.851,0.918,1.0,0.655,0.718,0.8,1.0], [0.3,1], 2); + + return _selectedHeaderGradient; +} + ++ (CGGradient)pressedHeaderGradient +{ + if (!_pressedHeaderGradient) + _pressedHeaderGradient = CGGradientCreateWithColorComponents(CGColorSpaceCreateDeviceRGB(),[0.929,0.929,0.929,1.0,1.0,1.0,1.0,1.0], [0.3,1], 2); + + return _pressedHeaderGradient; +} + ++ (CGGradient)selectedPressedHeaderGradient +{ + if (!_selectedPressedHeaderGradient) + _selectedPressedHeaderGradient = CGGradientCreateWithColorComponents(CGColorSpaceCreateDeviceRGB(), [0.655,0.718,0.8,1.0,0.804,0.851,0.918,1.0], [0.3,1], 2); + + return _selectedPressedHeaderGradient; +} + +- (void)initWithFrame:(CGRect)frame +{ + self = [super initWithFrame:frame]; + if (self) + { + _isPressed = NO; + _textField = [[CPTextField alloc] initWithFrame:[self bounds]]; + [_textField setAutoresizingMask:CPViewWidthSizable|CPViewHeightSizable]; + [self addSubview:_textField]; + + if (!supportsCanvasGradient) + [self setBackgroundColor:[CPColor colorWithPatternImage:CPAppKitImage("tableview-headerview.png", CGSizeMake(1.0, 22.0))]]; + + //[self setValue:headerColor forThemeAttribute:@"background-color" inState:CPThemeStateNormal]; + //[self setValue:headerHighlightedColor forThemeAttribute:@"background-color" inState:CPThemeStateHighlighted]; + } + + return self; +} + +- (void)setPressed:(BOOL)flag +{ + _isPressed = flag; + [self setNeedsDisplay:YES]; +} + +- (BOOL)setThemeState:(CPThemeState)aState +{ + if (supportsCanvasGradient) + [super setThemeState:aState]; + else if (aState & CPThemeStateHighlighted) + [self setBackgroundColor:[CPColor colorWithPatternImage:CPAppKitImage("tableview-headerview-highlighted.png", CGSizeMake(1.0, 22.0))]]; +} + +- (BOOL)unsetThemeState:(CPThemeState)aState +{ + if (supportsCanvasGradient) + [super unsetThemeState:aState]; + else if (aState & CPThemeStateHighlighted) + [self setBackgroundColor:[CPColor colorWithPatternImage:CPAppKitImage("tableview-headerview.png", CGSizeMake(1.0, 22.0))]]; +} + +- (void)setStringValue:(CPString)string +{ + [_textField setStringValue:string]; +} + +- (CPString)stringValue +{ + return [_textField stringValue]; +} + +- (void)textField +{ + return _textField; +} + +- (void)sizeToFit +{ +} + +- (void)drawRect:(CGRect)rect +{ + if (!supportsCanvasGradient) + return; + + var context = [[CPGraphicsContext currentContext] graphicsPort], + bounds = [self bounds], + isSelected = ([self themeState] & CPThemeStateSelected); + + if (_isPressed && isSelected) + gradient = [_CPTableColumnHeaderView selectedPressedHeaderGradient]; + else if (isSelected) + gradient = [_CPTableColumnHeaderView selectedHeaderGradient]; + else if (_isPressed) + gradient = [_CPTableColumnHeaderView pressedHeaderGradient]; + else + gradient = [_CPTableColumnHeaderView headerGradient]; + + CGContextBeginPath(context); + CGContextAddRect(context, bounds); + CGContextDrawLinearGradient(context, gradient, CGPointMakeZero(), CGPointMake(0, CGRectGetHeight(bounds)), 0); + CGContextClosePath(context); +} + +@end @implementation CPTableHeaderView : CPView { int _resizedColumn @accessors(readonly, property=resizedColumn); int _draggedColumn @accessors(readonly, property=draggedColumn); + int _pressedColumn @accessors(readonly, property=pressedColumn); float _draggedDistance @accessors(readonly, property=draggedDistance); @@ -43,6 +181,7 @@ { _resizedColumn = CPNotFound; _draggedColumn = CPNotFound; + _pressedColumn = CPNotFound; _draggedDistance = 0.0; } @@ -94,52 +233,156 @@ return bounds; } +- (CPRect)_resizeRectBeforeColumn:(CPInteger)column +{ + var rect = [self headerRectOfColumn:column]; + + rect.origin.x -= 10; + rect.size.width = 20; + + return rect; +} + +- (void)_updatePressed:(BOOL)flag +{ + var headerView = [_tableView._tableColumns[_pressedColumn] headerView]; + if ([headerView respondsToSelector:@selector(setPressed:)]) + [headerView setPressed:flag]; +} + +- (void)mouseDown:(CPEvent)theEvent +{ + var location = [self convertPoint:[theEvent locationInWindow] fromView:nil], + aPoint = CGPointMakeCopy(location), + clickedColumn = [self columnAtPoint:aPoint]; + + if (clickedColumn == -1) + return; + + // Error, can't find var CPTableViewDelegate_tableView_mouseDownInHeaderOfTableColumn_ !? + if (_tableView._implementedDelegateMethods & (1 << 6)) + [[_tableView delegate] tableView:_tableView + mouseDownInHeaderOfTableColumn:[[_tableView tableColumns] objectAtIndex:clickedColumn]]; + + _pressedColumn = clickedColumn; + [self _updatePressed:YES]; +} + +- (void)mouseUp:(CPEvent)theEvent +{ + var location = [self convertPoint:[theEvent locationInWindow] fromView:nil], + clickedColumn = [self columnAtPoint:location]; + + if (clickedColumn == -1) + return; + + if (_pressedColumn != CPNotFound) + { + [self _updatePressed:NO]; + _pressedColumn = CPNotFound; + } + + if ([_tableView allowsColumnSelection]) + { + if ([theEvent modifierFlags] & CPCommandKeyMask) + { + if ([_tableView isColumnSelected:clickedColumn]) + [_tableView deselectColumn:clickedColumn]; + else if ([_tableView allowsMultipleSelection] == YES) + [_tableView selectColumnIndexes:[CPIndexSet indexSetWithIndex:clickedColumn] byExtendingSelection:YES]; + } + else if ([theEvent modifierFlags] & CPShiftKeyMask) + { + // should be from clickedColumn to lastClickedColum with extending:(direction == previous selection) + var selectedIndexes = [_tableView selectedColumnIndexes], + startColumn = MIN(clickedColumn, [selectedIndexes lastIndex]), + endColumn = MAX(clickedColumn, [selectedIndexes firstIndex]); + + [_tableView selectColumnIndexes:[CPIndexSet indexSetWithIndexesInRange:CPMakeRange(startColumn, endColumn - startColumn + 1)] byExtendingSelection:YES]; + } + else + [_tableView selectColumnIndexes:[CPIndexSet indexSetWithIndex:clickedColumn] byExtendingSelection:NO]; + } +} + - (void)layoutSubviews { - var tableColumns = [_tableView tableColumns], - count = [tableColumns count], - columnRect = [self bounds], - spacing = [_tableView intercellSpacing]; - - for (i = 0; i < count; ++i) + var tableColumns = [_tableView tableColumns], + count = [tableColumns count]; + + for (var i = 0; i < count; i++) { var column = [tableColumns objectAtIndex:i], headerView = [column headerView]; - - columnRect.size.width = [column width] + spacing.width; - - [headerView setFrame:columnRect]; - - columnRect.origin.x += [column width] + spacing.width; - - [self addSubview:headerView]; + + var frame = [self headerRectOfColumn:i]; + frame.size.height -= 0.5; + if (i > 0) + { + frame.origin.x += 0.5; + frame.size.width -= 1; + } + + [headerView setFrame:frame]; + + if([headerView superview] != self) + [self addSubview:headerView]; } } - (void)drawRect:(CGRect)aRect { - [[_tableView gridColor] setStroke]; - var context = [[CPGraphicsContext currentContext] graphicsPort], - exposedColumnIndexes = exposedColumnIndexes = [_tableView columnIndexesInRect:aRect], - columnsArray = []; + exposedColumnIndexes = [_tableView columnIndexesInRect:aRect], + columnsArray = [], + tableColumns = [_tableView tableColumns], + exposedTableColumns = _tableView._exposedColumns, + firstIndex = [exposedTableColumns firstIndex], + exposedRange = CPMakeRange(firstIndex, [exposedTableColumns lastIndex] - firstIndex + 1); - [exposedColumnIndexes getIndexes:columnsArray maxCount:-1 inIndexRange:nil]; + CGContextSetLineWidth(context, 1); + CGContextSetStrokeColor(context, [_tableView gridColor]); + + [exposedColumnIndexes getIndexes:columnsArray maxCount:-1 inIndexRange:exposedRange]; var columnArrayIndex = 0, - columnArrayCount = columnsArray.length; - - for(; columnArrayIndex < columnArrayCount; ++columnArrayIndex) + columnArrayCount = columnsArray.length, + columnMaxX; + + CGContextBeginPath(context); + for(; columnArrayIndex < columnArrayCount; columnArrayIndex++) { - // grab each column rect and add horizontal lines - var columnToStroke = [self headerRectOfColumn:columnArrayIndex]; - - CGContextBeginPath(context); - CGContextMoveToPoint(context, ROUND(columnToStroke.origin.x + columnToStroke.size.width) + 0.5, ROUND(columnToStroke.origin.y) + 0.5); - CGContextAddLineToPoint(context, ROUND(columnToStroke.origin.x + columnToStroke.size.width) + 0.5, ROUND(columnToStroke.origin.y + columnToStroke.size.height) + 0.5); - CGContextSetLineWidth(context, 1); - CGContextStrokePath(context); + // grab each column rect and add vertical lines + var columnIndex = columnsArray[columnArrayIndex], + columnToStroke = [self headerRectOfColumn:columnIndex]; + + columnMaxX = CGRectGetMaxX(columnToStroke); + + CGContextMoveToPoint(context, ROUND(columnMaxX) + 0.5, ROUND(CGRectGetMinY(columnToStroke))); + CGContextAddLineToPoint(context, ROUND(columnMaxX) + 0.5, ROUND(CGRectGetMaxY(columnToStroke)) - 1); } + + CGContextClosePath(context); + CGContextStrokePath(context); + + var maxY = CGRectGetMaxY([self bounds]); + // draw normal gradient for remaining space + if (supportsCanvasGradient) + { + aRect.origin.x = columnMaxX - 0.5; + aRect.size.width -= columnMaxX; + CGContextBeginPath(context); + CGContextAddRect(context, CGRectMake(columnMaxX + 1, 0, CGRectGetMaxX([self bounds]) - columnMaxX, CGRectGetHeight([self bounds]))); + CGContextClosePath(context); + CGContextDrawLinearGradient(context, [_CPTableColumnHeaderView headerGradient], CGPointMake(0,0), CGPointMake(0, maxY - 1),0); + } + + // Draw bottom line + CGContextBeginPath(context); + CGContextMoveToPoint(context, 0, maxY - 0.5); + CGContextAddLineToPoint(context, CGRectGetMaxX([self bounds]), maxY - 0.5); + CGContextClosePath(context); + CGContextStrokePath(context); } @end diff --git a/AppKit/CPTableView.j b/AppKit/CPTableView.j index de4397fc3..176166f80 100644 --- a/AppKit/CPTableView.j +++ b/AppKit/CPTableView.j @@ -146,6 +146,7 @@ CPTableViewFirstColumnOnlyAutoresizingStyle = 5; //Configuring Behavior BOOL _allowsColumnReordering; BOOL _allowsColumnResizing; + BOOL _allowsColumnSelection; BOOL _allowsMultipleSelection; BOOL _allowsEmptySelection; @@ -766,13 +767,17 @@ window.setTimeout(function(){ - (void)deselectColumn:(CPInteger)aColumn { - [_selectedColumnIndexes removeIndex:aColumn]; + var selectedColumnIndexes = [_selectedColumnIndexes copy]; + [selectedColumnIndexes removeIndex:aColumn]; + [self selectColumnIndexes:selectedColumnIndexes byExtendingSelection:NO]; [self _noteSelectionDidChange]; } - (void)deselectRow:(CPInteger)aRow { - [_selectedRowIndexes removeIndex:aRow]; + var selectedRowIndexes = [_selectedRowIndexes copy]; + [selectedRowIndexes removeIndex:aRow]; + [self selectColumnIndexes:selectedRowIndexes byExtendingSelection:NO]; [self _noteSelectionDidChange]; } diff --git a/Tests/Manual/TableTest/AppController.j b/Tests/Manual/TableTest/AppController.j index f9fbb76bd..eb4b7830a 100644 --- a/Tests/Manual/TableTest/AppController.j +++ b/Tests/Manual/TableTest/AppController.j @@ -37,6 +37,7 @@ CPLogRegister(CPLogConsole); tableView = [[CPTableView alloc] initWithFrame:CGRectMake(0.0, 0.0, 500.0, 500.0)];//[view bounds]]; [tableView setAllowsMultipleSelection:YES]; + [tableView setAllowsColumnSelection:YES]; [tableView setUsesAlternatingRowBackgroundColors:YES]; [tableView setGridStyleMask:CPTableViewSolidHorizontalGridLineMask | CPTableViewSolidVerticalGridLineMask]; @@ -68,7 +69,7 @@ CPLogRegister(CPLogConsole); // [textDataView setBackgroundColor:[[CPColor redColor] colorWithAlphaComponent:0.5]]; - for (var i = 1; i <= 3; i++) + for (var i = 1; i <= 2; i++) { var column = [[CPTableColumn alloc] initWithIdentifier:String(i)]; @@ -85,7 +86,7 @@ CPLogRegister(CPLogConsole); //[tableView selectColumnIndexes:[CPIndexSet indexSetWithIndexesInRange:CPMakeRange(0,2)] byExtendingSelection:YES]; - [tableView setColumnAutoresizingStyle:CPTableViewUniformColumnAutoresizingStyle]; + // [tableView setColumnAutoresizingStyle:CPTableViewUniformColumnAutoresizingStyle]; var scrollView = [[CPScrollView alloc] initWithFrame:CGRectMake(0, 0, CGRectGetWidth([view bounds]), CGRectGetHeight([view bounds]))]; [tableView setRowHeight:22.0];