diff --git a/AppKit/CPScrollView.j b/AppKit/CPScrollView.j index 9b92c6032..9aae4700f 100644 --- a/AppKit/CPScrollView.j +++ b/AppKit/CPScrollView.j @@ -38,7 +38,8 @@ @implementation CPScrollView : CPView { CPClipView _contentView; - + CPClipView _headerClipView; + BOOL _hasVerticalScroller; BOOL _hasHorizontalScroller; BOOL _autohidesScrollers; @@ -57,23 +58,27 @@ - (id)initWithFrame:(CGRect)aFrame { self = [super initWithFrame:aFrame]; - + if (self) { _verticalLineScroll = 10.0; _verticalPageScroll = 10.0; - + _horizontalLineScroll = 10.0; _horizontalPageScroll = 10.0; - _contentView = [[CPClipView alloc] initWithFrame:[self bounds]]; - + _contentView = [[CPClipView alloc] initWithFrame:[self clipViewFrame]]; + [self addSubview:_contentView]; - + + _headerClipView = [[CPClipView alloc] initWithFrame:[self headerClipViewFrame]]; + + [self addSubview:_headerClipView]; + [self setHasVerticalScroller:YES]; [self setHasHorizontalScroller:YES]; } - + return self; } @@ -114,7 +119,7 @@ _contentView = aContentView; - [_contentView setFrame:CGRectMake(0.0, 0.0, size.width, size.height)]; + [_contentView setFrame:[self clipViewFrame]]; [_contentView setDocumentView:documentView]; [self addSubview:_contentView]; @@ -134,8 +139,13 @@ */ - (void)setDocumentView:(CPView)aView { - [_contentView setDocumentView:aView]; - [self reflectScrolledClipView:_contentView]; + [_contentView setDocumentView:aView]; + [_headerClipView setDocumentView:[self _headerView]]; + + [_contentView setFrame:[self clipViewFrame]]; + [_headerClipView setFrame:[self headerClipViewFrame]]; + + [self reflectScrolledClipView:_contentView]; } /*! @@ -167,17 +177,19 @@ // [_horizontalScroller setEnabled:NO]; } - [_contentView setFrame:[self bounds]]; + [_contentView setFrame:[self clipViewFrame]]; --_recursionCount; return; } - var documentFrame = [documentView frame], - contentViewFrame = [self bounds], + var documentFrame = [documentView frame], // the size of the whole document + clipViewFrame = [self clipViewFrame], // the size of the visible document, within the scrollbars + headerViewFrame = [self headerClipViewFrame], + headerViewHeight = _CGRectGetHeight(headerViewFrame), scrollPoint = [_contentView bounds].origin, - difference = _CGSizeMake(CPRectGetWidth(documentFrame) - CPRectGetWidth(contentViewFrame), CPRectGetHeight(documentFrame) - CPRectGetHeight(contentViewFrame)), + difference = _CGSizeMake(CPRectGetWidth(documentFrame) - CPRectGetWidth(clipViewFrame), CPRectGetHeight(documentFrame) - CPRectGetHeight(clipViewFrame)), shouldShowVerticalScroller = (!_autohidesScrollers || difference.height > 0.0) && _hasVerticalScroller, shouldShowHorizontalScroller = (!_autohidesScrollers || difference.width > 0.0) && _hasHorizontalScroller, wasShowingVerticalScroller = ![_verticalScroller isHidden], @@ -203,17 +215,17 @@ if (shouldShowVerticalScroller) { - var verticalScrollerHeight = CPRectGetHeight(contentViewFrame); + var verticalScrollerHeight = CPRectGetHeight([self bounds]) - headerViewHeight; if (shouldShowHorizontalScroller) verticalScrollerHeight -= horizontalScrollerHeight; difference.width += verticalScrollerWidth; - contentViewFrame.size.width -= verticalScrollerWidth; + clipViewFrame.size.width -= verticalScrollerWidth; [_verticalScroller setFloatValue:(difference.height <= 0.0) ? 0.0 : scrollPoint.y / difference.height - knobProportion:CPRectGetHeight(contentViewFrame) / CPRectGetHeight(documentFrame)]; - [_verticalScroller setFrame:CPRectMake(CPRectGetMaxX(contentViewFrame), 0.0, verticalScrollerWidth, verticalScrollerHeight)]; + knobProportion:CPRectGetHeight(clipViewFrame) / CPRectGetHeight(documentFrame)]; + [_verticalScroller setFrame:CPRectMake(CPRectGetMaxX(clipViewFrame), headerViewHeight, verticalScrollerWidth, verticalScrollerHeight)]; } else if (wasShowingVerticalScroller) [_verticalScroller setFloatValue:0.0 knobProportion:1.0]; @@ -221,16 +233,17 @@ if (shouldShowHorizontalScroller) { difference.height += horizontalScrollerHeight; - contentViewFrame.size.height -= horizontalScrollerHeight; + clipViewFrame.size.height -= horizontalScrollerHeight; [_horizontalScroller setFloatValue:(difference.width <= 0.0) ? 0.0 : scrollPoint.x / difference.width - knobProportion:CPRectGetWidth(contentViewFrame) / CPRectGetWidth(documentFrame)]; - [_horizontalScroller setFrame:CPRectMake(0.0, CPRectGetMaxY(contentViewFrame), CPRectGetWidth(contentViewFrame), horizontalScrollerHeight)]; + knobProportion:CPRectGetWidth(clipViewFrame) / CPRectGetWidth(documentFrame)]; + [_horizontalScroller setFrame:CPRectMake(0.0, CPRectGetMaxY(clipViewFrame), CPRectGetWidth(clipViewFrame), horizontalScrollerHeight)]; } else if (wasShowingHorizontalScroller) [_horizontalScroller setFloatValue:0.0 knobProportion:1.0]; - [_contentView setFrame:contentViewFrame]; + [_contentView setFrame:clipViewFrame]; + [_headerClipView setFrame:headerViewFrame]; --_recursionCount; } @@ -384,13 +397,47 @@ { return _autohidesScrollers; } -/* -- (void)setFrameSize:(CPRect)aSize + + +- (CGRect)insetBounds { - [super setFrameSize:aSize]; + return [self bounds]; +} + +- (CPView)_headerView +{ + var documentView = [self documentView]; - [self reflectScrolledClipView:_contentView]; -}*/ + if ([documentView respondsToSelector:@selector(headerView)]) + return [documentView performSelector:@selector(headerView)]; + + return nil; +} + +- (CGRect)headerClipViewFrame +{ + var headerView = [self _headerView], + bounds = [self insetBounds]; + + if (!headerView) + return CGRectMakeZero(); + + bounds.size.height = [headerView bounds].size.height; + bounds.size.width -= _verticalScroller ? [_verticalScroller frame].size.width : [CPScroller scrollerWidth]; + + return bounds; +} + +- (CGRect)clipViewFrame +{ + var bounds = [self insetBounds], + headerViewFrame = [self headerClipViewFrame]; + + bounds.origin.y += headerViewFrame.size.height; + bounds.size.height -= headerViewFrame.size.height; + + return bounds; +} /* @ignore */ - (void)_verticalScrollerDidScroll:(CPScroller)aScroller @@ -448,6 +495,7 @@ } [_contentView scrollToPoint:contentBounds.origin]; + [_headerClipView scrollToPoint:CGPointMake(contentBounds.origin.x, 0.0)]; } /*! @@ -588,6 +636,7 @@ contentBounds.origin.y += [anEvent deltaY] * _verticalLineScroll; [_contentView scrollToPoint:contentBounds.origin]; + [_headerClipView scrollToPoint:CGPointMake(contentBounds.origin.x, 0.0)]; } - (void)keyDown:(CPEvent)anEvent @@ -627,6 +676,7 @@ } [_contentView scrollToPoint:contentBounds.origin]; + [_headerClipView scrollToPoint:CGPointMake(contentBounds.origin, 0)]; } @end diff --git a/AppKit/CPTableHeaderView.j b/AppKit/CPTableHeaderView.j index faa544189..ebefe4a84 100644 --- a/AppKit/CPTableHeaderView.j +++ b/AppKit/CPTableHeaderView.j @@ -1,9 +1,38 @@ +/* + * CPTableHeaderView.j + * AppKit + * + * Created by Ross Boucher. + * Copyright 2009 280 North, 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 +@import "CPTableColumn.j" +@import "CPTableView.j" +@import "CPView.j" @implementation CPTableHeaderView : CPView { + int _resizedColumn @accessors(readonly, property=resizedColumn); + int _draggedColumn @accessors(readonly, property=draggedColumn); + + float _draggedDistance @accessors(readonly, property=draggedDistance); + + CPTableView _tableView @accessors(property=tableView); } - (void)initWithFrame:(CGRect)aFrame @@ -11,9 +40,76 @@ self = [super initWithFrame:aFrame]; if (self) - [self setBackgroundColor:[CPColor redColor]]; + { + _resizedColumn = CPNotFound; + _draggedColumn = CPNotFound; + _draggedDistance = 0.0; + } return self; } -@end \ No newline at end of file +- (int)columnAtPoint:(CGPoint)aPoint +{ + if (!CGRectContainsPoint([self bounds], aPoint)) + return CPNotFound; + + // at this point, we can essentially ignore height, because all columns have equal heights + // and that height is equal to the height of our own bounds, which we know we are inside of + + var index = 0, + count = [[_tableView tableColumns] count], + tableSpacing = [_tableView intercellSpacing], + tableColumns = [_tableView tableColumns], + leftOffset = 0, + pointX = aPoint.x; + + for (; index < count; index++) + { + var width = [tableColumns[index] width] + tableSpacing.width; + + if (pointX >= leftOffset && pointX < leftOffset + width) + return index; + + leftOffset += width; + } + + return CPNotFound; +} + +- (CGRect)headerRectOfColumn:(int)aColumnIndex +{ + var tableColumns = [_tableView tableColumns], + tableSpacing = [_tableView intercellSpacing], + bounds = [self bounds]; + + if (aColumnIndex < 0 || aColumnIndex > [tableColumns count]) + [CPException raise:"invalid" reason:"tried to get headerRectOfColumn: on invalid column"]; + + bounds.size.width = [tableColumns[aColumnIndex] width] + tableSpacing.width; + + while (--aColumnIndex >= 0) + bounds.origin.x += [tableColumns[aColumnIndex] width] + tableSpacing.width; + + return bounds; +} + +- (void)drawRect:(CGRect)aRect +{ + var tableColumns = [_tableView tableColumns]; + var count = [tableColumns count]; + var columnRect = [self bounds]; + var spacing = [_tableView intercellSpacing]; + + for (i = 0; i < count; ++i) { + var column = [tableColumns objectAtIndex:i]; + var headerView = [column headerView] ; + columnRect.size.width = [column width] + spacing.width; + // [headerView setHighlighted:[_tableView isColumnSelected:[[_tableView tableColumns] indexOfObject:column]]]; + [headerView setFrame:columnRect]; + columnRect.origin.x += [column width] + spacing.width; + [self addSubview:headerView] ; + } +} + +@end diff --git a/AppKit/NEWCPTableColumn.j b/AppKit/NEWCPTableColumn.j index e9f0018c5..50aa73f4b 100644 --- a/AppKit/NEWCPTableColumn.j +++ b/AppKit/NEWCPTableColumn.j @@ -54,7 +54,7 @@ CPTableColumnUserResizingMask = 2; _maxWidth = 1000000.0; [self setIdentifier:anIdentifier]; - [self setHeaderView:[CPTableHeaderView new]]; + [self setHeaderView:[CPTextField new]]; [self setDataView:[CPTextField new]]; } diff --git a/AppKit/NEWCPTableView.j b/AppKit/NEWCPTableView.j index a26c940f9..b7a3811e0 100644 --- a/AppKit/NEWCPTableView.j +++ b/AppKit/NEWCPTableView.j @@ -79,6 +79,8 @@ CPTableViewSelectionHighlightStyleSourceList = 1; unsigned _currentHighlightedTableColumn; unsigned _numberOfRows; + + CPTableHeaderView _headerView; } - (id)initWithFrame:(CGRect)aFrame @@ -113,6 +115,11 @@ CPTableViewSelectionHighlightStyleSourceList = 1; _cachedDataViews = { }; _intercellSpacing = _CGSizeMake(0.0, 0.0); _rowHeight = 24.0; + + _headerView = [[CPTableHeaderView alloc] initWithFrame:CGRectMake(0, 0, [self bounds].size.width, _rowHeight)]; + [_headerView setAutoresizingMask:CPViewWidthSizable]; + + [_headerView setTableView:self]; } return self; @@ -459,6 +466,18 @@ _cachedDataViews = { }; * - setCornerView: * - cornerView */ + +- (CPView)headerView +{ + return _headerView; +} + +- (void)setHeaderView:(CPView)aHeaderView +{ + _headerView = aHeaderView; + [_headerView setTableView:self]; +} + //Layout Support // Complexity: diff --git a/TableTest/AppController.j b/TableTest/AppController.j index cc6d96473..98d369aa8 100644 --- a/TableTest/AppController.j +++ b/TableTest/AppController.j @@ -38,15 +38,15 @@ CPLogRegister(CPLogConsole); iconImage = [[CPImage alloc] initWithContentsOfFile:"http://cappuccino.org/images/favicon.png" size:CGSizeMake(16,16)]; - for (var i = 1; i <= 10; i++) + for (var i = 1; i <= 20; i++) { var column = [[NEWCPTableColumn alloc] initWithIdentifier:String(i)]; -// [[column headerView] setStringValue:"Number"]; -// [[column headerView] sizeToFit]; -// [column setWidth:[[column headerView] frame].size.width]; + [[column headerView] setStringValue:"Number "+i]; + [[column headerView] sizeToFit]; + [column setWidth:[[column headerView] frame].size.width + 20]; - [column setWidth:200.0]; +// [column setWidth:200.0]; [tableView addTableColumn:column]; } @@ -58,6 +58,8 @@ CPLogRegister(CPLogConsole); [view addSubview:scrollView]; + [scrollView setAutohidesScrollers:YES]; + [tableView setDelegate:self]; [tableView setDataSource:self]; }