1
0
mirror of https://github.com/TomHarte/CLK.git synced 2025-04-21 18:37:11 +00:00

Require mouseover near the volume/controls to activate.

This commit is contained in:
Thomas Harte 2025-02-21 11:28:53 -05:00
parent e19dc1f067
commit f8c9aa8e6c
3 changed files with 83 additions and 16 deletions

View File

@ -111,6 +111,7 @@ class MachineDocument:
volumeSlider.floatValue = pow(2.0, userDefaultsVolume())
volumeView.layer!.cornerRadius = 5.0
scanTargetView.responderDelegate = self
}
private var missingROMs: String = ""
@ -227,7 +228,6 @@ class MachineDocument:
setupActivityDisplay()
machine.delegate = self
scanTargetView.responderDelegate = self
// If this machine has a mouse, enable mouse capture; also indicate whether usurption
// of the command key is desired.
@ -782,6 +782,10 @@ class MachineDocument:
private var optionsFader: ViewFader! = nil
internal func scanTargetView(_ view: CSScanTargetView, shouldTrackMousovers subview: NSView) -> Bool {
return subview == self.volumeView || subview == self.optionsView
}
internal func scanTargetViewDidShowOSMouseCursor(_ view: CSScanTargetView) {
// The OS mouse cursor became visible, so show the volume controls.
optionsFader.animateIn()

View File

@ -94,6 +94,13 @@
*/
- (void)scanTargetView:(nonnull CSScanTargetView *)view didReceiveFileAtURL:(nonnull NSURL *)URL;
/*!
Asks the receiver whether @c view should be included in the set of subviews that generate
@c scanTargetViewDidShowOSMouseCursor and subsequent actions.
*/
- (BOOL)scanTargetView:(nonnull CSScanTargetView *)view shouldTrackMousovers:(nonnull NSView *)view;
@end
/*!

View File

@ -24,7 +24,8 @@ static const NSTimeInterval quickMouseHideInterval = 0.1;
CVDisplayLinkRef _displayLink;
NSNumber *_currentScreenNumber;
NSTrackingArea *_mouseTrackingArea;
NSTrackingArea *_windowTrackingArea;
NSTrackingArea *_subviewTrackingArea;
NSTimer *_mouseHideTimer;
BOOL _mouseIsCaptured;
@ -222,21 +223,67 @@ static CVReturn DisplayLinkCallback(__unused CVDisplayLinkRef displayLink, const
- (void)setShouldCaptureMouse:(BOOL)shouldCaptureMouse {
_shouldCaptureMouse = shouldCaptureMouse;
if(_windowTrackingArea) {
[self removeTrackingArea:_windowTrackingArea];
}
_windowTrackingArea =
[[NSTrackingArea alloc]
initWithRect:self.bounds
options:NSTrackingMouseEnteredAndExited | NSTrackingMouseMoved | NSTrackingActiveWhenFirstResponder
owner:self
userInfo:nil];
[self addTrackingArea:_windowTrackingArea];
}
- (void)recalculateSubviewTrackingAreas {
if(_subviewTrackingArea) {
[self removeTrackingArea:_subviewTrackingArea];
}
// Use the union of rects of interesting subviews as the tracking area.
const NSRect emptySentinel = NSMakeRect(-1, -1, -1, -1);
NSRect trackingRect = emptySentinel;
for(NSView *const subview in self.subviews) {
if(
[self.responderDelegate respondsToSelector:@selector(scanTargetView:shouldTrackMousovers:)] &&
![self.responderDelegate scanTargetView:self shouldTrackMousovers:subview]
) {
continue;
}
if(NSEqualRects(trackingRect, emptySentinel)) {
trackingRect = subview.frame;
} else {
trackingRect = NSUnionRect(subview.frame, trackingRect);
}
}
if(NSEqualRects(trackingRect, emptySentinel)) {
return;
}
_subviewTrackingArea =
[[NSTrackingArea alloc]
initWithRect:trackingRect
options:NSTrackingMouseEnteredAndExited | NSTrackingMouseMoved | NSTrackingActiveWhenFirstResponder
owner:self
userInfo:nil];
[self addTrackingArea:_subviewTrackingArea];
}
- (void)updateTrackingAreas {
[super updateTrackingAreas];
[self recalculateSubviewTrackingAreas];
}
if(_mouseTrackingArea) {
[self removeTrackingArea:_mouseTrackingArea];
}
_mouseTrackingArea =
[[NSTrackingArea alloc]
initWithRect:self.bounds
options:NSTrackingMouseEnteredAndExited | NSTrackingMouseMoved | NSTrackingActiveWhenFirstResponder
owner:self
userInfo:nil];
[self addTrackingArea:_mouseTrackingArea];
- (void)didAddSubview:(NSView *)subview {
[self recalculateSubviewTrackingAreas];
}
- (void)layout {
[super layout];
[self recalculateSubviewTrackingAreas];
}
- (void)scheduleMouseHideAfter:(NSTimeInterval)interval {
@ -255,8 +302,12 @@ static CVReturn DisplayLinkCallback(__unused CVDisplayLinkRef displayLink, const
- (void)mouseEntered:(NSEvent *)event {
[super mouseEntered:event];
[self.responderDelegate scanTargetViewDidShowOSMouseCursor:self];
[self scheduleMouseHideAfter:standardMouseHideInterval];
if(event.trackingArea == _windowTrackingArea) {
[self scheduleMouseHideAfter:standardMouseHideInterval];
}
if(event.trackingArea == _subviewTrackingArea && !_mouseIsCaptured) {
[self.responderDelegate scanTargetViewDidShowOSMouseCursor:self];
}
}
- (void)mouseExited:(NSEvent *)event {
@ -272,7 +323,6 @@ static CVReturn DisplayLinkCallback(__unused CVDisplayLinkRef displayLink, const
CGAssociateMouseAndMouseCursorPosition(true);
[NSCursor unhide];
[self.responderDelegate scanTargetViewDidReleaseMouse:self];
[self.responderDelegate scanTargetViewDidShowOSMouseCursor:self];
((CSApplication *)[NSApplication sharedApplication]).eventDelegate = nil;
}
}
@ -284,7 +334,13 @@ static CVReturn DisplayLinkCallback(__unused CVDisplayLinkRef displayLink, const
// Mouse capture is off, so don't play games with the cursor, just schedule it to
// hide in the near future.
[self scheduleMouseHideAfter:standardMouseHideInterval];
[self.responderDelegate scanTargetViewDidShowOSMouseCursor:self];
if(
_subviewTrackingArea &&
NSPointInRect([self convertPoint:event.locationInWindow fromView:nil], _subviewTrackingArea.rect)
) {
[self.responderDelegate scanTargetViewDidShowOSMouseCursor:self];
}
} else {
// Mouse capture is on, so move the cursor back to the middle of the window, and
// forward the deltas to the listener.