Vuo  2.0.1
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  self.acceptsTouchEvents = YES;
51  self.wantsRestingTouches = YES;
52  _touchTriggers = [NSMutableSet new];
53  _zoomedTriggers = [NSMutableSet new];
54  _swipedLeftTriggers = [NSMutableSet new];
55  _swipedRightTriggers = [NSMutableSet new];
56 
57  // Prepare the circle mouse cursor.
58  {
59  _circleRect = NSMakeRect(0,0,48,48);
60  _circleImage = [[NSImage alloc] initWithSize:_circleRect.size];
61  [_circleImage lockFocus];
62  {
63  [[NSColor colorWithDeviceWhite:1 alpha:0.75] setFill];
64  [[NSColor colorWithDeviceWhite:0 alpha:0.15] setStroke];
65  NSBezierPath *circlePath = [NSBezierPath bezierPathWithOvalInRect:NSInsetRect(_circleRect, 1, 1)];
66  [circlePath fill];
67  [circlePath stroke];
68  }
69  [_circleImage unlockFocus];
70  }
71  }
72  return self;
73 }
74 
81 - (void)viewDidMoveToWindow
82 {
83  if (!self.window)
84  return;
85 
86  _viewport = self.frame;
87 }
88 
95 - (void)viewDidChangeBackingProperties
96 {
97  VuoGraphicsLayer *l = (VuoGraphicsLayer *)self.layer;
99  [l setNeedsDisplay];
100 }
101 
106 - (void)resetCursorRects
107 {
108  VuoGraphicsWindow *gw = (VuoGraphicsWindow *)self.window;
109  VuoCursor cursor = gw.cursor;
110  NSCursor *nsCursor = nil;
111 
112  if (cursor == VuoCursor_None)
113  {
114  NSImage *im = [[NSImage alloc] initWithSize:NSMakeSize(1,1)];
115  nsCursor = [[[NSCursor alloc] initWithImage:im hotSpot:NSMakePoint(0,0)] autorelease];
116  [im release];
117  }
118  else if (cursor == VuoCursor_Pointer)
119  nsCursor = [NSCursor arrowCursor];
120  else if (cursor == VuoCursor_Crosshair)
121  nsCursor = [NSCursor crosshairCursor];
122  else if (cursor == VuoCursor_HandOpen)
123  nsCursor = [NSCursor openHandCursor];
124  else if (cursor == VuoCursor_HandClosed)
125  nsCursor = [NSCursor closedHandCursor];
126  else if (cursor == VuoCursor_IBeam)
127  nsCursor = [NSCursor IBeamCursor];
128  else if (cursor == VuoCursor_Circle)
129  nsCursor = [[[NSCursor alloc] initWithImage:_circleImage hotSpot:NSMakePoint(NSMidX(_circleRect),NSMidY(_circleRect))] autorelease];
130 
131  if (nsCursor)
132  [self addCursorRect:[self visibleRect] cursor:nsCursor];
133 }
134 
141 - (BOOL)acceptsFirstResponder
142 {
143  return YES;
144 }
145 
157 - (BOOL)mouseDownCanMoveWindow
158 {
159  return NO;
160 }
161 
165 - (void)dealloc
166 {
167  [_circleImage release];
168  [super dealloc];
169 }
170 
171 static NSInteger VuoGraphicsView_touchComparator(NSTouch *a, NSTouch *b, void *p)
172 {
173  float ax = a.normalizedPosition.x;
174  float bx = b.normalizedPosition.x;
175  if (ax < bx)
176  return -1;
177  else if (ax > bx)
178  return 1;
179  else
180  return 0;
181 }
182 
183 - (void)fireTouches:(NSEvent *)e
184 {
185  NSSet *touchesSet = [e touchesMatchingPhase:NSTouchPhaseAny inView:nil];
186  NSArray *orderedTouches = [touchesSet.allObjects sortedArrayUsingFunction:VuoGraphicsView_touchComparator context:nil];
187 
188  VuoList_VuoPoint2d touches = VuoListCreateWithCount_VuoPoint2d(orderedTouches.count, (VuoPoint2d){0,0});
189  VuoPoint2d *touchPoints = VuoListGetData_VuoPoint2d(touches);
190  int i = 0;
191  for (NSTouch *t in orderedTouches)
192  touchPoints[i++] = (VuoPoint2d){
193  t.normalizedPosition.x * 2 - 1,
194  (t.normalizedPosition.y * 2 - 1) * (t.deviceSize.height / t.deviceSize.width)
195  };
196 
197  dispatch_async(dispatch_get_main_queue(), ^{
198  for (NSValue *v in self.touchTriggers)
199  {
200  void (*touchesMoved)(VuoList_VuoPoint2d) = v.pointerValue;
201  if (touchesMoved)
202  touchesMoved(touches);
203  }
204  });
205 }
206 - (void)touchesBeganWithEvent:(NSEvent *)event
207 {
208  [self fireTouches:event];
209 }
210 - (void)touchesMovedWithEvent:(NSEvent *)event
211 {
212  [self fireTouches:event];
213 }
214 - (void)touchesEndedWithEvent:(NSEvent *)event
215 {
216  [self fireTouches:event];
217 }
218 - (void)touchesCancelledWithEvent:(NSEvent *)event
219 {
220  [self fireTouches:event];
221 }
222 
223 - (void)magnifyWithEvent:(NSEvent *)event
224 {
225  if (event.magnification != 0)
226  dispatch_async(dispatch_get_main_queue(), ^{
227  for (NSValue *v in self.zoomedTriggers)
228  {
229  void (*zoomed)(VuoReal) = v.pointerValue;
230  if (zoomed)
231  zoomed(event.magnification);
232  }
233  });
234 }
235 
236 - (void)swipeWithEvent:(NSEvent *)event
237 {
238  if (event.deltaX > 0)
239  dispatch_async(dispatch_get_main_queue(), ^{
240  for (NSValue *v in self.swipedLeftTriggers)
241  {
242  void (*swipedLeft)(void) = v.pointerValue;
243  if (swipedLeft)
244  swipedLeft();
245  }
246  });
247  else if (event.deltaX < 0)
248  dispatch_async(dispatch_get_main_queue(), ^{
249  for (NSValue *v in self.swipedRightTriggers)
250  {
251  void (*swipedRight)(void) = v.pointerValue;
252  if (swipedRight)
253  swipedRight();
254  }
255  });
256 }
257 
264 - (void)addTouchesMovedTrigger:(void (*)(VuoList_VuoPoint2d))touchesMoved
265  zoomed:(void (*)(VuoReal))zoomed
266  swipedLeft:(void (*)(void))swipedLeft
267  swipedRight:(void (*)(void))swipedRight
268 {
269  dispatch_async(dispatch_get_main_queue(), ^{
270  [self.touchTriggers addObject:[NSValue valueWithPointer:touchesMoved]];
271  [self.zoomedTriggers addObject:[NSValue valueWithPointer:zoomed]];
272  [self.swipedLeftTriggers addObject:[NSValue valueWithPointer:swipedLeft]];
273  [self.swipedRightTriggers addObject:[NSValue valueWithPointer:swipedRight]];
274  });
275 }
276 
283 - (void)removeTouchesMovedTrigger:(void (*)(VuoList_VuoPoint2d))touchesMoved
284  zoomed:(void (*)(VuoReal))zoomed
285  swipedLeft:(void (*)(void))swipedLeft
286  swipedRight:(void (*)(void))swipedRight
287 {
288  dispatch_async(dispatch_get_main_queue(), ^{
289  for (NSValue *v in self.touchTriggers)
290  if (v.pointerValue == touchesMoved)
291  [self.touchTriggers removeObject:v];
292  for (NSValue *v in self.zoomedTriggers)
293  if (v.pointerValue == zoomed)
294  [self.zoomedTriggers removeObject:v];
295  for (NSValue *v in self.swipedLeftTriggers)
296  if (v.pointerValue == swipedLeft)
297  [self.swipedLeftTriggers removeObject:v];
298  for (NSValue *v in self.swipedRightTriggers)
299  if (v.pointerValue == swipedRight)
300  [self.swipedRightTriggers removeObject:v];
301  });
302 }
303 @end