Vuo  2.3.2
VuoGraphicsView.m
Go to the documentation of this file.
1 
10 #import "VuoGraphicsView.h"
11 
12 #import "module.h"
13 #import "VuoGraphicsLayer.h"
14 
15 #ifdef VUO_COMPILER
17  "title" : "VuoGraphicsView",
18  "dependencies" : [
19  "VuoGraphicsLayer",
20  ]
21 });
22 #endif
23 
27 @interface VuoGraphicsView ()
28 @property(retain) NSImage *circleImage;
29 @property NSRect circleRect;
30 
31 @property NSMutableSet *touchTriggers;
32 @property NSMutableSet *zoomedTriggers;
33 @property NSMutableSet *swipedLeftTriggers;
34 @property NSMutableSet *swipedRightTriggers;
35 @end
36 
37 @implementation VuoGraphicsView
38 
44 - (instancetype)init
45 {
46  if (self = [super init])
47  {
48  self.wantsLayer = true;
49 
50 #pragma clang diagnostic push
51 #pragma clang diagnostic ignored "-Wdeprecated-declarations"
52  // Replaced by acceptsTouchEvents, which isn't available in OS X 10.11.
53  self.acceptsTouchEvents = YES;
54 #pragma clang diagnostic pop
55 
56  self.wantsRestingTouches = YES;
57  _touchTriggers = [NSMutableSet new];
58  _zoomedTriggers = [NSMutableSet new];
59  _swipedLeftTriggers = [NSMutableSet new];
60  _swipedRightTriggers = [NSMutableSet new];
61 
62  // Prepare the circle mouse cursor.
63  {
64  _circleRect = NSMakeRect(0,0,48,48);
65  _circleImage = [[NSImage alloc] initWithSize:_circleRect.size];
66  [_circleImage lockFocus];
67  {
68  [[NSColor colorWithDeviceWhite:1 alpha:0.75] setFill];
69  [[NSColor colorWithDeviceWhite:0 alpha:0.15] setStroke];
70  NSBezierPath *circlePath = [NSBezierPath bezierPathWithOvalInRect:NSInsetRect(_circleRect, 1, 1)];
71  [circlePath fill];
72  [circlePath stroke];
73  }
74  [_circleImage unlockFocus];
75  }
76  }
77  return self;
78 }
79 
86 - (void)viewDidMoveToWindow
87 {
88  if (!self.window)
89  return;
90 
91  _viewport = self.frame;
92 }
93 
100 - (void)viewDidChangeBackingProperties
101 {
102  VuoGraphicsLayer *l = (VuoGraphicsLayer *)self.layer;
104  [l setNeedsDisplay];
105 }
106 
111 - (void)resetCursorRects
112 {
113  VuoGraphicsWindow *gw = (VuoGraphicsWindow *)self.window;
114  VuoCursor cursor = gw.cursor;
115  NSCursor *nsCursor = nil;
116 
117  if (cursor == VuoCursor_None)
118  {
119  NSImage *im = [[NSImage alloc] initWithSize:NSMakeSize(1,1)];
120  nsCursor = [[[NSCursor alloc] initWithImage:im hotSpot:NSMakePoint(0,0)] autorelease];
121  [im release];
122  }
123  else if (cursor == VuoCursor_Pointer)
124  nsCursor = [NSCursor arrowCursor];
125  else if (cursor == VuoCursor_Crosshair)
126  nsCursor = [NSCursor crosshairCursor];
127  else if (cursor == VuoCursor_HandOpen)
128  nsCursor = [NSCursor openHandCursor];
129  else if (cursor == VuoCursor_HandClosed)
130  nsCursor = [NSCursor closedHandCursor];
131  else if (cursor == VuoCursor_IBeam)
132  nsCursor = [NSCursor IBeamCursor];
133  else if (cursor == VuoCursor_Circle)
134  nsCursor = [[[NSCursor alloc] initWithImage:_circleImage hotSpot:NSMakePoint(NSMidX(_circleRect),NSMidY(_circleRect))] autorelease];
135 
136  if (nsCursor)
137  [self addCursorRect:[self visibleRect] cursor:nsCursor];
138 }
139 
146 - (BOOL)acceptsFirstResponder
147 {
148  return YES;
149 }
150 
162 - (BOOL)mouseDownCanMoveWindow
163 {
164  return NO;
165 }
166 
170 - (void)dealloc
171 {
172  [_circleImage release];
173  [super dealloc];
174 }
175 
176 static NSInteger VuoGraphicsView_touchComparator(NSTouch *a, NSTouch *b, void *p)
177 {
178  float ax = a.normalizedPosition.x;
179  float bx = b.normalizedPosition.x;
180  if (ax < bx)
181  return -1;
182  else if (ax > bx)
183  return 1;
184  else
185  return 0;
186 }
187 
188 - (void)fireTouches:(NSEvent *)e
189 {
190  NSSet *touchesSet = [e touchesMatchingPhase:NSTouchPhaseAny inView:nil];
191  NSArray *orderedTouches = [touchesSet.allObjects sortedArrayUsingFunction:VuoGraphicsView_touchComparator context:nil];
192 
193  VuoList_VuoPoint2d touches = VuoListCreateWithCount_VuoPoint2d(orderedTouches.count, (VuoPoint2d){0,0});
194  VuoPoint2d *touchPoints = VuoListGetData_VuoPoint2d(touches);
195  int i = 0;
196  for (NSTouch *t in orderedTouches)
197  touchPoints[i++] = (VuoPoint2d){
198  t.normalizedPosition.x * 2 - 1,
199  (t.normalizedPosition.y * 2 - 1) * (t.deviceSize.height / t.deviceSize.width)
200  };
201 
202  dispatch_async(dispatch_get_main_queue(), ^{
203  for (NSValue *v in self.touchTriggers)
204  {
205  void (*touchesMoved)(VuoList_VuoPoint2d) = v.pointerValue;
206  if (touchesMoved)
207  touchesMoved(touches);
208  }
209  });
210 }
211 - (void)touchesBeganWithEvent:(NSEvent *)event
212 {
213  [self fireTouches:event];
214 }
215 - (void)touchesMovedWithEvent:(NSEvent *)event
216 {
217  [self fireTouches:event];
218 }
219 - (void)touchesEndedWithEvent:(NSEvent *)event
220 {
221  [self fireTouches:event];
222 }
223 - (void)touchesCancelledWithEvent:(NSEvent *)event
224 {
225  [self fireTouches:event];
226 }
227 
228 - (void)magnifyWithEvent:(NSEvent *)event
229 {
230  if (event.magnification != 0)
231  dispatch_async(dispatch_get_main_queue(), ^{
232  for (NSValue *v in self.zoomedTriggers)
233  {
234  void (*zoomed)(VuoReal) = v.pointerValue;
235  if (zoomed)
236  zoomed(event.magnification);
237  }
238  });
239 }
240 
241 - (void)swipeWithEvent:(NSEvent *)event
242 {
243  if (event.deltaX > 0)
244  dispatch_async(dispatch_get_main_queue(), ^{
245  for (NSValue *v in self.swipedLeftTriggers)
246  {
247  void (*swipedLeft)(void) = v.pointerValue;
248  if (swipedLeft)
249  swipedLeft();
250  }
251  });
252  else if (event.deltaX < 0)
253  dispatch_async(dispatch_get_main_queue(), ^{
254  for (NSValue *v in self.swipedRightTriggers)
255  {
256  void (*swipedRight)(void) = v.pointerValue;
257  if (swipedRight)
258  swipedRight();
259  }
260  });
261 }
262 
269 - (void)addTouchesMovedTrigger:(void (*)(VuoList_VuoPoint2d))touchesMoved
270  zoomed:(void (*)(VuoReal))zoomed
271  swipedLeft:(void (*)(void))swipedLeft
272  swipedRight:(void (*)(void))swipedRight
273 {
274  dispatch_async(dispatch_get_main_queue(), ^{
275  [self.touchTriggers addObject:[NSValue valueWithPointer:touchesMoved]];
276  [self.zoomedTriggers addObject:[NSValue valueWithPointer:zoomed]];
277  [self.swipedLeftTriggers addObject:[NSValue valueWithPointer:swipedLeft]];
278  [self.swipedRightTriggers addObject:[NSValue valueWithPointer:swipedRight]];
279  });
280 }
281 
288 - (void)removeTouchesMovedTrigger:(void (*)(VuoList_VuoPoint2d))touchesMoved
289  zoomed:(void (*)(VuoReal))zoomed
290  swipedLeft:(void (*)(void))swipedLeft
291  swipedRight:(void (*)(void))swipedRight
292 {
293  dispatch_async(dispatch_get_main_queue(), ^{
294  for (NSValue *v in self.touchTriggers)
295  if (v.pointerValue == touchesMoved)
296  [self.touchTriggers removeObject:v];
297  for (NSValue *v in self.zoomedTriggers)
298  if (v.pointerValue == zoomed)
299  [self.zoomedTriggers removeObject:v];
300  for (NSValue *v in self.swipedLeftTriggers)
301  if (v.pointerValue == swipedLeft)
302  [self.swipedLeftTriggers removeObject:v];
303  for (NSValue *v in self.swipedRightTriggers)
304  if (v.pointerValue == swipedRight)
305  [self.swipedRightTriggers removeObject:v];
306  });
307 }
308 @end