diff --git a/AppKit/CPAccordionView.j b/AppKit/CPAccordionView.j index c9bcf71a7..ec1798a67 100644 --- a/AppKit/CPAccordionView.j +++ b/AppKit/CPAccordionView.j @@ -30,7 +30,12 @@ #import "CoreGraphics/CGGeometry.h" - +/*! + @ingroup appkit + @class CPAccordionViewItem + +
A CPAccordionViewItem represents a single section of a CPAccordionView.
+*/ @implementation CPAccordionViewItem : CPObject { CPString _identifier @accessors(property=identifier); @@ -43,6 +48,10 @@ return [self initWithIdentifier:@""]; } +/*! + Initializes a new CPAccordionViewItem with the specified identifier. This identifier may + then be used in subsequent methods to provide abstract introspection of the CPAccordionView. +*/ - (id)initWithIdentifier:(CPString)anIdentifier { self = [super init]; @@ -55,6 +64,25 @@ @end +/*! + @ingroup appkit + @class CPAccordionView + +CPAccordionView provides a container for CPAccordionViewItem objects and manages layout state + for all sublayout items.
+ + Example+var myAccordionView = [[CPAccordionView alloc] initWithFrame:CGRectMakeZero()]; +var firstItem = [[CPAccordionViewItem alloc] initWithIdentifier:@"firstSection"]]; +[firstItem setView:[[CPView alloc] initWithFrame:CGRectMakeZero()]]; +var secondItem = [[CPAccordionViewItem alloc] initWithIdentifier:@"secondSection"]]; +[secondItem setView:[[CPView alloc] initWithFrame:CGRectMakeZero()]]; +[myAccordionView addItem:firstItem]; +[myAccordionView addItem:secondItem]; +[myAccordionView setAutoresizingMask: CPViewWidthSizable | CPViewHeightSizable]; ++*/ @implementation CPAccordionView : CPView { CPInteger _dirtyItemIndex; @@ -64,7 +92,10 @@ CPMutableArray _itemViews; CPIndexSet _expandedItemIndexes; } - +/*! + Initializes the receiver for usage with the specified bounding rectangle + @return the initialized view +*/ - (id)initWithFrame:(CGRect)aFrame { self = [super initWithFrame:aFrame]; @@ -95,7 +126,11 @@ { return _items; } - +/*! + Append a CPAccordionViewItem to the receiver. Note that the CPAccordionViewItem must contain + a valid CPView derived component or a TypeError will be generated when the contents of the + ViewItem are disclosed. +*/ - (void)addItem:(CPAccordionViewItem)anItem { [self insertItem:anItem atIndex:_items.length]; diff --git a/AppKit/CPButton.j b/AppKit/CPButton.j index 8a602a607..00b898233 100644 --- a/AppKit/CPButton.j +++ b/AppKit/CPButton.j @@ -530,6 +530,7 @@ CPButtonStateMixed = CPThemeState("mixed"); [contentView setTextShadowOffset:[self currentValueForThemeAttribute:@"text-shadow-offset"]]; [contentView setImagePosition:[self currentValueForThemeAttribute:@"image-position"]]; [contentView setImageScaling:[self currentValueForThemeAttribute:@"image-scaling"]]; + [contentView setDimsImage:[self hasThemeState:CPThemeStateDisabled] && _imageDimsWhenDisabled]; } } diff --git a/AppKit/CPImageView.j b/AppKit/CPImageView.j index 234f74ceb..7d365f71f 100644 --- a/AppKit/CPImageView.j +++ b/AppKit/CPImageView.j @@ -365,7 +365,7 @@ var LEFT_SHADOW_INSET = 3.0, return _isEditable; } -- (void)performDragOperation:(CPDraggingInfo)aSender +- (BOOL)performDragOperation:(CPDraggingInfo)aSender { var images = [CPKeyedUnarchiver unarchiveObjectWithData:[[aSender draggingPasteboard] dataForType:CPImagesPboardType]]; @@ -374,6 +374,8 @@ var LEFT_SHADOW_INSET = 3.0, [self setImage:images[0]]; [self sendAction:[self action] to:[self target]]; } + + return YES; } @end diff --git a/AppKit/CPMenu/CPMenu.j b/AppKit/CPMenu/CPMenu.j index 1116437b7..687fb7045 100644 --- a/AppKit/CPMenu/CPMenu.j +++ b/AppKit/CPMenu/CPMenu.j @@ -747,6 +747,9 @@ var _CPMenuBarVisible = NO, } // Show it. + if ([CPPlatform isBrowser]) + [menuWindow setPlatformWindow:[[aView window] platformWindow]]; + [menuWindow orderFront:self]; // Track it. @@ -816,6 +819,9 @@ var _CPMenuBarVisible = NO, [menuWindow setFrameOrigin:CGRectIntersection(unconstrainedFrame, constraintRect).origin]; } + if ([CPPlatform isBrowser]) + [menuWindow setPlatformWindow:[[aView window] platformWindow]]; + [menuWindow orderFront:self]; [[_CPMenuManager sharedMenuManager] diff --git a/AppKit/CPOutlineView.j b/AppKit/CPOutlineView.j index 6711eba89..7c396f1f9 100644 --- a/AppKit/CPOutlineView.j +++ b/AppKit/CPOutlineView.j @@ -85,6 +85,8 @@ CPOutlineViewDropOnItemIndex = -1; BOOL _shouldRetargetChildIndex; CPInteger _retargedChildIndex; + CPTimer _dragHoverTimer; + id _dropItem; } - (id)initWithFrame:(CGRect)aFrame @@ -108,6 +110,7 @@ CPOutlineViewDropOnItemIndex = -1; _retargedChildIndex = nil; _shouldRetargetChildIndex = NO; + _startHoverTime = nil; [self setIndentationPerLevel:16.0]; [self setIndentationMarkerFollowsDataView:YES]; @@ -382,43 +385,14 @@ CPOutlineViewDropOnItemIndex = -1; return frame; } -- (void)selectRowIndexes:(CPIndexSet)rows byExtendingSelection:(BOOL)shouldExtendSelection +- (void)_performSelection:(BOOL)select forRow:(CPInteger)rowIndex context:(id)context { - // First un highlight the old disclosure controls - var previousSelectedRows = []; - [[self selectedRowIndexes] getIndexes:previousSelectedRows maxCount:-1 inIndexRange:nil]; + [super _performSelection:select forRow:rowIndex context:context]; - var index = [previousSelectedRows count]; - while (index--) - { - var rowIndex = previousSelectedRows[index], - item = [self itemAtRow:rowIndex]; + var control = _disclosureControlsForRows[rowIndex], + selector = select ? @"setThemeState:" : @"unsetThemeState:"; - if (![self isExpandable:item]) - continue; - - var control = _disclosureControlsForRows[rowIndex]; - [control setHighlighted:NO]; - } - - [super selectRowIndexes:rows byExtendingSelection:shouldExtendSelection]; - - // Now highlight the new disclosure controls - var selectedRows = []; - [rows getIndexes:selectedRows maxCount:-1 inIndexRange:nil]; - - var index = [selectedRows count]; - while (index--) - { - var rowIndex = selectedRows[index], - item = [self itemAtRow:rowIndex]; - - if (![self isExpandable:item]) - continue; - - var control = _disclosureControlsForRows[rowIndex]; - [control setHighlighted:YES]; - } + [control performSelector:CPSelectorFromString(selector) withObject:CPThemeStateSelected]; } - (void)setDelegate:(id)aDelegate @@ -534,6 +508,29 @@ CPOutlineViewDropOnItemIndex = -1; - (void)setDropItem:(id)theItem dropChildIndex:(int)theIndex { + if (_dropItem !== theItem && theIndex < 0 && [self isExpandable:theItem] && ![self isItemExpanded:theItem]) + { + if (_dragHoverTimer) + [_dragHoverTimer invalidate]; + + var autoExpandCallBack = function(){ + if (_dropItem) + { + [_dropOperationFeedbackView blink]; + [CPTimer scheduledTimerWithTimeInterval:.3 callback:objj_msgSend(self, "expandItem:", _dropItem) repeats:NO]; //[self expandItem:_dropItem]; + } + } + + _dragHoverTimer = [CPTimer scheduledTimerWithTimeInterval:.8 callback:autoExpandCallBack repeats:NO]; + } + + if (theIndex >= 0) + { + [_dragHoverTimer invalidate]; + _dragHoverTimer = nil; + } + + _dropItem = theItem; _retargetedItem = theItem; _shouldRetargetItem = YES; @@ -541,6 +538,14 @@ CPOutlineViewDropOnItemIndex = -1; _shouldRetargetChildIndex = YES; } +- (void)_draggingEnded +{ + [super _draggingEnded]; + _dropItem = nil; + [_dragHoverTimer invalidate]; + _dragHoverTimer = nil; +} + - (id)_parentItemForUpperRow:(int)theUpperRowIndex andLowerRow:(int)theLowerRowIndex atMouseOffset:(CPPoint)theOffset { if (_shouldRetargetItem) @@ -619,6 +624,8 @@ CPOutlineViewDropOnItemIndex = -1; _disclosureControlsForRows[row] = control; [control setState:[self isItemExpanded:item] ? CPOnState : CPOffState]; + var selector = [self isRowSelected:row] ? @"setThemeState:" : @"unsetThemeState:"; + [control performSelector:CPSelectorFromString(selector) withObject:CPThemeStateSelected]; [control setFrame:frame]; [self addSubview:control]; @@ -1080,8 +1087,10 @@ var _loadItemInfoForItem = function(/*CPOutlineView*/ anOutlineView, /*id*/ anIt CGContextAddLineToPoint(context, 0.0, 0.0); CGContextClosePath(context); - - CGContextSetFillColor(context, [self isHighlighted] ? [CPColor whiteColor] : [CPColor grayColor]); + var isHighlighted = [self hasThemeState:CPThemeStateHighlighted]; + var color = [self hasThemeState:CPThemeStateSelected] ? (isHighlighted ? [CPColor lightGrayColor] : [CPColor whiteColor]) : (isHighlighted ? [CPColor blackColor] : [CPColor grayColor]); + + CGContextSetFillColor(context, color); CGContextFillPath(context); } diff --git a/AppKit/CPTableHeaderView.j b/AppKit/CPTableHeaderView.j index 534b24da1..073db4e72 100644 --- a/AppKit/CPTableHeaderView.j +++ b/AppKit/CPTableHeaderView.j @@ -26,7 +26,7 @@ @implementation _CPTableColumnHeaderView : CPView { - _CPImageAndTextView _textField; + _CPImageAndTextView _textField; } - (void)initWithFrame:(CGRect)frame @@ -36,7 +36,7 @@ { [self _init]; } - + return self; } @@ -44,7 +44,7 @@ { _textField = [[_CPImageAndTextView alloc] initWithFrame:CGRectMake(5, 1, CGRectGetWidth([self bounds]) - 10, CGRectGetHeight([self bounds]) - 1)]; [_textField setAutoresizingMask:CPViewWidthSizable|CPViewHeightSizable]; - + [_textField setLineBreakMode:CPLineBreakByTruncatingTail]; [_textField setTextColor: [CPColor colorWithHexString: @"333333"]]; [_textField setFont:[CPFont boldSystemFontOfSize:12.0]]; @@ -137,7 +137,7 @@ var _CPTableColumnHeaderViewStringValueKey = @"_CPTableColumnHeaderViewStringVal - (void)encodeWithCoder:(CPCoder)aCoder { [super encodeWithCoder:aCoder]; - + [aCoder encodeObject:[_textField text] forKey:_CPTableColumnHeaderViewStringValueKey]; [aCoder encodeObject:[_textField image] forKey:_CPTableColumnHeaderViewImageKey]; [aCoder encodeObject:[_textField font] forKey:_CPTableColumnHeaderViewFontKey]; @@ -147,25 +147,32 @@ var _CPTableColumnHeaderViewStringValueKey = @"_CPTableColumnHeaderViewStringVal @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); - float _lastLocation; - float _columnOldWidth; - - CPTableView _tableView @accessors(property=tableView); + CPPoint _mouseDownLocation; + CPPoint _previousTrackingLocation; + int _activeColumn; + int _pressedColumn; + + BOOL _isResizing; + BOOL _isDragging; + BOOL _isTrackingColumn; + + float _columnOldWidth; + + CPTableView _tableView @accessors(property=tableView); } - (void)_init { - _resizedColumn = -1; - _draggedColumn = -1; + _mouseDownLocation = CPPointMakeZero(); + _previousTrackingLocation = CPPointMakeZero(); + _activeColumn = -1; _pressedColumn = -1; - _draggedDistance = 0.0; - _lastLocation = nil; - _columnOldWidth = nil; + + _isResizing = NO; + _isDragging = NO; + _isTrackingColumn = NO; + + _columnOldWidth = 0.0; [self setBackgroundColor:[CPColor colorWithPatternImage:CPAppKitImage("tableview-headerview.png", CGSizeMake(1.0, 22.0))]]; } @@ -182,17 +189,17 @@ var _CPTableColumnHeaderViewStringValueKey = @"_CPTableColumnHeaderViewStringVal - (int)columnAtPoint:(CGPoint)aPoint { - return [_tableView columnAtPoint:CGPointMake(aPoint.x, 0)]; + return [_tableView columnAtPoint:CGPointMake(aPoint.x, aPoint.y)]; } - (CGRect)headerRectOfColumn:(int)aColumnIndex { var headerRect = [self bounds], - columnRect = [[self tableView] rectOfColumn:aColumnIndex]; - + columnRect = [_tableView rectOfColumn:aColumnIndex]; + headerRect.origin.x = CPRectGetMinX(columnRect); headerRect.size.width = CPRectGetWidth(columnRect); - + return headerRect; } @@ -216,116 +223,292 @@ var _CPTableColumnHeaderViewStringValueKey = @"_CPTableColumnHeaderViewStringVal var headerView = [_tableView._tableColumns[_pressedColumn] headerView]; [headerView unsetThemeState:CPThemeStateHighlighted]; } - + if (column != -1) { var headerView = [_tableView._tableColumns[column] headerView]; [headerView setThemeState:CPThemeStateHighlighted]; } - + _pressedColumn = column; } - (void)mouseDown:(CPEvent)theEvent { - var mouseLocation = [self convertPoint:[theEvent locationInWindow] fromView:nil], - clickedColumn = [self columnAtPoint:mouseLocation]; - - // should we send column -1 ? - [_tableView _sendDelegateDidMouseDownInHeader:clickedColumn]; - - var resizeLocation = CGPointMake(mouseLocation.x - 5, mouseLocation.y), - resizedColumn = [self columnAtPoint:resizeLocation]; - - if (resizedColumn == -1) - return; - - // 2 different tracking methods: one for resizing/stop-resizing, another one for selection/reordering - if ([_tableView allowsColumnResizing] - && CGRectContainsPoint([self _cursorRectForColumn:resizedColumn], mouseLocation)) - { - _resizedColumn = resizedColumn; - [_tableView._tableColumns[_resizedColumn] setDisableResizingPosting:YES]; - [_tableView setDisableAutomaticResizing:YES]; - [self trackResizeWithEvent:theEvent]; - } - else - { - [self _setPressedColumn:clickedColumn]; - [self trackMouseWithEvent:theEvent]; - } + [self trackMouse:theEvent]; } -- (void)trackMouseWithEvent:(CPEvent)theEvent +- (void)trackMouse:(CPEvent)theEvent { - var type = [theEvent type]; - - if (type == CPLeftMouseUp) - { - var location = [self convertPoint:[theEvent locationInWindow] fromView:nil], - clickedColumn = [self columnAtPoint:location]; + var type = [theEvent type], + currentLocation = [self convertPoint:[theEvent locationInWindow] fromView:nil]; - [self _setPressedColumn:-1]; - - if (clickedColumn != -1) - [_tableView _didClickTableColumn:clickedColumn modifierFlags:[theEvent modifierFlags]]; - - return; - } + // Take the right columns resize tracking area into account + currentLocation.x -= 5.0; - [CPApp setTarget:self selector:@selector(trackMouseWithEvent:) forNextEventMatchingMask:CPLeftMouseDraggedMask | CPLeftMouseUpMask | CPLeftMouseDownMask untilDate:nil inMode:nil dequeue:YES]; -} - -- (void)trackResizeWithEvent:(CPEvent)anEvent -{ - var location = [self convertPoint:[anEvent locationInWindow] fromView:nil], - tableColumn = [[_tableView tableColumns] objectAtIndex:_resizedColumn], - type = [anEvent type]; - - if (_lastLocation == nil) - _lastLocation = location; - - if (_columnOldWidth == nil) - _columnOldWidth = [tableColumn width]; + var columnIndex = [self columnAtPoint:currentLocation], + shouldResize = [self shouldResizeTableColumn:columnIndex at:CPPointMake(currentLocation.x + 5.0, currentLocation.y)]; if (type === CPLeftMouseUp) - { - [self _updateResizeCursor:anEvent]; - - [tableColumn _postDidResizeNotificationWithOldWidth:_columnOldWidth]; - [tableColumn setDisableResizingPosting:NO]; - [_tableView setDisableAutomaticResizing:NO]; - - _resizedColumn = -1; - _lastLocation = nil; - _columnOldWidth = nil; - - return; - } - else if (type === CPLeftMouseDragged) { - var newWidth = [tableColumn width] + location.x - _lastLocation.x; - - if (newWidth < [tableColumn minWidth]) - [[CPCursor resizeRightCursor] set]; - else if (newWidth > [tableColumn maxWidth]) - [[CPCursor resizeLeftCursor] set]; + if (shouldResize) + [self stopResizingTableColumn:_activeColumn at:currentLocation]; + else if ([self _shouldStopTrackingTableColumn:columnIndex at:currentLocation]) + { + [_tableView _didClickTableColumn:columnIndex modifierFlags:[theEvent modifierFlags]]; + [self stopTrackingTableColumn:columnIndex at:currentLocation]; + + _isTrackingColumn = NO; + } + + [self _updateResizeCursor:[CPApp currentEvent]]; + + _activeColumn = CPNotFound; + return; + } + + if (type === CPLeftMouseDown) + { + if (columnIndex === -1) + return; + + _mouseDownLocation = currentLocation; + _activeColumn = columnIndex; + + [_tableView _sendDelegateDidMouseDownInHeader:columnIndex]; + + if (shouldResize) + [self startResizingTableColumn:columnIndex at:currentLocation]; else { - _tableView._lastColumnShouldSnap = NO; - [tableColumn setWidth:newWidth]; - // FIXME: there has to be a better way to do this... - // We should refactor the auto resizing crap. - // We need to figure out the exact cocoa behavior here though. - _lastLocation = location; + [self startTrackingTableColumn:columnIndex at:currentLocation]; + _isTrackingColumn = YES; + } + } + else if (type === CPLeftMouseDragged) + { + if (shouldResize) + [self continueResizingTableColumn:_activeColumn at:currentLocation]; + else + { + if (_activeColumn === columnIndex && CPRectContainsPoint([self headerRectOfColumn:columnIndex], currentLocation)) + { + if (_isTrackingColumn && _pressedColumn !== -1) + { + if (![self continueTrackingTableColumn:columnIndex at:currentLocation]) + return; // Stop tracking the column, because it's being dragged + } else + [self startTrackingTableColumn:columnIndex at:currentLocation]; - [[CPCursor resizeLeftRightCursor] set]; - [self setNeedsLayout]; - [self setNeedsDisplay:YES]; + } else if (_isTrackingColumn && _pressedColumn !== -1) + [self stopTrackingTableColumn:_activeColumn at:currentLocation]; } } - [CPApp setTarget:self selector:@selector(trackResizeWithEvent:) forNextEventMatchingMask:CPLeftMouseDraggedMask | CPLeftMouseUpMask untilDate:nil inMode:nil dequeue:YES]; + _previousTrackingLocation = currentLocation; + [CPApp setTarget:self selector:@selector(trackMouse:) forNextEventMatchingMask:CPLeftMouseDraggedMask | CPLeftMouseUpMask untilDate:nil inMode:nil dequeue:YES]; +} + +- (void)startTrackingTableColumn:(int)aColumnIndex at:(CPPoint)aPoint +{ + [self _setPressedColumn:aColumnIndex]; +} + +- (BOOL)continueTrackingTableColumn:(int)aColumnIndex at:(CPPoint)aPoint +{ + if ([self _shouldDragTableColumn:aColumnIndex at:aPoint]) + { + var columnRect = [self headerRectOfColumn:aColumnIndex], + offset = CPPointMakeZero(), + view = [_tableView _dragViewForColumn:aColumnIndex event:[CPApp currentEvent] offset:offset], + viewLocation = CPPointMakeZero(); + + viewLocation.x = ( CPRectGetMinX(columnRect) + offset.x ) + ( aPoint.x - _mouseDownLocation.x ); + viewLocation.y = CPRectGetMinY(columnRect) + offset.y; + + [self dragView:view at:viewLocation offset:CPSizeMakeZero() event:[CPApp currentEvent] + pasteboard:[CPPasteboard pasteboardWithName:CPDragPboard] source:self slideBack:YES]; + + return NO; + } + + return YES; +} + +- (BOOL)_shouldStopTrackingTableColumn:(int)aColumnIndex at:(CPPoint)aPoint +{ + return _isTrackingColumn && _activeColumn === aColumnIndex && + CPRectContainsPoint([self headerRectOfColumn:aColumnIndex], aPoint); +} + +- (void)stopTrackingTableColumn:(int)aColumnIndex at:(CPPoint)aPoint +{ + [self _setPressedColumn:CPNotFound]; + [self _updateResizeCursor:[CPApp currentEvent]]; +} + +- (BOOL)_shouldDragTableColumn:(int)aColumnIndex at:(CPPoint)aPoint +{ + return [_tableView allowsColumnReordering] && ABS(aPoint.x - _mouseDownLocation.x) >= 10.0; +} + +- (CPRect)_headerRectOfLastVisibleColumn +{ + var tableColumns = [_tableView tableColumns], + columnIndex = [tableColumns count]; + + while (columnIndex--) + { + var tableColumn = [tableColumns objectAtIndex:columnIndex]; + + if (![tableColumn isHidden]) + return [self headerRectOfColumn:columnIndex]; + } + + return nil; +} + +- (void)_constrainDragView:(CPView)theDragView at:(CPPoint)aPoint +{ + var tableColumns = [_tableView tableColumns], + lastColumnRect = [self _headerRectOfLastVisibleColumn]; + activeColumnRect = [self headerRectOfColumn:_activeColumn]; + dragWindow = [theDragView window], + frame = [dragWindow frame]; + + // Convert the frame origin from the global coordinate system to the windows' coordinate system + frame.origin = [[self window] convertGlobalToBase:frame.origin]; + // the from the window to the view + frame.origin = [self convertPoint:frame.origin fromView:nil]; + + // This effectively clamps the value between the minimum and maximum + frame.origin.x = MAX(0.0, MIN(CGRectGetMinX(frame), CGRectGetMaxX(lastColumnRect) - CGRectGetWidth(activeColumnRect))); + + // Make sure the column cannot move vertically + frame.origin.y = CPRectGetMinY(lastColumnRect); + + // Convert the calculated origin back to the window coordinate system + frame.origin = [self convertPoint:frame.origin toView:nil]; + // Then back to the global coordinate system + frame.origin = [[self window] convertBaseToGlobal:frame.origin]; + + [dragWindow setFrame:frame]; +} + +- (void)_moveColumn:(int)aFromIndex toColumn:(int)aToIndex +{ + [_tableView moveColumn:aFromIndex toColumn:aToIndex]; + _activeColumn = aToIndex; + _pressedColumn = _activeColumn; + + [_tableView _setDraggedColumn:_activeColumn]; +} + +- (void)draggedView:(CPView)aView beganAt:(CPPoint)aPoint +{ + _isDragging = YES; + + [[[[_tableView tableColumns] objectAtIndex:_activeColumn] headerView] setHidden:YES]; + [_tableView _setDraggedColumn:_activeColumn]; + + [self setNeedsDisplay:YES]; +} + +- (void)draggedView:(CPView)aView movedTo:(CPPoint)aPoint +{ + [self _constrainDragView:aView at:aPoint]; + + var dragWindow = [aView window], + dragWindowFrame = [dragWindow frame]; + + var hoverPoint = CGPointCreateCopy(aPoint); + + if (aPoint.x < _previousTrackingLocation.x) + hoverPoint = CGPointMake(CGRectGetMinX(dragWindowFrame), CGRectGetMinY(dragWindowFrame)); + else if (aPoint.x > _previousTrackingLocation.x) + hoverPoint = CGPointMake(CGRectGetMaxX(dragWindowFrame), CGRectGetMinY(dragWindowFrame)); + + // Convert the hover point from the global coordinate system to windows' coordinate system + hoverPoint = [[self window] convertGlobalToBase:hoverPoint]; + // then to the view + hoverPoint = [self convertPoint:hoverPoint fromView:nil]; + + var hoveredColumn = [self columnAtPoint:hoverPoint]; + + if (hoveredColumn !== -1) + { + var columnRect = [self headerRectOfColumn:hoveredColumn], + columnCenterPoint = [self convertPoint:CGPointMake(CGRectGetMidX(columnRect), CGRectGetMidY(columnRect)) fromView:self]; + if (hoveredColumn < _activeColumn && hoverPoint.x < columnCenterPoint.x) + [self _moveColumn:_activeColumn toColumn:hoveredColumn]; + else if (hoveredColumn > _activeColumn && hoverPoint.x > columnCenterPoint.x) + [self _moveColumn:_activeColumn toColumn:hoveredColumn]; + } + + _previousTrackingLocation = aPoint; +} + +- (void)draggedView:(CPImage)aView endedAt:(CGPoint)aLocation operation:(CPDragOperation)anOperation +{ + _isDragging = NO; + _isTrackingColumn = NO; // We need to do this explicitly because the mouse up section of trackMouse is never reached + + [_tableView _setDraggedColumn:-1]; + [[[[_tableView tableColumns] objectAtIndex:_activeColumn] headerView] setHidden:NO]; + [self stopTrackingTableColumn:_activeColumn at:aLocation]; + + [self setNeedsDisplay:YES]; +} + +- (BOOL)shouldResizeTableColumn:(int)aColumnIndex at:(CPPoint)aPoint +{ + if (_isResizing) + return YES; + + if (_isTrackingColumn) + return NO; + + return [_tableView allowsColumnResizing] && CPRectContainsPoint([self _cursorRectForColumn:aColumnIndex], aPoint); +} + +- (void)startResizingTableColumn:(int)aColumnIndex at:(CPPoint)aPoint +{ + _isResizing = YES; + + var tableColumn = [[_tableView tableColumns] objectAtIndex:aColumnIndex]; + + [tableColumn setDisableResizingPosting:YES]; + [_tableView setDisableAutomaticResizing:YES]; +} + +- (void)continueResizingTableColumn:(int)aColumnIndex at:(CPPoint)aPoint +{ + var tableColumn = [[_tableView tableColumns] objectAtIndex:aColumnIndex], + newWidth = [tableColumn width] + aPoint.x - _previousTrackingLocation.x; + + if (newWidth < [tableColumn minWidth]) + [[CPCursor resizeRightCursor] set]; + else if (newWidth > [tableColumn maxWidth]) + [[CPCursor resizeLeftCursor] set]; + else + { + _tableView._lastColumnShouldSnap = NO; + [tableColumn setWidth:newWidth]; + + [[CPCursor resizeLeftRightCursor] set]; + [self setNeedsLayout]; + [self setNeedsDisplay:YES]; + } +} + +- (void)stopResizingTableColumn:(int)aColumnIndex at:(CPPoint)aPoint +{ + var tableColumn = [[_tableView tableColumns] objectAtIndex:aColumnIndex]; + [tableColumn _postDidResizeNotificationWithOldWidth:_columnOldWidth]; + [tableColumn setDisableResizingPosting:NO]; + [_tableView setDisableAutomaticResizing:NO]; + + _isResizing = NO; } - (void)_updateResizeCursor:(CPEvent)theEvent @@ -340,12 +523,12 @@ var _CPTableColumnHeaderViewStringValueKey = @"_CPTableColumnHeaderViewStringVal var mouseLocation = [self convertPoint:[theEvent locationInWindow] fromView:nil], mouseOverLocation = CGPointMake(mouseLocation.x - 5, mouseLocation.y), overColumn = [self columnAtPoint:mouseOverLocation]; - + if (overColumn >= 0 && CGRectContainsPoint([self _cursorRectForColumn:overColumn], mouseLocation)) { var tableColumn = [[_tableView tableColumns] objectAtIndex:overColumn], width = [tableColumn width]; - + if (width == [tableColumn minWidth]) [[CPCursor resizeRightCursor] set]; else if (width == [tableColumn maxWidth]) @@ -357,12 +540,6 @@ var _CPTableColumnHeaderViewStringValueKey = @"_CPTableColumnHeaderViewStringVal [[CPCursor arrowCursor] set]; } -- (void)viewDidMoveToWindow -{ - //if ([_tableView allowsColumnResizing]) - // [[self window] setAcceptsMouseMovedEvents:YES]; -} - - (void)mouseEntered:(CPEvent)theEvent { [self _updateResizeCursor:theEvent]; @@ -383,12 +560,12 @@ var _CPTableColumnHeaderViewStringValueKey = @"_CPTableColumnHeaderViewStringVal { var tableColumns = [_tableView tableColumns], count = [tableColumns count]; - + for (var i = 0; i < count; i++) { var column = [tableColumns objectAtIndex:i], headerView = [column headerView]; - + var frame = [self headerRectOfColumn:i]; frame.size.height -= 0.5; if (i > 0) @@ -396,9 +573,9 @@ var _CPTableColumnHeaderViewStringValueKey = @"_CPTableColumnHeaderViewStringVal frame.origin.x += 0.5; frame.size.width -= 1; } - + [headerView setFrame:frame]; - + if([headerView superview] != self) [self addSubview:headerView]; } @@ -425,43 +602,28 @@ var _CPTableColumnHeaderViewStringValueKey = @"_CPTableColumnHeaderViewStringVal var columnArrayIndex = 0, columnArrayCount = columnsArray.length, columnMaxX; - + CGContextBeginPath(context); for(; columnArrayIndex < columnArrayCount; columnArrayIndex++) { // 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))); } - + CGContextClosePath(context); CGContextStrokePath(context); - -/* - var maxY = CGRectGetMaxY([self bounds]); - // draw normal gradient for remaining space - if (supportsCanvasGradient) + + if (_isDragging) { - 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); -*/ + CGContextSetFillColor(context, [CPColor grayColor]); + CGContextFillRect(context, [self headerRectOfColumn:_activeColumn]) + } } @end @@ -487,5 +649,4 @@ var CPTableHeaderViewTableViewKey = @"CPTableHeaderViewTableViewKey"; [aCoder encodeObject:_tableView forKey:CPTableHeaderViewTableViewKey]; } -@end - +@end \ No newline at end of file diff --git a/AppKit/CPTableView.j b/AppKit/CPTableView.j index 3768e2e60..75e096ce5 100644 --- a/AppKit/CPTableView.j +++ b/AppKit/CPTableView.j @@ -86,7 +86,7 @@ CPTableViewSolidVerticalGridLineMask = 1 << 0; CPTableViewSolidHorizontalGridLineMask = 1 << 1; CPTableViewNoColumnAutoresizing = 0; -CPTableViewUniformColumnAutoresizingStyle = 1; +CPTableViewUniformColumnAutoresizingStyle = 1; // FIX ME: This is FUBAR CPTableViewSequentialColumnAutoresizingStyle = 2; CPTableViewReverseSequentialColumnAutoresizingStyle = 3; CPTableViewLastColumnOnlyAutoresizingStyle = 4; @@ -212,6 +212,9 @@ CPTableViewFirstColumnOnlyAutoresizingStyle = 5; CPGradient _sourceListActiveGradient; CPColor _sourceListActiveTopLineColor; CPColor _sourceListActiveBottomLineColor; + + int _draggedColumnIndex; + /* CPGradient _sourceListInactiveGradient; CPColor _sourceListInactiveTopLineColor; @@ -309,7 +312,9 @@ CPTableViewFirstColumnOnlyAutoresizingStyle = 5; if (!_cornerView) _cornerView = [[_CPCornerView alloc] initWithFrame:CGRectMake(0, 0, [CPScroller scrollerWidth], CGRectGetHeight([_headerView frame]))]; - + + _draggedColumnIndex = -1; + // Gradients for the source list _sourceListActiveGradient = CGGradientCreateWithColorComponents(CGColorSpaceCreateDeviceRGB(), [89.0/255.0, 153.0/255.0, 209.0/255.0,1.0, 33.0/255.0, 94.0/255.0, 208.0/255.0,1.0], [0,1], 2); _sourceListActiveTopLineColor = [CPColor colorWithCalibratedRed:(61.0/255.0) green:(123.0/255.0) blue:(218.0/255.0) alpha:1.0]; @@ -672,6 +677,15 @@ CPTableViewFirstColumnOnlyAutoresizingStyle = 5; [self setNeedsLayout]; } +- (void)_setDraggedColumn:(int)aColumnIndex +{ + if (_draggedColumnIndex === aColumnIndex) + return; + + _draggedColumnIndex = aColumnIndex; + + [self reloadDataForRowIndexes:_exposedRows columnIndexes:[CPIndexSet indexSetWithIndex:aColumnIndex]]; +} /*! Moves the column and heading at a given index to a new given index. @@ -691,15 +705,18 @@ CPTableViewFirstColumnOnlyAutoresizingStyle = 5; else _dirtyTableColumnRangeIndex = MIN(fromIndex, toIndex, _dirtyTableColumnRangeIndex); - if (toIndex > fromIndex) - --toIndex; - var tableColumn = _tableColumns[fromIndex]; [_tableColumns removeObjectAtIndex:fromIndex]; [_tableColumns insertObject:tableColumn atIndex:toIndex]; + + [[self headerView] setNeedsLayout]; + [[self headerView] setNeedsDisplay:YES]; - [self setNeedsLayout]; + var rowIndexes = [CPIndexSet indexSetWithIndexesInRange:CPMakeRange(0, [self numberOfRows])], + columnIndexes = [CPIndexSet indexSetWithIndexesInRange:CPMakeRange(fromIndex, toIndex)]; + + [self reloadDataForRowIndexes:rowIndexes columnIndexes:columnIndexes]; } /*! @@ -717,7 +734,8 @@ CPTableViewFirstColumnOnlyAutoresizingStyle = 5; [[self headerView] setNeedsLayout]; [[self headerView] setNeedsDisplay:YES]; - [self reloadData]; + var rowIndexes = [CPIndexSet indexSetWithIndexesInRange:CPMakeRange(0, [self numberOfRows])]; + [self reloadDataForRowIndexes:rowIndexes columnIndexes:[CPIndexSet indexSetWithIndex:columnIndex]]; } - (CPArray)tableColumns @@ -835,22 +853,22 @@ CPTableViewFirstColumnOnlyAutoresizingStyle = 5; var count = deselectRows.length; while (count--) - { - var rowIndex = deselectRows[count]; - var view = dataViewsInTableColumn[rowIndex]; - [view unsetThemeState:CPThemeStateSelected]; - } - + [self _performSelection:NO forRow:deselectRows[count] context:dataViewsInTableColumn]; + count = selectRows.length; while (count--) - { - var rowIndex = selectRows[count]; - var view = dataViewsInTableColumn[rowIndex]; - [view setThemeState:CPThemeStateSelected]; - } + [self _performSelection:YES forRow:selectRows[count] context:dataViewsInTableColumn]; } } +- (void)_performSelection:(BOOL)select forRow:(CPInteger)rowIndex context:(id)context +{ + var view = context[rowIndex], + selector = select ? @"setThemeState:" : @"unsetThemeState:"; + + [view performSelector:CPSelectorFromString(selector) withObject:CPThemeStateSelected]; +} + - (void)_updateHighlightWithOldColumns:(CPIndexSet)oldColumns newColumns:(CPIndexSet)newColumns { var firstExposedColumn = [_exposedColumns firstIndex], @@ -1265,68 +1283,63 @@ CPTableViewFirstColumnOnlyAutoresizingStyle = 5; return _CGRectMake(tableColumnRange.location, _CGRectGetMinY(rectOfRow), tableColumnRange.length, _CGRectGetHeight(rectOfRow)); } -//FIX ME: We should refactor this! - (void)resizeWithOldSuperviewSize:(CGSize)aSize { [super resizeWithOldSuperviewSize:aSize]; - + if (_disableAutomaticResizing) return; var mask = _columnAutoResizingStyle; if(mask === CPTableViewUniformColumnAutoresizingStyle) - { [self _resizeAllColumnUniformlyWithOldSize:aSize]; - } - - if(mask === CPTableViewLastColumnOnlyAutoresizingStyle) - { + else if(mask === CPTableViewLastColumnOnlyAutoresizingStyle) [self sizeLastColumnToFit]; - } + else if(mask === CPTableViewFirstColumnOnlyAutoresizingStyle) + [self _autoResizeFirstColumn]; +} - if(mask === CPTableViewFirstColumnOnlyAutoresizingStyle) - { - var superview = [self superview]; +- (void)_autoResizeFirstColumn +{ + var superview = [self superview]; - if (!superview) - return; + if (!superview) + return; - var superviewSize = [superview bounds].size; + var superviewSize = [superview bounds].size; - UPDATE_COLUMN_RANGES_IF_NECESSARY(); + UPDATE_COLUMN_RANGES_IF_NECESSARY(); - var count = NUMBER_OF_COLUMNS(); + var count = NUMBER_OF_COLUMNS(), + visColumns = [[CPArray alloc] init], + totalWidth = 0, + i = 0; - var visColumns = [[CPArray alloc] init]; - var totalWidth = 0; + for(; i < count; i++) + { + if(![_tableColumns[i] isHidden]) + { + [visColumns addObject:i]; + totalWidth += [_tableColumns[i] width]; + } + } - for(var i=0; i < count; i++) - { - if(![_tableColumns[i] isHidden]) - { - [visColumns addObject:i]; - totalWidth += [_tableColumns[i] width]; - } - } + count = [visColumns count]; - count = [visColumns count]; + //if there are rows + if (count > 0) + { + var columnToResize = _tableColumns[visColumns[0]]; + var newWidth = superviewSize.width - totalWidth;// - [columnToResize width]; + newWidth += [columnToResize width]; + newWidth = (newWidth < [columnToResize minWidth]) ? [columnToResize minWidth] : newWidth; + newWidth = (newWidth > [columnToResize maxWidth]) ? [columnToResize maxWidth] : newWidth; - //if there are rows - if (count > 0) - { - var columnToResize = _tableColumns[visColumns[0]]; - var newWidth = superviewSize.width - totalWidth;// - [columnToResize width]; - newWidth += [columnToResize width]; - newWidth = (newWidth < [columnToResize minWidth]) ? [columnToResize minWidth] : newWidth; - newWidth = (newWidth > [columnToResize maxWidth]) ? [columnToResize maxWidth] : newWidth; - - [columnToResize setWidth:FLOOR(newWidth)]; - } - - [self setNeedsLayout]; - } + [columnToResize setWidth:FLOOR(newWidth)]; + } + [self setNeedsLayout]; } - (void)_resizeAllColumnUniformlyWithOldSize:(CGSize)oldSize @@ -1805,7 +1818,7 @@ CPTableViewFirstColumnOnlyAutoresizingStyle = 5; return [[CPImage alloc] initWithContentsOfFile:@"Frameworks/AppKit/Resources/GenericFile.png" size:CGSizeMake(32,32)]; } -- (CPView)dragViewForRowsWithIndexes:(CPIndexSet)theDraggedRows tableColumns:(CPArray)theTableColumns event:(CPEvent)theDragEvent offset:(CPPoint)dragViewOffset +- (CPView)dragViewForRowsWithIndexes:(CPIndexSet)theDraggedRows tableColumns:(CPArray)theTableColumns event:(CPEvent)theDragEvent offset:(CPPointPointer)dragViewOffset { var bounds = [self bounds], view = [[CPView alloc] initWithFrame:bounds]; @@ -1841,6 +1854,55 @@ CPTableViewFirstColumnOnlyAutoresizingStyle = 5; return view; } +/*! + @ignore + // Fetches all the data views (from the datasource) for the column and it's visible rows + // Copy the dataviews add them to a transparent drag view and use that drag view + // to make it appear we are dragging images of those rows (as you would do in regular Cocoa) +*/ +- (CPView)_dragViewForColumn:(int)theColumnIndex event:(CPEvent)theDragEvent offset:(CPPointPointer)theDragViewOffset +{ + var dragView = [[CPView alloc] initWithFrame:CPRectMakeZero()]; + tableColumn = [[self tableColumns] objectAtIndex:theColumnIndex], + bounds = CPRectMake(0.0, 0.0, [tableColumn width], CPRectGetHeight([self _exposedRect]) + 23.0), + columnRect = [self rectOfColumn:theColumnIndex], + headerView = [tableColumn headerView]; + + row = [_exposedRows firstIndex]; + while (row !== CPNotFound) + { + var dataView = [self _newDataViewForRow:row tableColumn:tableColumn], + dataViewFrame = [self frameOfDataViewAtColumn:theColumnIndex row:row]; + + // Only one column is ever dragged so we just place the view at + dataViewFrame.origin.x = 0.0; + + // Offset by table header height - scroll position + dataViewFrame.origin.y = ( CPRectGetMinY(dataViewFrame) - CPRectGetMinY([self _exposedRect]) ) + 23.0; + [dataView setFrame:dataViewFrame]; + + [dataView setObjectValue:[self _objectValueForTableColumn:tableColumn row:row]]; + [dragView addSubview:dataView]; + + row = [_exposedRows indexGreaterThanIndex:row]; + } + + // Add the column header view + var headerFrame = [headerView frame]; + headerFrame.origin = CPPointMakeZero(); + + columnHeaderView = [[_CPTableColumnHeaderView alloc] initWithFrame:headerFrame]; + [columnHeaderView setStringValue:[headerView stringValue]]; + [columnHeaderView setThemeState:[headerView themeState]]; + [dragView addSubview:columnHeaderView]; + + [dragView setBackgroundColor:[CPColor whiteColor]]; + [dragView setAlphaValue:0.7]; + [dragView setFrame:bounds]; + + return dragView; +} + - (void)setDraggingSourceOperationMask:(CPDragOperation)mask forLocal:(BOOL)isLocal { //ignoral local for the time being since only one capp app can run at a time... @@ -2083,7 +2145,7 @@ CPTableViewFirstColumnOnlyAutoresizingStyle = 5; var column = columnArray[columnIndex], tableColumn = _tableColumns[column]; - if ([tableColumn isHidden]) + if ([tableColumn isHidden] || columnIndex === _draggedColumnIndex) continue; var tableColumnUID = [tableColumn UID]; @@ -2239,6 +2301,15 @@ CPTableViewFirstColumnOnlyAutoresizingStyle = 5; [self drawBackgroundInClipRect:exposedRect]; [self drawGridInClipRect:exposedRect]; [self highlightSelectionInClipRect:exposedRect]; + + if (_draggedColumnIndex === -1) + return; + + var context = [[CPGraphicsContext currentContext] graphicsPort], + columnRect = [self rectOfColumn:_draggedColumnIndex]; + + CGContextSetFillColor(context, [CPColor grayColor]); + CGContextFillRect(context, columnRect); } - (void)drawBackgroundInClipRect:(CGRect)aRect @@ -2246,7 +2317,6 @@ CPTableViewFirstColumnOnlyAutoresizingStyle = 5; if (!_usesAlternatingRowBackgroundColors) return; - var rowColors = [self alternatingRowBackgroundColors], colorCount = [rowColors count]; @@ -2384,6 +2454,9 @@ CPTableViewFirstColumnOnlyAutoresizingStyle = 5; - (void)highlightSelectionInClipRect:(CGRect)aRect { + if (_selectionHighlightStyle === CPTableViewDraggingDestinationFeedbackStyleNone) + return; + var context = [[CPGraphicsContext currentContext] graphicsPort], indexes = [], rectSelector = @selector(rectOfRow:); @@ -2413,9 +2486,8 @@ CPTableViewFirstColumnOnlyAutoresizingStyle = 5; if (!count) return; - var drawGradient = (_selectionHighlightStyle === CPTableViewSelectionHighlightStyleSourceList && [_selectedRowIndexes count] >= 1); - - var deltaHeight = 0.5 * (_gridStyleMask & CPTableViewSolidHorizontalGridLineMask); + var drawGradient = (_selectionHighlightStyle === CPTableViewSelectionHighlightStyleSourceList && [_selectedRowIndexes count] >= 1), + deltaHeight = 0.5 * (_gridStyleMask & CPTableViewSolidHorizontalGridLineMask); CGContextBeginPath(context); while (count--) @@ -3331,11 +3403,12 @@ var CPTableViewDataSourceKey = @"CPTableViewDataSourceKey", unsigned dropOperation @accessors; CPTableView tableView @accessors; int currentRow @accessors; + BOOL isBlinking @accessors; } - (void)drawRect:(CGRect)aRect { - if(tableView._destinationDragStyle === CPTableViewDraggingDestinationFeedbackStyleNone) + if(tableView._destinationDragStyle === CPTableViewDraggingDestinationFeedbackStyleNone || isBlinking) return; var context = [[CPGraphicsContext currentContext] graphicsPort]; @@ -3401,7 +3474,28 @@ var CPTableViewDataSourceKey = @"CPTableViewDataSourceKey", CGContextStrokePath(context); //CGContextStrokeLineSegments(context, [aRect.origin.x + 8, aRect.origin.y + 8, 300 , aRect.origin.y + 8]); } - +} +- (void)blink +{ + if (dropOperation !== CPTableViewDropOn) + return; + + isBlinking = YES; + + var showCallback = function() { + objj_msgSend(self, "setHidden:", NO) + isBlinking = NO; + } + + var hideCallback = function() { + objj_msgSend(self, "setHidden:", YES) + isBlinking = YES; + } + + objj_msgSend(self, "setHidden:", YES); + [CPTimer scheduledTimerWithTimeInterval:0.1 callback:showCallback repeats:NO]; + [CPTimer scheduledTimerWithTimeInterval:0.19 callback:hideCallback repeats:NO]; + [CPTimer scheduledTimerWithTimeInterval:0.27 callback:showCallback repeats:NO]; } @end diff --git a/AppKit/CPViewAnimation.j b/AppKit/CPViewAnimation.j index 692523584..b1bc4d414 100644 --- a/AppKit/CPViewAnimation.j +++ b/AppKit/CPViewAnimation.j @@ -1,5 +1,5 @@ /* - * CPFlashView.j + * CPViewAnimation.j * AppKit * * Created by Klaas Pieter Annema on September 3, 2009. @@ -22,6 +22,8 @@ @import