mirror of
https://github.com/cappuccino/cappuccino.git
synced 2026-08-25 04:57:03 +00:00
First submit for CPTrackingArea
This commit is contained in:
@@ -103,6 +103,7 @@
|
||||
@import "CPTokenField.j"
|
||||
@import "CPToolbar.j"
|
||||
@import "CPToolbarItem.j"
|
||||
@import "CPTrackingArea.j"
|
||||
@import "CPTreeNode.j"
|
||||
@import "CPUserDefaultsController.j"
|
||||
@import "CPView.j"
|
||||
|
||||
@@ -27,6 +27,7 @@
|
||||
@import "CPShadow.j"
|
||||
@import "CPView.j"
|
||||
@import "CPKeyValueBinding.j"
|
||||
@import "CPTrackingArea.j"
|
||||
|
||||
@global CPApp
|
||||
|
||||
@@ -195,11 +196,23 @@ var CPControlBlackColor = [CPColor blackColor];
|
||||
{
|
||||
_sendActionOn = CPLeftMouseUpMask;
|
||||
_trackingMouseDownFlags = 0;
|
||||
|
||||
[self addTrackingArea:[[CPTrackingArea alloc] initWithRect:CGRectMakeZero()
|
||||
options:CPTrackingMouseEnteredAndExited | CPTrackingActiveInKeyWindow | CPTrackingInVisibleRect
|
||||
owner:self
|
||||
userInfo:nil]];
|
||||
}
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)awakeFromCib
|
||||
{
|
||||
[self addTrackingArea:[[CPTrackingArea alloc] initWithRect:CGRectMakeZero()
|
||||
options:CPTrackingMouseEnteredAndExited | CPTrackingActiveInKeyWindow | CPTrackingInVisibleRect
|
||||
owner:self
|
||||
userInfo:nil]];
|
||||
}
|
||||
|
||||
#pragma mark -
|
||||
#pragma mark Control Size
|
||||
|
||||
@@ -29,6 +29,7 @@
|
||||
@import "CPCompatibility.j"
|
||||
@import "CGGeometry.j"
|
||||
@import "CPText.j"
|
||||
@import "CPTrackingArea.j"
|
||||
|
||||
@class CPTextField
|
||||
@class CPWindow
|
||||
@@ -82,6 +83,8 @@ var _CPEventPeriodicEventPeriod = 0,
|
||||
BOOL _suppressCappuccinoCut;
|
||||
BOOL _suppressCappuccinoPaste;
|
||||
#endif
|
||||
|
||||
CPTrackingArea _trackingArea;
|
||||
}
|
||||
|
||||
/*!
|
||||
@@ -141,6 +144,27 @@ var _CPEventPeriodicEventPeriod = 0,
|
||||
timestamp:aTimestamp windowNumber:aWindowNumber context:aGraphicsContext eventNumber:anEventNumber clickCount:aClickCount pressure:aPressure];
|
||||
}
|
||||
|
||||
/*!
|
||||
Creates a new mouse tracking event.
|
||||
|
||||
@param anEventType the event type
|
||||
@param aPoint the location of the cursor in the window specified by \c aWindowNumber
|
||||
@param modifierFlags a bitwise combination of the modifiers specified in the CPEvent globals
|
||||
@param aTimestamp the time the event occurred
|
||||
@param aWindowNumber the number of the CPWindow where the event occurred
|
||||
@param aGraphicsContext the graphics context where the event occurred
|
||||
@param anEventNumber a number for this event
|
||||
@param aTrackingArea the tracking area that triggered the event
|
||||
@throws CPInternalInconsistencyException if an invalid event type is provided
|
||||
@return the new mouse event
|
||||
*/
|
||||
+ (id)enterExitEventWithType:(CPEventType)anEventType location:(CGPoint)aPoint modifierFlags:(unsigned)modifierFlags
|
||||
timestamp:(CPTimeInterval)aTimestamp windowNumber:(int)aWindowNumber context:(CPGraphicsContext)aGraphicsContext
|
||||
eventNumber:(int)anEventNumber trackingArea:(CPTrackingArea)aTrackingArea
|
||||
{
|
||||
return [[self alloc] _initEnterExitEventWithType:anEventType location:aPoint modifierFlags:modifierFlags timestamp:aTimestamp windowNumber:aWindowNumber context:aGraphicsContext eventNumber:anEventNumber trackingArea:aTrackingArea];
|
||||
}
|
||||
|
||||
/*!
|
||||
Creates a new custom event.
|
||||
|
||||
@@ -201,6 +225,28 @@ var _CPEventPeriodicEventPeriod = 0,
|
||||
return self;
|
||||
}
|
||||
|
||||
/* @ignore */
|
||||
- (id)_initEnterExitEventWithType:(CPEventType)anEventType location:(CGPoint)aPoint modifierFlags:(unsigned)modifierFlags
|
||||
timestamp:(CPTimeInterval)aTimestamp windowNumber:(int)aWindowNumber context:(CPGraphicsContext)aGraphicsContext
|
||||
eventNumber:(int)anEventNumber trackingArea:(CPTrackingArea)aTrackingArea
|
||||
{
|
||||
if ((anEventType != CPMouseEntered) && (anEventType != CPMouseExited) && (anEventType != CPCursorUpdate))
|
||||
[CPException raise:CPInternalInconsistencyException reason:"Invalid event type"];
|
||||
|
||||
if (self = [self _initWithType:anEventType])
|
||||
{
|
||||
_location = CGPointCreateCopy(aPoint);
|
||||
_modifierFlags = modifierFlags;
|
||||
_timestamp = aTimestamp;
|
||||
_context = aGraphicsContext;
|
||||
_eventNumber = anEventNumber;
|
||||
_trackingArea = aTrackingArea;
|
||||
_window = [CPApp windowWithWindowNumber:aWindowNumber];
|
||||
}
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
/* @ignore */
|
||||
- (id)_initKeyEventWithType:(CPEventType)anEventType location:(CGPoint)aPoint modifierFlags:(unsigned int)modifierFlags
|
||||
timestamp:(CPTimeInterval)aTimestamp windowNumber:(int)aWindowNumber context:(CPGraphicsContext)aGraphicsContext
|
||||
@@ -583,6 +629,14 @@ var _CPEventPeriodicEventPeriod = 0,
|
||||
}
|
||||
}
|
||||
|
||||
- (CPTrackingArea)trackingArea
|
||||
{
|
||||
if ((_type != CPMouseEntered) && (_type != CPMouseExited) && (_type != CPCursorUpdate))
|
||||
[CPException raise:CPInternalInconsistencyException reason:"You can't call trackingArea for this event type"];
|
||||
|
||||
return _trackingArea;
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
function _CPEventFirePeriodEvent()
|
||||
|
||||
@@ -26,6 +26,7 @@
|
||||
@import "CPImage.j"
|
||||
@import "CPView.j"
|
||||
@import "CPCursor.j"
|
||||
@import "CPTrackingArea.j"
|
||||
|
||||
@class CPUserDefaults
|
||||
@global CPApp
|
||||
@@ -145,6 +146,14 @@ var ShouldSuppressResizeNotifications = 1,
|
||||
};
|
||||
}
|
||||
|
||||
- (void)awakeFromCib
|
||||
{
|
||||
[self addTrackingArea:[[CPTrackingArea alloc] initWithRect:CGRectMakeZero()
|
||||
options:CPTrackingMouseEnteredAndExited | CPTrackingMouseMoved | CPTrackingActiveInKeyWindow | CPTrackingInVisibleRect
|
||||
owner:self
|
||||
userInfo:nil]];
|
||||
}
|
||||
|
||||
- (id)initWithFrame:(CGRect)aFrame
|
||||
{
|
||||
if (self = [super initWithFrame:aFrame])
|
||||
@@ -159,6 +168,11 @@ var ShouldSuppressResizeNotifications = 1,
|
||||
_shouldAutosave = YES;
|
||||
|
||||
[self _setVertical:YES];
|
||||
|
||||
[self addTrackingArea:[[CPTrackingArea alloc] initWithRect:CGRectMakeZero()
|
||||
options:CPTrackingMouseEnteredAndExited | CPTrackingMouseMoved | CPTrackingActiveInKeyWindow | CPTrackingInVisibleRect
|
||||
owner:self
|
||||
userInfo:nil]];
|
||||
}
|
||||
|
||||
return self;
|
||||
|
||||
@@ -24,6 +24,7 @@
|
||||
@import "CPView.j"
|
||||
@import "CPCursor.j"
|
||||
@import "_CPImageAndTextView.j"
|
||||
@import "CPTrackingArea.j"
|
||||
|
||||
@class CPTableView
|
||||
|
||||
@@ -281,6 +282,14 @@ var CPTableHeaderViewResizeZone = 3.0,
|
||||
};
|
||||
}
|
||||
|
||||
- (void)awakeFromCib
|
||||
{
|
||||
[self addTrackingArea:[[CPTrackingArea alloc] initWithRect:CGRectMakeZero()
|
||||
options:CPTrackingMouseEnteredAndExited | CPTrackingMouseMoved | CPTrackingMouseMoved | CPTrackingActiveInKeyWindow | CPTrackingInVisibleRect
|
||||
owner:self
|
||||
userInfo:nil]];
|
||||
}
|
||||
|
||||
- (void)_init
|
||||
{
|
||||
_mouseDownLocation = CGPointMakeZero();
|
||||
@@ -305,7 +314,13 @@ var CPTableHeaderViewResizeZone = 3.0,
|
||||
self = [super initWithFrame:aFrame];
|
||||
|
||||
if (self)
|
||||
{
|
||||
[self _init];
|
||||
[self addTrackingArea:[[CPTrackingArea alloc] initWithRect:CGRectMakeZero()
|
||||
options:CPTrackingMouseEnteredAndExited | CPTrackingMouseMoved | CPTrackingMouseMoved | CPTrackingActiveInKeyWindow | CPTrackingInVisibleRect
|
||||
owner:self
|
||||
userInfo:nil]];
|
||||
}
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,138 @@
|
||||
/*
|
||||
* CPTrackingArea.j
|
||||
* AppKit
|
||||
*
|
||||
* Created by Didier Korthoudt.
|
||||
* Copyright 2015, Cappuccino Project.
|
||||
*
|
||||
* 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 <Foundation/Foundation.j>
|
||||
@import "CPView.j"
|
||||
|
||||
@typedef CPTrackingAreaOptions
|
||||
CPTrackingMouseEnteredAndExited = 1 << 1,
|
||||
CPTrackingMouseMoved = 1 << 2,
|
||||
CPTrackingCursorUpdate = 1 << 3,
|
||||
CPTrackingActiveWhenFirstResponder = 1 << 4,
|
||||
CPTrackingActiveInKeyWindow = 1 << 5,
|
||||
CPTrackingActiveInActiveApp = 1 << 6, // both mean the same in cappuccino context
|
||||
CPTrackingActiveAlways = 1 << 6,
|
||||
CPTrackingAssumeInside = 1 << 7,
|
||||
CPTrackingInVisibleRect = 1 << 8,
|
||||
CPTrackingEnabledDuringMouseDrag = 1 << 9;
|
||||
|
||||
/*!
|
||||
@ingroup appkit
|
||||
|
||||
A CPTrackingArea defines a region of view that generates mouse-tracking and
|
||||
cursor-update events when the mouse is over that region.
|
||||
*/
|
||||
@implementation CPTrackingArea : CPObject
|
||||
{
|
||||
CGRect _rect @accessors(property=rect, readonly);
|
||||
CPTrackingAreaOptions _options @accessors(property=options, readonly);
|
||||
id _owner @accessors(property=owner, readonly);
|
||||
CPDictionary _userInfo @accessors(property=userInfo, readonly);
|
||||
|
||||
CPView _referencingView;
|
||||
}
|
||||
|
||||
|
||||
#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.
|
||||
*/
|
||||
- (CPTrackingArea)initWithRect:(CGRect)aRect options:(CPTrackingAreaOptions)options owner:(id)owner userInfo:(CPDictionary)userInfo
|
||||
{
|
||||
if (self = [super init])
|
||||
{
|
||||
if (!(options > 0))
|
||||
[CPException raise:CPInternalInconsistencyException reason:"Invalid CPTrackingArea options"];
|
||||
|
||||
// Temporary, waiting for cursor rect management
|
||||
if (options & CPTrackingCursorUpdate)
|
||||
[CPException raise:CPInternalInconsistencyException reason:"CPTrackingCursorUpdate not yet implemented"];
|
||||
|
||||
// Check options:
|
||||
// - at least one in CPTrackingMouseEnteredAndExited, CPTrackingMouseMoved, CPTrackingCursorUpdate
|
||||
// - exactly one in CPTrackingActiveWhenFirstResponder, CPTrackingActiveInKeyWindow, CPTrackingActiveAlways
|
||||
// - no check on CPTrackingAssumeInside, CPTrackingInVisibleRect, CPTrackingEnableDuringMouseDrag
|
||||
|
||||
if (!((options & CPTrackingMouseEnteredAndExited) || (options & CPTrackingMouseMoved) || (options & CPTrackingCursorUpdate)))
|
||||
[CPException raise:CPInternalInconsistencyException reason:"You must at least select a type of event message"];
|
||||
|
||||
if ((((options & CPTrackingActiveWhenFirstResponder) > 0) + ((options & CPTrackingActiveInKeyWindow) > 0) + ((options & CPTrackingActiveAlways) > 0)) != 1)
|
||||
[CPException raise:CPInternalInconsistencyException reason:"You must select one and only one scope of tracking"];
|
||||
|
||||
_rect = aRect;
|
||||
_options = options;
|
||||
_owner = owner;
|
||||
_userInfo = userInfo;
|
||||
|
||||
_referencingView = nil;
|
||||
}
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
|
||||
#pragma mark -
|
||||
#pragma mark Implementation
|
||||
|
||||
- (void)_setReferencingView:(CPView)aView
|
||||
{
|
||||
_referencingView = aView;
|
||||
}
|
||||
|
||||
- (CPView)_referencingView
|
||||
{
|
||||
return _referencingView;
|
||||
}
|
||||
|
||||
- (BOOL)_isReferenced
|
||||
{
|
||||
return (!!_referencingView);
|
||||
}
|
||||
|
||||
#pragma mark -
|
||||
#pragma mark CPCoding
|
||||
|
||||
- (id)initWithCoder:(CPCoder)aCoder
|
||||
{
|
||||
if (self = [super init])
|
||||
{
|
||||
_rect = [aCoder decodeObjectForKey:@"_rect"];
|
||||
_options = [aCoder decodeObjectForKey:@"_options"];
|
||||
_owner = [aCoder decodeObjectForKey:@"_owner"];
|
||||
_userInfo = [aCoder decodeObjectForKey:@"_userInfo"];
|
||||
_referencingView = [aCoder decodeObjectForKey:@"_referencingView"];
|
||||
}
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)encodeWithCoder:(CPCoder)aCoder
|
||||
{
|
||||
[aCoder encodeObject:_rect forKey:@"_rect"];
|
||||
[aCoder encodeObject:_options forKey:@"_options"];
|
||||
[aCoder encodeObject:_owner forKey:@"_owner"];
|
||||
[aCoder encodeObject:_userInfo forKey:@"_userInfo"];
|
||||
[aCoder encodeObject:_referencingView forKey:@"_referencingView"];
|
||||
}
|
||||
|
||||
@end
|
||||
@@ -32,6 +32,7 @@
|
||||
@import "CPGraphicsContext.j"
|
||||
@import "CPResponder.j"
|
||||
@import "CPTheme.j"
|
||||
@import "CPTrackingArea.j"
|
||||
@import "CPWindow_Constants.j"
|
||||
@import "_CPDisplayServer.j"
|
||||
|
||||
@@ -239,6 +240,8 @@ var CPViewHighDPIDrawingEnabled = YES;
|
||||
BOOL _allowsVibrancy @accessors(property=allowsVibrancy);
|
||||
CPAppearance _appearance @accessors(getter=appearance);
|
||||
CPAppearance _effectiveAppearance;
|
||||
|
||||
CPMutableArray _trackingAreas @accessors(property=trackingAreas, readonly);
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -352,6 +355,8 @@ var CPViewHighDPIDrawingEnabled = YES;
|
||||
_registeredDraggedTypes = [CPSet set];
|
||||
_registeredDraggedTypesArray = [];
|
||||
|
||||
_trackingAreas = [];
|
||||
|
||||
_tag = -1;
|
||||
|
||||
_frame = CGRectMakeCopy(aFrame);
|
||||
@@ -799,8 +804,16 @@ var CPViewHighDPIDrawingEnabled = YES;
|
||||
[_window _noteUnregisteredDraggedTypes:_registeredDraggedTypes];
|
||||
[aWindow _noteRegisteredDraggedTypes:_registeredDraggedTypes];
|
||||
}
|
||||
|
||||
// View must be removed from the current window viewsWithTrackingAreas
|
||||
if (_window && ([_trackingAreas count] > 0))
|
||||
[_window _removeFromViewsWithTrackingAreas:self];
|
||||
|
||||
_window = aWindow;
|
||||
|
||||
// View must be added to the new window viewsWithTrackingAreas
|
||||
if (_window && ([_trackingAreas count] > 0))
|
||||
[_window _addToViewsWithTrackingAreas:self];
|
||||
|
||||
var count = [_subviews count];
|
||||
|
||||
@@ -3390,6 +3403,60 @@ setBoundsOrigin:
|
||||
}
|
||||
|
||||
|
||||
@end
|
||||
|
||||
@implementation CPView (TrackingArea)
|
||||
|
||||
- (void)addTrackingArea:(CPTrackingArea)trackingArea
|
||||
{
|
||||
CPLog.trace("addTrackingArea for view:"+self);
|
||||
// Consistency check
|
||||
if (!trackingArea || [_trackingAreas containsObject:trackingArea])
|
||||
return;
|
||||
|
||||
if ([trackingArea _isReferenced])
|
||||
[CPException raise:CPInternalInconsistencyException reason:"TrackingArea is already associated with another view"];
|
||||
|
||||
CPLog.trace("addTrackingArea here we go. FYI, _window="+_window);
|
||||
[_trackingAreas addObject:trackingArea];
|
||||
[trackingArea _setReferencingView:self];
|
||||
|
||||
CPLog.trace("addTrackingArea count="+[_trackingAreas count]);
|
||||
|
||||
if (_window)
|
||||
if ([_trackingAreas count] == 1)
|
||||
[_window _addToViewsWithTrackingAreas:self];
|
||||
else
|
||||
[_window _addTrackingArea:trackingArea];
|
||||
}
|
||||
|
||||
- (void)removeTrackingArea:(CPTrackingArea)trackingArea
|
||||
{
|
||||
// Consistency check
|
||||
if (!trackingArea)
|
||||
return;
|
||||
|
||||
if (![_trackingAreas containsObject:trackingArea])
|
||||
[CPException raise:CPInternalInconsistencyException reason:"Trying to remove unreferenced trackingArea"];
|
||||
|
||||
if (_window)
|
||||
if ([_trackingAreas count] == 1)
|
||||
[_window _removeFromViewsWithTrackingAreas:self];
|
||||
else
|
||||
[_window _removeTrackingArea:trackingArea];
|
||||
|
||||
[trackingArea _setReferencingView:nil];
|
||||
[_trackingAreas removeObject:trackingArea];
|
||||
}
|
||||
|
||||
// Invoked automatically when the view’s geometry changes such that its tracking areas need to be recalculated.
|
||||
|
||||
- (void)updateTrackingAreas
|
||||
{
|
||||
// You should override this method to remove out of date tracking areas and add recomputed tracking areas;
|
||||
// your implementation should call super.
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
var CPViewAutoresizingMaskKey = @"CPViewAutoresizingMask",
|
||||
@@ -3412,6 +3479,7 @@ var CPViewAutoresizingMaskKey = @"CPViewAutoresizingMask",
|
||||
CPViewSizeScaleKey = @"CPViewSizeScaleKey",
|
||||
CPViewIsScaledKey = @"CPViewIsScaledKey",
|
||||
CPViewAppearanceKey = @"CPViewAppearanceKey";
|
||||
CPViewTrackingAreasKey = @"CPViewTrackingAreasKey";
|
||||
|
||||
@implementation CPView (CPCoding)
|
||||
|
||||
@@ -3511,6 +3579,10 @@ var CPViewAutoresizingMaskKey = @"CPViewAutoresizingMask",
|
||||
[self _decodeThemeObjectsWithCoder:aCoder];
|
||||
|
||||
[self setAppearance:[aCoder decodeObjectForKey:CPViewAppearanceKey]];
|
||||
|
||||
_trackingAreas = [aCoder decodeObjectForKey:CPViewTrackingAreasKey];
|
||||
if (!_trackingAreas)
|
||||
_trackingAreas = [];
|
||||
|
||||
[self setNeedsDisplay:YES];
|
||||
[self setNeedsLayout];
|
||||
@@ -3596,6 +3668,7 @@ var CPViewAutoresizingMaskKey = @"CPViewAutoresizingMask",
|
||||
[aCoder encodeSize:[self _hierarchyScaleSize] forKey:CPViewSizeScaleKey];
|
||||
[aCoder encodeBool:_isScaled forKey:CPViewIsScaledKey];
|
||||
[aCoder encodeObject:_appearance forKey:CPViewAppearanceKey];
|
||||
[aCoder encodeObject:_trackingAreas forKey:CPViewTrackingAreasKey];
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
+172
-45
@@ -36,6 +36,7 @@
|
||||
@import "CPResponder.j"
|
||||
@import "CPScreen.j"
|
||||
@import "CPText.j"
|
||||
@import "CPTrackingArea.j"
|
||||
@import "CPView.j"
|
||||
@import "CPWindow_Constants.j"
|
||||
@import "_CPBorderlessBridgeWindowView.j"
|
||||
@@ -198,6 +199,8 @@ var CPWindowActionMessageKeys = [
|
||||
CPView _toolbarView;
|
||||
|
||||
CPArray _mouseEnteredStack;
|
||||
CPArray mouseEnteredStack;
|
||||
CPArray _viewsWithTrackingAreas;
|
||||
CPView _leftMouseDownView;
|
||||
CPView _rightMouseDownView;
|
||||
|
||||
@@ -386,6 +389,9 @@ CPTexturedBackgroundWindowMask
|
||||
selector:@selector(_didReceiveResizeStyleChange:)
|
||||
name:CPWindowResizeStyleGlobalChangeNotification
|
||||
object:nil];
|
||||
|
||||
_viewsWithTrackingAreas = [];
|
||||
_mouseEnteredStack = [];
|
||||
}
|
||||
|
||||
return self;
|
||||
@@ -1958,6 +1964,74 @@ CPTexturedBackgroundWindowMask
|
||||
|
||||
case CPLeftMouseDragged:
|
||||
case CPRightMouseDragged:
|
||||
// First, we search for any tracking area requesting CPTrackingEnabledDuringMouseDrag.
|
||||
// At the same time, we update the entered stack.
|
||||
mouseEnteredStack = [];
|
||||
|
||||
for (var i = 0, nb = [_viewsWithTrackingAreas count], aView, trackingAreas, convertedPoint, event, trackingOptions; i < nb; i++)
|
||||
{
|
||||
aView = [_viewsWithTrackingAreas objectAtIndex:i];
|
||||
trackingAreas = [aView trackingAreas];
|
||||
convertedPoint = [aView convertPoint:point fromView:_windowView];
|
||||
|
||||
for (var j = 0, nbTA = [trackingAreas count], aTrackingArea; j < nbTA; j++)
|
||||
{
|
||||
aTrackingArea = [trackingAreas objectAtIndex:j];
|
||||
trackingOptions = [aTrackingArea options];
|
||||
|
||||
if (trackingOptions & CPTrackingEnabledDuringMouseDrag)
|
||||
{
|
||||
if ((trackingOptions & CPTrackingActiveAlways) ||
|
||||
((trackingOptions & CPTrackingActiveInKeyWindow) && ([self isKeyWindow])) ||
|
||||
((trackingOptions & CPTrackingActiveWhenFirstResponder) && ([self isKeyWindow]) && (_firstResponder == aView)))
|
||||
{
|
||||
if (CGRectContainsPoint(((trackingOptions & CPTrackingInVisibleRect) ? [aView visibleRect] : [aTrackingArea rect]), convertedPoint))
|
||||
{
|
||||
[mouseEnteredStack addObject:aTrackingArea];
|
||||
|
||||
if (![_mouseEnteredStack containsObject:aTrackingArea])
|
||||
{
|
||||
// Mouse was not in this rect so it's a mouseEntered
|
||||
|
||||
if (trackingOptions & CPTrackingMouseEnteredAndExited)
|
||||
{
|
||||
event = [CPEvent enterExitEventWithType:CPMouseEntered location:point modifierFlags:[anEvent modifierFlags] timestamp:[anEvent timestamp] windowNumber:_windowNumber context:nil eventNumber:-1 trackingArea:aTrackingArea];
|
||||
|
||||
[[aTrackingArea owner] mouseEntered:event];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Search now for exited views (were in _mouseEnteredStack but no more in mouseEnteredStack)
|
||||
|
||||
for (var i = 0, nb = [_mouseEnteredStack count], aTrackingArea, trackingOptions; i < nb; i++)
|
||||
{
|
||||
aTrackingArea = [_mouseEnteredStack objectAtIndex:i];
|
||||
trackingOptions = [aTrackingArea options];
|
||||
|
||||
if (trackingOptions & CPTrackingEnabledDuringMouseDrag)
|
||||
{
|
||||
if (![mouseEnteredStack containsObject:aTrackingArea])
|
||||
{
|
||||
// Mouse is no more in this area so it's a mouseExited
|
||||
|
||||
if (trackingOptions & CPTrackingMouseEnteredAndExited)
|
||||
{
|
||||
event = [CPEvent enterExitEventWithType:CPMouseExited location:point modifierFlags:[anEvent modifierFlags] timestamp:[anEvent timestamp] windowNumber:_windowNumber context:nil eventNumber:-1 trackingArea:aTrackingArea];
|
||||
|
||||
[[aTrackingArea owner] mouseExited:event];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
_mouseEnteredStack = mouseEnteredStack;
|
||||
|
||||
// Normal mouseDragged workflow
|
||||
if (!_leftMouseDownView)
|
||||
return [[_windowView hitTest:point] mouseDragged:anEvent];
|
||||
|
||||
@@ -1981,56 +2055,73 @@ CPTexturedBackgroundWindowMask
|
||||
// Ignore mouse moves for parents of sheets
|
||||
if (!_acceptsMouseMovedEvents || sheet)
|
||||
return;
|
||||
|
||||
if (!_mouseEnteredStack)
|
||||
_mouseEnteredStack = [];
|
||||
|
||||
var hitTestView = [_windowView hitTest:point];
|
||||
|
||||
if ([_mouseEnteredStack count] && [_mouseEnteredStack lastObject] === hitTestView)
|
||||
return [hitTestView mouseMoved:anEvent];
|
||||
|
||||
var view = hitTestView,
|
||||
mouseEnteredStack = [];
|
||||
|
||||
while (view)
|
||||
|
||||
mouseEnteredStack = [];
|
||||
|
||||
for (var i = 0, nb = [_viewsWithTrackingAreas count], aView, trackingAreas, convertedPoint, event, trackingOptions; i < nb; i++)
|
||||
{
|
||||
mouseEnteredStack.unshift(view);
|
||||
|
||||
view = [view superview];
|
||||
aView = [_viewsWithTrackingAreas objectAtIndex:i];
|
||||
trackingAreas = [aView trackingAreas];
|
||||
convertedPoint = [aView convertPoint:point fromView:_windowView];
|
||||
|
||||
for (var j = 0, nbTA = [trackingAreas count], aTrackingArea; j < nbTA; j++)
|
||||
{
|
||||
aTrackingArea = [trackingAreas objectAtIndex:j];
|
||||
trackingOptions = [aTrackingArea options];
|
||||
|
||||
if ((trackingOptions & CPTrackingActiveAlways) ||
|
||||
((trackingOptions & CPTrackingActiveInKeyWindow) && ([self isKeyWindow])) ||
|
||||
((trackingOptions & CPTrackingActiveWhenFirstResponder) && ([self isKeyWindow]) && (_firstResponder == aView)))
|
||||
{
|
||||
if (CGRectContainsPoint(((trackingOptions & CPTrackingInVisibleRect) ? [aView visibleRect] : [aTrackingArea rect]), convertedPoint))
|
||||
{
|
||||
[mouseEnteredStack addObject:aTrackingArea];
|
||||
|
||||
if ([_mouseEnteredStack containsObject:aTrackingArea])
|
||||
{
|
||||
// Mouse was already in this rect so it's a mouseMoved
|
||||
|
||||
if (trackingOptions & CPTrackingMouseMoved)
|
||||
[[aTrackingArea owner] mouseMoved:anEvent];
|
||||
}
|
||||
else
|
||||
{
|
||||
// Mouse was not in this rect so it's a mouseEntered
|
||||
|
||||
if (trackingOptions & CPTrackingMouseEnteredAndExited)
|
||||
{
|
||||
event = [CPEvent enterExitEventWithType:CPMouseEntered location:point modifierFlags:[anEvent modifierFlags] timestamp:[anEvent timestamp] windowNumber:_windowNumber context:nil eventNumber:-1 trackingArea:aTrackingArea];
|
||||
|
||||
[[aTrackingArea owner] mouseEntered:event];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var deviation = MIN(_mouseEnteredStack.length, mouseEnteredStack.length);
|
||||
|
||||
while (deviation--)
|
||||
if (_mouseEnteredStack[deviation] === mouseEnteredStack[deviation])
|
||||
break;
|
||||
|
||||
var index = deviation + 1,
|
||||
count = _mouseEnteredStack.length;
|
||||
|
||||
if (index < count)
|
||||
|
||||
// Search now for exited views (were in _mouseEnteredStack but no more in mouseEnteredStack)
|
||||
|
||||
for (var i = 0, nb = [_mouseEnteredStack count], aTrackingArea; i < nb; i++)
|
||||
{
|
||||
var event = [CPEvent mouseEventWithType:CPMouseExited location:point modifierFlags:[anEvent modifierFlags] timestamp:[anEvent timestamp] windowNumber:_windowNumber context:nil eventNumber:-1 clickCount:1 pressure:0];
|
||||
|
||||
for (; index < count; ++index)
|
||||
[_mouseEnteredStack[index] mouseExited:event];
|
||||
aTrackingArea = [_mouseEnteredStack objectAtIndex:i];
|
||||
|
||||
if (![mouseEnteredStack containsObject:aTrackingArea])
|
||||
{
|
||||
// Mouse is no more in this area so it's a mouseExited
|
||||
|
||||
if ([aTrackingArea options] & CPTrackingMouseEnteredAndExited)
|
||||
{
|
||||
event = [CPEvent enterExitEventWithType:CPMouseExited location:point modifierFlags:[anEvent modifierFlags] timestamp:[anEvent timestamp] windowNumber:_windowNumber context:nil eventNumber:-1 trackingArea:aTrackingArea];
|
||||
|
||||
[[aTrackingArea owner] mouseExited:event];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
index = deviation + 1;
|
||||
count = mouseEnteredStack.length;
|
||||
|
||||
if (index < count)
|
||||
{
|
||||
var event = [CPEvent mouseEventWithType:CPMouseEntered location:point modifierFlags:[anEvent modifierFlags] timestamp:[anEvent timestamp] windowNumber:_windowNumber context:nil eventNumber:-1 clickCount:1 pressure:0];
|
||||
|
||||
for (; index < count; ++index)
|
||||
[mouseEnteredStack[index] mouseEntered:event];
|
||||
}
|
||||
|
||||
|
||||
// End of treatment
|
||||
|
||||
_mouseEnteredStack = mouseEnteredStack;
|
||||
|
||||
[hitTestView mouseMoved:anEvent];
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3844,6 +3935,42 @@ var interpolate = function(fromValue, toValue, progress)
|
||||
|
||||
@end
|
||||
|
||||
@implementation CPWindow (TrackingArea)
|
||||
|
||||
- (void)_addToViewsWithTrackingAreas:(CPView)aView
|
||||
{
|
||||
[_viewsWithTrackingAreas addObject:aView];
|
||||
|
||||
for (var i = 0, tas = [aView trackingAreas], nb = [tas count]; i < nb; i++)
|
||||
[self _addTrackingArea:[tas objectAtIndex:i]];
|
||||
}
|
||||
|
||||
- (void)_removeFromViewsWithTrackingAreas:(CPView)aView
|
||||
{
|
||||
for (var i = 0, tas = [aView trackingAreas], nb = [tas count]; i < nb; i++)
|
||||
[self _removeTrackingArea:[tas objectAtIndex:i]];
|
||||
|
||||
[_viewsWithTrackingAreas removeObject:aView];
|
||||
}
|
||||
|
||||
- (void)_addTrackingArea:(CPTrackingArea)trackingArea
|
||||
{
|
||||
// If CPTrackingAssumeInside option is set, put the tracking area in the mouseEnteredStack
|
||||
|
||||
if ([trackingArea options] & CPTrackingAssumeInside)
|
||||
[_mouseEnteredStack addObject:trackingArea];
|
||||
}
|
||||
|
||||
- (void)_removeTrackingArea:(CPTrackingArea)trackingArea
|
||||
{
|
||||
// If mouse is in the tracking area, we remove it from the stack to avoid to fire a future mouseExited event
|
||||
|
||||
if ([_mouseEnteredStack containsObject:trackingArea])
|
||||
[_mouseEnteredStack removeObject:trackingArea];
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
function _CPWindowFullPlatformWindowSessionMake(aWindowView, aContentRect, hasShadow, aLevel)
|
||||
{
|
||||
return { windowView:aWindowView, contentRect:aContentRect, hasShadow:hasShadow, level:aLevel };
|
||||
|
||||
Reference in New Issue
Block a user