2016-03-05 19:45:09 +00:00
|
|
|
//
|
2020-08-04 22:22:14 +00:00
|
|
|
// CSScanTargetView.h
|
2016-03-05 19:45:09 +00:00
|
|
|
// Clock Signal
|
|
|
|
//
|
|
|
|
// Created by Thomas Harte on 16/07/2015.
|
2018-05-13 19:19:52 +00:00
|
|
|
// Copyright 2015 Thomas Harte. All rights reserved.
|
2016-03-05 19:45:09 +00:00
|
|
|
//
|
|
|
|
|
|
|
|
#import <Foundation/Foundation.h>
|
|
|
|
#import <AppKit/AppKit.h>
|
2020-08-04 22:22:14 +00:00
|
|
|
#import <MetalKit/MetalKit.h>
|
2016-03-05 19:45:09 +00:00
|
|
|
|
2020-08-04 22:22:14 +00:00
|
|
|
@class CSScanTargetView;
|
2016-03-05 19:45:09 +00:00
|
|
|
|
2020-08-04 22:22:14 +00:00
|
|
|
typedef NS_ENUM(NSInteger, CSScanTargetViewRedrawEvent) {
|
2019-03-03 00:33:28 +00:00
|
|
|
/// Indicates that AppKit requested a redraw for some reason (mostly likely, the window is being resized). So,
|
|
|
|
/// if the delegate doesn't redraw the view, the user is likely to see a graphical flaw.
|
2020-08-04 22:22:14 +00:00
|
|
|
CSScanTargetViewRedrawEventAppKit,
|
2019-03-03 00:33:28 +00:00
|
|
|
/// Indicates that the view's display-linked timer has triggered a redraw request. So, if the delegate doesn't
|
|
|
|
/// redraw the view, the user will just see the previous drawing without interruption.
|
2020-08-04 22:22:14 +00:00
|
|
|
CSScanTargetViewRedrawEventTimer
|
2019-03-03 00:33:28 +00:00
|
|
|
};
|
|
|
|
|
2020-08-04 22:22:14 +00:00
|
|
|
//@protocol CSScanTargetViewDelegate
|
|
|
|
///*!
|
|
|
|
// Requests that the delegate produce an image of its current output state. May be called on
|
|
|
|
// any queue or thread.
|
|
|
|
// @param view The view making the request.
|
|
|
|
// @param redrawEvent If @c YES then the delegate may decline to redraw if its output would be
|
|
|
|
// identical to the previous frame. If @c NO then the delegate must draw.
|
|
|
|
//*/
|
|
|
|
//- (void)openGLViewRedraw:(nonnull CSScanTargetView *)view event:(CSScanTargetViewRedrawEvent)redrawEvent;
|
|
|
|
//
|
|
|
|
//
|
|
|
|
//@end
|
2016-03-05 19:45:09 +00:00
|
|
|
|
2020-08-04 22:22:14 +00:00
|
|
|
@protocol CSScanTargetViewResponderDelegate <NSObject>
|
2016-03-13 17:38:03 +00:00
|
|
|
/*!
|
2018-05-13 15:12:03 +00:00
|
|
|
Supplies a keyDown event to the delegate.
|
2016-03-13 17:38:03 +00:00
|
|
|
@param event The @c NSEvent describing the keyDown.
|
|
|
|
*/
|
2016-03-05 19:45:09 +00:00
|
|
|
- (void)keyDown:(nonnull NSEvent *)event;
|
2016-03-13 17:38:03 +00:00
|
|
|
|
|
|
|
/*!
|
2018-05-13 15:12:03 +00:00
|
|
|
Supplies a keyUp event to the delegate.
|
2016-03-13 17:38:03 +00:00
|
|
|
@param event The @c NSEvent describing the keyUp.
|
|
|
|
*/
|
2016-03-05 19:45:09 +00:00
|
|
|
- (void)keyUp:(nonnull NSEvent *)event;
|
2016-03-13 17:38:03 +00:00
|
|
|
|
|
|
|
/*!
|
2018-05-13 15:12:03 +00:00
|
|
|
Supplies a flagsChanged event to the delegate.
|
2016-03-13 17:38:03 +00:00
|
|
|
@param event The @c NSEvent describing the flagsChanged.
|
|
|
|
*/
|
2017-07-22 01:27:50 +00:00
|
|
|
- (void)flagsChanged:(nonnull NSEvent *)event;
|
2016-03-13 17:38:03 +00:00
|
|
|
|
2018-05-13 15:12:03 +00:00
|
|
|
/*!
|
|
|
|
Supplies a paste event to the delegate.
|
|
|
|
*/
|
|
|
|
- (void)paste:(nonnull id)sender;
|
|
|
|
|
2019-06-11 20:30:53 +00:00
|
|
|
@optional
|
|
|
|
|
|
|
|
/*!
|
|
|
|
Supplies a mouse moved event to the delegate. This functions only if
|
|
|
|
shouldCaptureMouse is set to YES, in which case the view will ensure it captures
|
|
|
|
the mouse and returns only relative motion
|
|
|
|
(Cf. CGAssociateMouseAndMouseCursorPosition). It will also elide mouseDragged:
|
|
|
|
(and rightMouseDragged:, etc) and mouseMoved: events.
|
|
|
|
*/
|
|
|
|
- (void)mouseMoved:(nonnull NSEvent *)event;
|
|
|
|
|
|
|
|
/*!
|
|
|
|
Supplies a mouse button down event. This elides mouseDown, rightMouseDown and otherMouseDown.
|
|
|
|
@c shouldCaptureMouse must be set to @c YES to receive these events.
|
|
|
|
*/
|
|
|
|
- (void)mouseDown:(nonnull NSEvent *)event;
|
|
|
|
|
|
|
|
/*!
|
|
|
|
Supplies a mouse button up event. This elides mouseUp, rightMouseUp and otherMouseUp.
|
|
|
|
@c shouldCaptureMouse must be set to @c YES to receive these events.
|
|
|
|
*/
|
|
|
|
- (void)mouseUp:(nonnull NSEvent *)event;
|
|
|
|
|
2020-08-04 22:22:14 +00:00
|
|
|
/*!
|
|
|
|
Announces 'capture' of the mouse — i.e. that the view is now preventing the mouse from exiting
|
|
|
|
the window, in order to forward continuous mouse motion.
|
|
|
|
@param view The view making the announcement.
|
|
|
|
*/
|
|
|
|
- (void)openGLViewDidCaptureMouse:(nonnull CSScanTargetView *)view;
|
|
|
|
|
|
|
|
/*!
|
|
|
|
Announces that the mouse is no longer captured.
|
|
|
|
@param view The view making the announcement.
|
|
|
|
*/
|
|
|
|
- (void)openGLViewDidReleaseMouse:(nonnull CSScanTargetView *)view;
|
|
|
|
|
|
|
|
/*!
|
|
|
|
Announces that the OS mouse cursor is now being displayed again, after having been invisible.
|
|
|
|
@param view The view making the announcement.
|
|
|
|
*/
|
|
|
|
- (void)openGLViewDidShowOSMouseCursor:(nonnull CSScanTargetView *)view;
|
|
|
|
|
|
|
|
/*!
|
|
|
|
Announces that the OS mouse cursor will now be hidden.
|
|
|
|
@param view The view making the announcement.
|
|
|
|
*/
|
|
|
|
- (void)openGLViewWillHideOSMouseCursor:(nonnull CSScanTargetView *)view;
|
|
|
|
|
|
|
|
/*!
|
|
|
|
Announces receipt of a file by drag and drop to the delegate.
|
|
|
|
@param view The view making the request.
|
|
|
|
@param URL The file URL of the received file.
|
|
|
|
*/
|
|
|
|
- (void)openGLView:(nonnull CSScanTargetView *)view didReceiveFileAtURL:(nonnull NSURL *)URL;
|
|
|
|
|
2016-03-05 19:45:09 +00:00
|
|
|
@end
|
|
|
|
|
2020-02-04 02:58:29 +00:00
|
|
|
/*!
|
2020-08-04 22:22:14 +00:00
|
|
|
Although I'm still on the fence about this as a design decision, CSScanTargetView is itself responsible
|
2020-02-04 02:58:29 +00:00
|
|
|
for creating and destroying a CVDisplayLink. There's a practical reason for this: you'll get real synchronisation
|
2020-08-04 22:22:14 +00:00
|
|
|
only if a link is explicitly tied to a particular display, and the CSScanTargetView therefore owns the knowledge
|
2020-02-04 02:58:29 +00:00
|
|
|
necessary to decide when to create and modify them. It doesn't currently just propagate "did change screen"-type
|
|
|
|
messages because I haven't yet found a way to track that other than polling, in which case I might as well put
|
|
|
|
that into the display link callback.
|
|
|
|
*/
|
2020-08-04 22:22:14 +00:00
|
|
|
@protocol CSScanTargetViewDisplayLinkDelegate
|
2020-02-04 02:58:29 +00:00
|
|
|
|
|
|
|
/*!
|
|
|
|
Informs the delegate that the display link has fired.
|
|
|
|
*/
|
2020-08-04 22:22:14 +00:00
|
|
|
- (void)openGLViewDisplayLinkDidFire:(nonnull CSScanTargetView *)view now:(nonnull const CVTimeStamp *)now outputTime:(nonnull const CVTimeStamp *)outputTime;
|
2020-02-04 02:58:29 +00:00
|
|
|
|
|
|
|
@end
|
|
|
|
|
2016-03-05 19:45:09 +00:00
|
|
|
/*!
|
2018-05-13 15:12:03 +00:00
|
|
|
Provides an OpenGL canvas with a refresh-linked update timer that can forward a subset
|
|
|
|
of typical first-responder actions.
|
2016-03-05 19:45:09 +00:00
|
|
|
*/
|
2020-08-04 22:22:14 +00:00
|
|
|
@interface CSScanTargetView : MTKView
|
2016-03-05 19:45:09 +00:00
|
|
|
|
2020-08-04 22:22:14 +00:00
|
|
|
//@property (atomic, weak, nullable) id <CSOpenGLViewDelegate> delegate;
|
|
|
|
@property (nonatomic, weak, nullable) id <CSScanTargetViewResponderDelegate> responderDelegate;
|
|
|
|
@property (atomic, weak, nullable) id <CSScanTargetViewDisplayLinkDelegate> displayLinkDelegate;
|
2016-03-05 19:45:09 +00:00
|
|
|
|
2019-09-22 17:15:35 +00:00
|
|
|
/// Determines whether the view offers mouse capturing — i.e. if the user clicks on the view then
|
2020-08-04 22:22:14 +00:00
|
|
|
/// then the system cursor is disabled and the mouse events defined by CSScanTargetViewResponderDelegate
|
2019-09-22 17:15:35 +00:00
|
|
|
/// are forwarded, unless and until the user releases the mouse using the control+command shortcut.
|
2019-06-11 20:30:53 +00:00
|
|
|
@property (nonatomic, assign) BOOL shouldCaptureMouse;
|
|
|
|
|
2020-08-04 22:22:14 +00:00
|
|
|
/// Determines whether the CSScanTargetViewResponderDelegate of this window expects to use the command
|
2019-09-22 17:15:35 +00:00
|
|
|
/// key as though it were any other key — i.e. all command combinations should be forwarded to the delegate,
|
|
|
|
/// not being allowed to trigger regular application shortcuts such as command+q or command+h.
|
|
|
|
///
|
|
|
|
/// How the view respects this will depend on other state; if this view is one that captures the mouse then it
|
|
|
|
/// will usurp command only while the mouse is captured.
|
|
|
|
///
|
|
|
|
/// TODO: what's smart behaviour if this view doesn't capture the mouse? Probably
|
|
|
|
/// force a similar capturing behaviour?
|
|
|
|
@property (nonatomic, assign) BOOL shouldUsurpCommand;
|
|
|
|
|
2016-03-13 17:38:03 +00:00
|
|
|
/*!
|
|
|
|
Ends the timer tracking time; should be called prior to giving up the last owning reference
|
|
|
|
to ensure that any retain cycles implied by the timer are resolved.
|
|
|
|
*/
|
2016-03-05 19:45:09 +00:00
|
|
|
- (void)invalidate;
|
|
|
|
|
2016-03-13 17:38:03 +00:00
|
|
|
/// The size in pixels of the OpenGL canvas, factoring in screen pixel density and view size in points.
|
2016-03-05 19:45:09 +00:00
|
|
|
@property (nonatomic, readonly) CGSize backingSize;
|
|
|
|
|
2018-05-13 15:12:03 +00:00
|
|
|
/*!
|
|
|
|
Locks this view's OpenGL context and makes it current, performs @c action and then unlocks
|
|
|
|
the context. @c action is performed on the calling queue.
|
|
|
|
*/
|
2020-02-04 02:58:29 +00:00
|
|
|
- (void)performWithGLContext:(nonnull dispatch_block_t)action flushDrawable:(BOOL)flushDrawable;
|
2016-03-20 02:46:17 +00:00
|
|
|
- (void)performWithGLContext:(nonnull dispatch_block_t)action;
|
|
|
|
|
2019-06-11 20:30:53 +00:00
|
|
|
/*!
|
|
|
|
Instructs that the mouse cursor, if currently captured, should be released.
|
|
|
|
*/
|
|
|
|
- (void)releaseMouse;
|
|
|
|
|
2016-03-05 19:45:09 +00:00
|
|
|
@end
|