various-fixes

Following @aparajita indications
This commit is contained in:
Didier Korthoudt
2015-12-07 14:58:42 +01:00
parent dcc0768411
commit 08d4e19851
5 changed files with 139 additions and 112 deletions
+13
View File
@@ -24,6 +24,7 @@
@import <Foundation/CPObjJRuntime.j>
@import "CPEvent.j"
@import "CPCursor.j"
@class CPKeyBinding
@class CPMenu
@@ -200,6 +201,18 @@ CPDeleteForwardKeyCode = 46;
[_nextResponder performSelector:_cmd withObject:anEvent];
}
/*!
Notifies the receiver that the mouse entered the receiver's area and that it can adapt the cursor.
@param anEvent contains information about the exit
*/
- (void)cursorUpdate:(CPEvent)anEvent
{
if (_nextResponder)
[_nextResponder performSelector:_cmd withObject:anEvent];
else
[[CPCursor arrowCursor] set];
}
/*!
Notifies the receiver that the mouse scroll wheel has moved.
@param anEvent information about the scroll
-9
View File
@@ -692,7 +692,6 @@ var CPTableHeaderViewResizeZone = 3.0,
[[_tableView headerView] setNeedsLayout];
[[CPCursor arrowCursor] set];
[self updateTrackingAreas];
}
@@ -761,7 +760,6 @@ var CPTableHeaderViewResizeZone = 3.0,
if ([tableColumn width] != _columnOldWidth)
{
[_tableView _didResizeTableColumn:tableColumn oldWidth:_columnOldWidth];
[self updateTrackingAreas];
}
@@ -773,13 +771,6 @@ var CPTableHeaderViewResizeZone = 3.0,
- (void)_updateResizeCursor:(CPEvent)theEvent
{
// never get stuck in resize cursor mode (FIXME take out when we turn on tracking rects)
if (![_tableView allowsColumnResizing] || ([theEvent type] === CPLeftMouseUp && ![[self window] acceptsMouseMovedEvents]))
{
[[CPCursor arrowCursor] set];
return;
}
var mouseLocation = [self convertPoint:[theEvent locationInWindow] fromView:nil],
mouseOverLocation = CGPointMake(MAX(mouseLocation.x - CPTableHeaderViewResizeZone, 0.0), mouseLocation.y),
overColumn = [self columnAtPoint:mouseOverLocation];
+35 -9
View File
@@ -21,7 +21,8 @@
*/
@import <Foundation/Foundation.j>
@import "CPView.j"
@class CPView
/* @group CPTrackingAreaOptions */
@typedef CPTrackingAreaOptions
@@ -43,6 +44,10 @@ var CPTrackingAreaViewRectKey = @"CPTrackinkAreaViewRectKey",
CPTrackingAreaReferencingViewKey = @"CPTrackingAreaReferencingViewKey",
CPTrackingAreaWindowRect = @"CPTrackingAreaWindowRect";
CPTrackingOwnerImplementsMouseEntered = 1 << 1;
CPTrackingOwnerImplementsMouseExited = 1 << 2;
CPTrackingOwnerImplementsMouseMoved = 1 << 3;
CPTrackingOwnerImplementsCursorUpdate = 1 << 4;
/*!
@ingroup appkit
@@ -52,25 +57,32 @@ var CPTrackingAreaViewRectKey = @"CPTrackinkAreaViewRectKey",
*/
@implementation CPTrackingArea : CPObject
{
CGRect _viewRect @accessors(getter=rect);
CPTrackingAreaOptions _options @accessors(getter=options);
id _owner @accessors(getter=owner);
CPDictionary _userInfo @accessors(getter=userInfo);
CGRect _viewRect @accessors(getter=rect);
CPTrackingAreaOptions _options @accessors(getter=options);
id _owner @accessors(getter=owner);
CPDictionary _userInfo @accessors(getter=userInfo);
CPView _referencingView @accessors(property=view);
CGRect _windowRect @accessors(getter=actualRect);
CPView _referencingView @accessors(property=view);
CGRect _windowRect @accessors(getter=actualRect);
unsigned _implementedOwnerMethods @accessors(getter=implementedOwnerMethods);
}
#pragma mark -
#pragma mark Initialization
/*! Initializes and returns an object defining a region of a view to receive mouse-tracking events, mouse-moved events, cursor-update events, or possibly all these events.
/*!
Initializes and returns an object defining a region of a view to receive mouse-tracking events, mouse-moved events, cursor-update events, or possibly
all these events.
*/
- (CPTrackingArea)initWithRect:(CGRect)aRect options:(CPTrackingAreaOptions)options owner:(id)owner userInfo:(CPDictionary)userInfo
{
if (self = [super init])
{
if (owner === nil)
[CPException raise:CPInternalInconsistencyException reason:"No owner specified"];
if (options === 0)
[CPException raise:CPInternalInconsistencyException reason:"Invalid CPTrackingArea options"];
@@ -89,6 +101,20 @@ var CPTrackingAreaViewRectKey = @"CPTrackinkAreaViewRectKey",
_options = options;
_owner = owner;
_userInfo = userInfo;
// Cache owner implemented methods
if ([_owner respondsToSelector:@selector(mouseEntered:)])
_implementedOwnerMethods |= CPTrackingOwnerImplementsMouseEntered;
if ([_owner respondsToSelector:@selector(mouseExited:)])
_implementedOwnerMethods |= CPTrackingOwnerImplementsMouseExited;
if ([_owner respondsToSelector:@selector(mouseMoved:)])
_implementedOwnerMethods |= CPTrackingOwnerImplementsMouseMoved;
if ([_owner respondsToSelector:@selector(cursorUpdate:)])
_implementedOwnerMethods |= CPTrackingOwnerImplementsCursorUpdate;
}
return self;
@@ -98,7 +124,7 @@ var CPTrackingAreaViewRectKey = @"CPTrackinkAreaViewRectKey",
#pragma mark -
#pragma mark Implementation
- (void)_updateActualRect
- (void)_updateWindowRect
{
_windowRect = [_referencingView convertRect:((_options & CPTrackingInVisibleRect) ? [_referencingView visibleRect] : _viewRect) toView:[[_referencingView window] _windowView]];
}
+76 -80
View File
@@ -242,9 +242,7 @@ var CPViewHighDPIDrawingEnabled = YES;
CPAppearance _effectiveAppearance;
CPMutableArray _trackingAreas @accessors(getter=trackingAreas, copy);
BOOL _inhibitUpdateTrackingAreasNotifications;
// BOOL _postsUpdateTrackingAreas;
// CGRect _previousVisibleRect;
BOOL _inhibitUpdateTrackingAreas;
}
/*
@@ -814,14 +812,23 @@ var CPViewHighDPIDrawingEnabled = YES;
_window = aWindow;
// View must be added to the new window viewsWithTrackingAreas
if (_window && (_trackingAreas.length > 0))
[_window _addTrackingAreaView:self];
// Notify that view tracking areas should be updated
// Cocoa doesn't notify on leaving a window
if (_window)
[self _notifyUpdateTrackingAreasForSetWindow];
{
var owners;
if (_trackingAreas.length > 0)
{
// View must be added to the new window viewsWithTrackingAreas
[_window _addTrackingAreaView:self];
owners = [self _calcTrackingAreaOwners];
}
else
owners = [self];
// Notify that view tracking areas should be updated
// Cocoa doesn't notify on leaving a window
[self _updateTrackingAreasForOwners:owners];
}
var count = [_subviews count];
@@ -1016,8 +1023,8 @@ var CPViewHighDPIDrawingEnabled = YES;
if (_isSuperviewAClipView)
[[self superview] viewFrameChanged:[[CPNotification alloc] initWithName:CPViewFrameDidChangeNotification object:self userInfo:nil]];
if (!_inhibitUpdateTrackingAreasNotifications)
[self _notifyUpdateTrackingAreas];
if (!_inhibitUpdateTrackingAreas)
[self _updateTrackingAreas];
}
/*!
@@ -1089,8 +1096,8 @@ var CPViewHighDPIDrawingEnabled = YES;
CPDOMDisplayServerSetStyleLeftTop(_DOMElement, transform, origin.x, origin.y);
#endif
if (!_inhibitUpdateTrackingAreasNotifications && !_inhibitFrameAndBoundsChangedNotifications)
[self _notifyUpdateTrackingAreas];
if (!_inhibitUpdateTrackingAreas && !_inhibitFrameAndBoundsChangedNotifications)
[self _updateTrackingAreas];
}
/*!
@@ -1243,8 +1250,8 @@ var CPViewHighDPIDrawingEnabled = YES;
if (_isSuperviewAClipView && !_inhibitFrameAndBoundsChangedNotifications)
[[self superview] viewFrameChanged:[[CPNotification alloc] initWithName:CPViewFrameDidChangeNotification object:self userInfo:nil]];
if (!_inhibitUpdateTrackingAreasNotifications && !_inhibitFrameAndBoundsChangedNotifications)
[self _notifyUpdateTrackingAreas];
if (!_inhibitUpdateTrackingAreas && !_inhibitFrameAndBoundsChangedNotifications)
[self _updateTrackingAreas];
}
/*!
@@ -1292,8 +1299,8 @@ var CPViewHighDPIDrawingEnabled = YES;
if (_isSuperviewAClipView)
[[self superview] viewBoundsChanged:[[CPNotification alloc] initWithName:CPViewBoundsDidChangeNotification object:self userInfo:nil]];
if (!_inhibitUpdateTrackingAreasNotifications)
[self _notifyUpdateTrackingAreas];
if (!_inhibitUpdateTrackingAreas)
[self _updateTrackingAreas];
}
/*!
@@ -1360,8 +1367,8 @@ var CPViewHighDPIDrawingEnabled = YES;
if (_isSuperviewAClipView && !_inhibitFrameAndBoundsChangedNotifications)
[[self superview] viewBoundsChanged:[[CPNotification alloc] initWithName:CPViewBoundsDidChangeNotification object:self userInfo:nil]];
if (!_inhibitUpdateTrackingAreasNotifications && !_inhibitFrameAndBoundsChangedNotifications)
[self _notifyUpdateTrackingAreas];
if (!_inhibitUpdateTrackingAreas && !_inhibitFrameAndBoundsChangedNotifications)
[self _updateTrackingAreas];
}
/*!
@@ -1404,8 +1411,8 @@ var CPViewHighDPIDrawingEnabled = YES;
if (_isSuperviewAClipView && !_inhibitFrameAndBoundsChangedNotifications)
[[self superview] viewBoundsChanged:[[CPNotification alloc] initWithName:CPViewBoundsDidChangeNotification object:self userInfo:nil]];
if (!_inhibitUpdateTrackingAreasNotifications && !_inhibitFrameAndBoundsChangedNotifications)
[self _notifyUpdateTrackingAreas];
if (!_inhibitUpdateTrackingAreas && !_inhibitFrameAndBoundsChangedNotifications)
[self _updateTrackingAreas];
}
@@ -3448,7 +3455,7 @@ setBoundsOrigin:
if (_window)
[_window _addTrackingArea:trackingArea];
[trackingArea _updateActualRect];
[trackingArea _updateWindowRect];
}
- (void)removeTrackingArea:(CPTrackingArea)trackingArea
@@ -3463,37 +3470,42 @@ setBoundsOrigin:
[self _removeTrackingArea:trackingArea];
}
// Invoked automatically when the views geometry changes such that its tracking areas need to be recalculated.
/*!
Invoked automatically when the views geometry changes such that its tracking areas need to be recalculated.
You should override this method to remove out of date tracking areas and add recomputed tracking areas;
Cocoa calls this on every view, whereas they have tracking area(s) or not.
Cappuccino behaves differently :
- updateTrackingAreas is called when placing a view in the view hierarchy (that is in a window)
- if you have only CPTrackingInVisibleRect tracking areas attached to a view, it will not be called again (until you move the view in the hierarchy)
- if you have at least one non-CPTrackingInVisibleRect tracking area attached, it will be called every time the view geometry could be modified
You don't have to touch to CPTrackingInVisibleRect tracking areas, they will be automatically updated
Please note that it is the owner of a tracking area who is called for updateTrackingAreas.
But, if a view without any tracking area is inserted in the view hierarchy (that is, in a window), the view is called for updateTrackingAreas.
This enables you to use updateTrackingArea to initially attach your tracking areas to the view.
*/
- (void)updateTrackingAreas
{
// You should override this method to remove out of date tracking areas and add recomputed tracking areas;
// Cocoa calls this on every view, whereas they have tracking area(s) or not.
// Cappuccino behaves differently :
// - updateTrackingAreas is called when placing a view in the view hierarchy (that is in a window)
// - if you have only CPTrackingInVisibleRect tracking areas attached to a view, it will not be called again (until you move the view in the hierarchy)
// - if you have at least one non-CPTrackingInVisibleRect tracking area attached, it will be called every time the view geometry could be modified
// You don't have to touch to CPTrackingInVisibleRect tracking areas, they will be automatically updated
//
// Please note that it is the owner of a tracking area who is called for updateTrackingAreas.
// But, if a view without any tracking area is inserted in the view hierarchy (that is, in a window), the view is called for updateTrackingAreas.
// This enables you to use updateTrackingArea to initially attach your tracking areas to the view.
}
/*!
This utility method is intended for CPView subclasses overriding updateTrackingAreas
Typical use would be :
- (void)updateTrackingAreas
{
[self removeAllTrackingAreas];
... add your specific updated tracking areas ...
}
*/
- (void)removeAllTrackingAreas
{
// This utility method is intended for CPView subclasses overwriting updateTrackingAreas
//
// Typical use would be :
//
// - (void)updateTrackingAreas
// {
// [self removeAllTrackingAreas];
//
// ... add your specific updated tracking areas ...
// }
while (_trackingAreas.length > 0)
[self _removeTrackingArea:_trackingAreas[0]];
}
@@ -3510,70 +3522,54 @@ setBoundsOrigin:
[_trackingAreas removeObjectIdenticalTo:trackingArea];
}
- (void)_notifyUpdateTrackingAreas
- (void)_updateTrackingAreas
{
_inhibitUpdateTrackingAreasNotifications = YES;
_inhibitUpdateTrackingAreas = YES;
[self _recursiveNotifyUpdateTrackingAreas];
[self _recursivelyUpdateTrackingAreas];
_inhibitUpdateTrackingAreasNotifications = NO;
_inhibitUpdateTrackingAreas = NO;
}
- (void)_recursiveNotifyUpdateTrackingAreas
- (void)_recursivelyUpdateTrackingAreas
{
[self _notifyOwners:[self _prepareOwnersToNotify]];
// Recursive call for all subviews
[self _updateTrackingAreasForOwners:[self _calcTrackingAreaOwners]];
for (var i = 0; i < _subviews.length; i++)
[_subviews[i] _recursiveNotifyUpdateTrackingAreas];
[_subviews[i] _recursivelyUpdateTrackingAreas];
}
- (void)_notifyUpdateTrackingAreasForSetWindow
{
// As _setWindow will call recursively itself for subviews, we only have to deal with the view itself
// We also do special treatment and notify the view itself if it has no tracking area to
// enable the use of updateTrackingAreas as a mean to install tracking areas.
if ([_trackingAreas count] > 0)
var ownersToNotify = [self _prepareOwnersToNotify];
else
var ownersToNotify = @[ self ];
[self _notifyOwners:ownersToNotify]
}
- (CPArray)_prepareOwnersToNotify
- (CPArray)_calcTrackingAreaOwners
{
// First search all owners that must be notified
// Remark: 99.99% of time, the only owner will be the view itself
// In the same time, update the rects of InVisibleRect tracking areas
var ownersToNotify = [];
var owners = [];
for (var i = 0, count = [_trackingAreas count]; i < count; i++)
{
var trackingArea = _trackingAreas[i];
if ([trackingArea options] & CPTrackingInVisibleRect)
[trackingArea _updateActualRect];
[trackingArea _updateWindowRect];
else
{
var owner = [trackingArea owner];
if (![ownersToNotify containsObject:owner])
[ownersToNotify addObject:owner];
if (![owners containsObject:owner])
[owners addObject:owner];
}
}
return ownersToNotify;
return owners;
}
- (void)_notifyOwners:(CPArray)ownersToNotify
- (void)_updateTrackingAreasForOwners:(CPArray)owners
{
for (var i = 0; i < ownersToNotify.length; i++)
[ownersToNotify[i] updateTrackingAreas];
for (var i = 0; i < owners.length; i++)
[owners[i] updateTrackingAreas];
}
@end
@@ -3703,7 +3699,7 @@ var CPViewAutoresizingMaskKey = @"CPViewAutoresizingMask",
[self _decodeThemeObjectsWithCoder:aCoder];
[self setAppearance:[aCoder decodeObjectForKey:CPViewAppearanceKey]];
[self setNeedsDisplay:YES];
[self setNeedsLayout];
}
+15 -14
View File
@@ -1974,7 +1974,7 @@ CPTexturedBackgroundWindowMask
case CPRightMouseDragged:
// First, we search for any tracking area requesting CPTrackingEnabledDuringMouseDrag.
// At the same time, we update the entered stack.
[self _trackEvent:anEvent];
[self _handleTrackingAreaEvent:anEvent];
// Normal mouseDragged workflow
if (!_leftMouseDownView)
@@ -2000,7 +2000,7 @@ CPTexturedBackgroundWindowMask
if (!_acceptsMouseMovedEvents || sheet)
return;
[self _trackEvent:anEvent];
[self _handleTrackingAreaEvent:anEvent];
}
}
@@ -3856,7 +3856,7 @@ var interpolate = function(fromValue, toValue, progress)
[_trackingAreaViews removeObjectIdenticalTo:trackingAreaView];
}
- (void)_trackEvent:(CPEvent)anEvent
- (void)_handleTrackingAreaEvent:(CPEvent)anEvent
{
var mouseEnteredStack = [],
cursorUpdateStack = [],
@@ -3874,8 +3874,9 @@ var interpolate = function(fromValue, toValue, progress)
for (var j = 0; j < trackingAreas.length; j++)
{
var aTrackingArea = trackingAreas[j],
trackingOptions = [aTrackingArea options];
var aTrackingArea = trackingAreas[j],
trackingOptions = [aTrackingArea options],
trackingImplementedMethods = [aTrackingArea implementedOwnerMethods];
if (dragging && !(trackingOptions & CPTrackingEnabledDuringMouseDrag))
continue;
@@ -3894,14 +3895,14 @@ var interpolate = function(fromValue, toValue, progress)
{
// Mouse was already in this rect so it's a mouseMoved
if (!dragging && (trackingOptions & CPTrackingMouseMoved))
if (!dragging && (trackingOptions & CPTrackingMouseMoved) && (trackingImplementedMethods & CPTrackingOwnerImplementsMouseMoved))
[[aTrackingArea owner] mouseMoved:anEvent];
}
else
{
// Mouse was not in this rect so it's a mouseEntered
if (trackingOptions & CPTrackingMouseEnteredAndExited)
if ((trackingOptions & CPTrackingMouseEnteredAndExited) && (trackingImplementedMethods & CPTrackingOwnerImplementsMouseEntered))
[[aTrackingArea owner] mouseEntered:[CPEvent enterExitEventWithType:CPMouseEntered
location:point
modifierFlags:[anEvent modifierFlags]
@@ -3912,7 +3913,7 @@ var interpolate = function(fromValue, toValue, progress)
trackingArea:aTrackingArea]];
}
if (trackingOptions & CPTrackingCursorUpdate)
if ((trackingOptions & CPTrackingCursorUpdate) && (trackingImplementedMethods & CPTrackingOwnerImplementsCursorUpdate))
[cursorUpdateStack addObject:aTrackingArea];
}
}
@@ -3929,7 +3930,7 @@ var interpolate = function(fromValue, toValue, progress)
{
// Mouse is no more in this area so it's a mouseExited
if ((trackingOptions & CPTrackingMouseEnteredAndExited) && (!dragging || (dragging && (trackingOptions & CPTrackingEnabledDuringMouseDrag))))
if ((trackingOptions & CPTrackingMouseEnteredAndExited) && (!dragging || (dragging && (trackingOptions & CPTrackingEnabledDuringMouseDrag))) && (trackingImplementedMethods & CPTrackingOwnerImplementsMouseExited))
[[aTrackingArea owner] mouseExited:[CPEvent enterExitEventWithType:CPMouseExited
location:point
modifierFlags:[anEvent modifierFlags]
@@ -3958,8 +3959,8 @@ var interpolate = function(fromValue, toValue, progress)
// Cursor update
// We must send the cursorUpdate event to the frontmost view (the nearest from the mouse pointer)
// If no frontmost view is found, we set standard cursor
// We must send the cursorUpdate event to the frontmost tracking area (the nearest from the mouse pointer)
// If no frontmost tracking area is found, we set standard cursor
var nbCursorUpdates = [cursorUpdateStack count],
overlappingTrackingAreas = [];
@@ -3971,7 +3972,6 @@ var interpolate = function(fromValue, toValue, progress)
var aTrackingArea = cursorUpdateStack[i];
if ((![_cursorUpdateStack containsObject:aTrackingArea]) || (aTrackingArea === _activeCursorTrackingArea))
[overlappingTrackingAreas addObject:aTrackingArea];
}
@@ -4031,8 +4031,9 @@ var interpolate = function(fromValue, toValue, progress)
if (firstSuperview !== secondSuperview)
[CPException raise:CPInternalInconsistencyException reason:"Problem with view hierarchy"];
var firstViewIndex = [[firstSuperview subviews] indexOfObject:firstView],
secondViewIndex = [[firstSuperview subviews] indexOfObject:secondView];
var firstSuperviewSubviews = [firstSuperview subviews],
firstViewIndex = [firstSuperviewSubviews indexOfObject:firstView],
secondViewIndex = [firstSuperviewSubviews indexOfObject:secondView];
if (secondViewIndex > firstViewIndex)
{