iPlug2 - C++ Audio Plug-in Framework
IGraphicsMac_view.mm
1 /*
2  ==============================================================================
3 
4  This file is part of the iPlug 2 library. Copyright (C) the iPlug 2 developers.
5 
6  See LICENSE.txt for more info.
7 
8  ==============================================================================
9 */
10 
11 #import <QuartzCore/QuartzCore.h>
12 
13 #if defined IGRAPHICS_METAL
14 #import <Metal/Metal.h>
15 #endif
16 
17 #if defined IGRAPHICS_IMGUI
18 #import <Metal/Metal.h>
19 #include "imgui.h"
20 #import "imgui_impl_metal.h"
21 #endif
22 
23 #include "wdlutf8.h"
24 
25 #import "IGraphicsMac_view.h"
26 #include "IControl.h"
27 #include "IPlugParameter.h"
28 #include "IPlugLogger.h"
29 
30 using namespace iplug;
31 using namespace igraphics;
32 
33 static int MacKeyCodeToVK(int code)
34 {
35  switch (code)
36  {
37  case 51: return kVK_BACK;
38  case 65: return kVK_DECIMAL;
39  case 67: return kVK_MULTIPLY;
40  case 69: return kVK_ADD;
41  case 71: return kVK_NUMLOCK;
42  case 75: return kVK_DIVIDE;
43  case 76: return kVK_RETURN | 0x8000;
44  case 78: return kVK_SUBTRACT;
45  case 81: return kVK_SEPARATOR;
46  case 82: return kVK_NUMPAD0;
47  case 83: return kVK_NUMPAD1;
48  case 84: return kVK_NUMPAD2;
49  case 85: return kVK_NUMPAD3;
50  case 86: return kVK_NUMPAD4;
51  case 87: return kVK_NUMPAD5;
52  case 88: return kVK_NUMPAD6;
53  case 89: return kVK_NUMPAD7;
54  case 91: return kVK_NUMPAD8;
55  case 92: return kVK_NUMPAD9;
56  case 96: return kVK_F5;
57  case 97: return kVK_F6;
58  case 98: return kVK_F7;
59  case 99: return kVK_F3;
60  case 100: return kVK_F8;
61  case 101: return kVK_F9;
62  case 109: return kVK_F10;
63  case 103: return kVK_F11;
64  case 111: return kVK_F12;
65  case 114: return kVK_INSERT;
66  case 115: return kVK_HOME;
67  case 117: return kVK_DELETE;
68  case 116: return kVK_PRIOR;
69  case 118: return kVK_F4;
70  case 119: return kVK_END;
71  case 120: return kVK_F2;
72  case 121: return kVK_NEXT;
73  case 122: return kVK_F1;
74  case 123: return kVK_LEFT;
75  case 124: return kVK_RIGHT;
76  case 125: return kVK_DOWN;
77  case 126: return kVK_UP;
78  case 0x69: return kVK_F13;
79  case 0x6B: return kVK_F14;
80  case 0x71: return kVK_F15;
81  case 0x6A: return kVK_F16;
82  }
83  return kVK_NONE;
84 }
85 
86 static int MacKeyEventToVK(NSEvent* pEvent, int& flag)
87 {
88  int code = kVK_NONE;
89 
90  const NSInteger mod = [pEvent modifierFlags];
91 
92  if (mod & NSShiftKeyMask) flag |= kFSHIFT;
93  if (mod & NSCommandKeyMask) flag |= kFCONTROL;
94  if (mod & NSAlternateKeyMask) flag |= kFALT;
95  if ((mod & NSControlKeyMask) /*&& !IsRightClickEmulateEnabled()*/) flag |= kFLWIN;
96 
97  int rawcode = [pEvent keyCode];
98 
99  code = MacKeyCodeToVK(rawcode);
100  if (code == kVK_NONE)
101  {
102  NSString *str = NULL;
103 
104  if (!str || ![str length]) str = [pEvent charactersIgnoringModifiers];
105 
106  if (!str || ![str length])
107  {
108  if (!code)
109  {
110  code = 1024 + rawcode; // raw code
111  flag |= kFVIRTKEY;
112  }
113  }
114  else
115  {
116  code = [str characterAtIndex:0];
117  if (code >= NSF1FunctionKey && code <= NSF24FunctionKey)
118  {
119  flag |= kFVIRTKEY;
120  code += kVK_F1 - NSF1FunctionKey;
121  }
122  else
123  {
124  if (code >= 'a' && code <= 'z') code += 'A'-'a';
125  if (code == 25 && (flag & FSHIFT)) code = kVK_TAB;
126  if (isalnum(code) || code==' ' || code == '\r' || code == '\n' || code ==27 || code == kVK_TAB) flag |= kFVIRTKEY;
127  }
128  }
129  }
130  else
131  {
132  flag |= kFVIRTKEY;
133  if (code == 8) code = '\b';
134  }
135 
136  if (!(flag & kFVIRTKEY)) flag &= ~kFSHIFT;
137 
138  return code;
139 }
140 
141 @implementation IGRAPHICS_MENU_RCVR
142 
143 - (NSMenuItem*) menuItem
144 {
145  return nsMenuItem;
146 }
147 
148 - (void) onMenuSelection:(id) sender
149 {
150  nsMenuItem = sender;
151 }
152 
153 @end
154 
155 @implementation IGRAPHICS_MENU
156 
157 - (id) initWithIPopupMenuAndReceiver: (IPopupMenu*) pMenu : (NSView*) pView
158 {
159  [self initWithTitle: @""];
160 
161  NSMenuItem* nsMenuItem;
162  NSMutableString* nsMenuItemTitle;
163 
164  [self setAutoenablesItems:NO];
165 
166  int numItems = pMenu->NItems();
167 
168  for (int i = 0; i < numItems; ++i)
169  {
170  IPopupMenu::Item* pMenuItem = pMenu->GetItem(i);
171 
172  nsMenuItemTitle = [[[NSMutableString alloc] initWithCString:pMenuItem->GetText() encoding:NSUTF8StringEncoding] autorelease];
173 
174  if (pMenu->GetPrefix())
175  {
176  NSString* prefixString = 0;
177 
178  switch (pMenu->GetPrefix())
179  {
180  case 0: prefixString = [NSString stringWithUTF8String:""]; break;
181  case 1: prefixString = [NSString stringWithFormat:@"%1d: ", i+1]; break;
182  case 2: prefixString = [NSString stringWithFormat:@"%02d: ", i+1]; break;
183  case 3: prefixString = [NSString stringWithFormat:@"%03d: ", i+1]; break;
184  }
185 
186  [nsMenuItemTitle insertString:prefixString atIndex:0];
187  }
188 
189  if (pMenuItem->GetIsSeparator())
190  {
191  [self addItem:[NSMenuItem separatorItem]];
192  }
193  else if (pMenuItem->GetSubmenu())
194  {
195  nsMenuItem = [self addItemWithTitle:nsMenuItemTitle action:nil keyEquivalent:@""];
196  NSMenu* subMenu = [[IGRAPHICS_MENU alloc] initWithIPopupMenuAndReceiver:pMenuItem->GetSubmenu() :pView];
197  [self setSubmenu: subMenu forItem:nsMenuItem];
198  [subMenu release];
199  }
200  else
201  {
202  nsMenuItem = [self addItemWithTitle:nsMenuItemTitle action:@selector(onMenuSelection:) keyEquivalent:@""];
203 
204  [nsMenuItem setTarget:pView];
205  }
206 
207  if (!pMenuItem->GetIsSeparator())
208  {
209  [nsMenuItem setIndentationLevel:pMenuItem->GetIsTitle() ? 1 : 0 ];
210  [nsMenuItem setEnabled:pMenuItem->GetEnabled() ? YES : NO];
211  [nsMenuItem setState:pMenuItem->GetChecked() ? NSOnState : NSOffState];
212  }
213  }
214 
215  mIPopupMenu = pMenu;
216 
217  return self;
218 }
219 
220 - (IPopupMenu*) iPopupMenu
221 {
222  return mIPopupMenu;
223 }
224 
225 @end
226 
227 @implementation IGRAPHICS_TEXTFIELD
228 
229 - (bool) becomeFirstResponder;
230 {
231  bool success = [super becomeFirstResponder];
232  if (success)
233  {
234  NSTextView *textField = (NSTextView*) [self currentEditor];
235  if( [textField respondsToSelector: @selector(setInsertionPointColor:)] )
236  [textField setInsertionPointColor: [self textColor]];
237  }
238  return success;
239 }
240 
241 @end
242 
243 // IGRAPHICS_TEXTFIELDCELL based on...
244 
245 // https://red-sweater.com/blog/148/what-a-difference-a-cell-makes
246 
247 // This source code is provided to you compliments of Red Sweater Software under the license as described below. NOTE: This is the MIT License.
248 //
249 // Copyright (c) 2006 Red Sweater Software
250 //
251 // Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
252 //
253 // The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
254 //
255 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
256 
257 @implementation IGRAPHICS_TEXTFIELDCELL
258 
259 - (NSRect) drawingRectForBounds: (NSRect) inRect
260 {
261  // Get the parent's idea of where we should draw
262  NSRect outRect = [super drawingRectForBounds:inRect];
263 
264  // When the text field is being
265  // edited or selected, we have to turn off the magic because it screws up
266  // the configuration of the field editor. We sneak around this by
267  // intercepting selectWithFrame and editWithFrame and sneaking a
268  // reduced, centered rect in at the last minute.
269  if (mIsEditingOrSelecting == NO)
270  {
271  // Get our ideal size for current text
272  NSSize textSize = [self cellSize];
273 
274  // Center that in the proposed rect
275  float heightDelta = outRect.size.height - textSize.height;
276 
277  outRect.size.height -= heightDelta;
278  outRect.origin.y += (heightDelta / 2);
279  }
280 
281  return outRect;
282 }
283 
284 - (void) selectWithFrame: (NSRect) aRect inView: (NSView*) controlView editor: (NSText*) textObj delegate: (id) anObject start: (NSInteger) selStart length: (NSInteger) selLength
285 {
286  aRect = [self drawingRectForBounds:aRect];
287  mIsEditingOrSelecting = YES;
288  [super selectWithFrame:aRect inView:controlView editor:textObj delegate:anObject start:selStart length:selLength];
289  mIsEditingOrSelecting = NO;
290 }
291 
292 - (void) editWithFrame: (NSRect) aRect inView: (NSView*) controlView editor: (NSText*) textObj delegate: (id) anObject event: (NSEvent*) theEvent
293 {
294  aRect = [self drawingRectForBounds:aRect];
295  mIsEditingOrSelecting = YES;
296  [super editWithFrame:aRect inView:controlView editor:textObj delegate:anObject event:theEvent];
297  mIsEditingOrSelecting = NO;
298 }
299 @end
300 
301 
302 @implementation IGRAPHICS_FORMATTER
303 
304 - (void) dealloc
305 {
306  [filterCharacterSet release];
307  [super dealloc];
308 }
309 
310 - (BOOL) isPartialStringValid:(NSString*) partialString newEditingString:(NSString**) newString errorDescription:(NSString**) error
311 {
312  if (filterCharacterSet != nil)
313  {
314  int i = 0;
315  int len = (int) [partialString length];
316 
317  for (i = 0; i < len; i++)
318  {
319  if (![filterCharacterSet characterIsMember:[partialString characterAtIndex:i]])
320  {
321  return NO;
322  }
323  }
324  }
325 
326  if (maxLength)
327  {
328  if ([partialString length] > maxLength)
329  {
330  return NO;
331  }
332  }
333 
334  if (maxValue && [partialString intValue] > maxValue)
335  {
336  return NO;
337  }
338 
339  return YES;
340 }
341 
342 - (void) setAcceptableCharacterSet: (NSCharacterSet*) inCharacterSet
343 {
344  [inCharacterSet retain];
345  [filterCharacterSet release];
346  filterCharacterSet = inCharacterSet;
347 }
348 
349 - (void) setMaximumLength: (int) inLength
350 {
351  maxLength = inLength;
352 }
353 
354 - (void) setMaximumValue: (int) inValue
355 {
356  maxValue = inValue;
357 }
358 
359 - (NSString*) stringForObjectValue: (id) anObject
360 {
361  if ([anObject isKindOfClass:[NSString class]])
362  {
363  return anObject;
364  }
365 
366  return nil;
367 }
368 
369 - (BOOL) getObjectValue: (id*) anObject forString:(NSString*) string errorDescription: (NSString **) error
370 {
371  if (anObject && string)
372  {
373  *anObject = [NSString stringWithString:string];
374  }
375 
376  return YES;
377 }
378 @end
379 
380 #pragma mark -
381 
382 extern StaticStorage<CoreTextFontDescriptor> sFontDescriptorCache;
383 
384 @implementation IGRAPHICS_VIEW
385 
386 - (id) initWithIGraphics: (IGraphicsMac*) pGraphics
387 {
388  TRACE
389 
390  mGraphics = pGraphics;
391  NSRect r = NSMakeRect(0.f, 0.f, (float) pGraphics->WindowWidth(), (float) pGraphics->WindowHeight());
392  self = [super initWithFrame:r];
393 
394  mMouseOutDuringDrag = false;
395 
396  self.wantsLayer = YES;
397  self.layer.opaque = YES;
398  self.layerContentsRedrawPolicy = NSViewLayerContentsRedrawDuringViewResize;
399 
400  [self registerForDraggedTypes:[NSArray arrayWithObjects: NSFilenamesPboardType, nil]];
401 
402  #if defined IGRAPHICS_METAL
403  self.layer = [CAMetalLayer new];
404  [(CAMetalLayer*)[self layer] setPixelFormat:MTLPixelFormatBGRA8Unorm];
405  ((CAMetalLayer*) self.layer).device = MTLCreateSystemDefaultDevice();
406 
407  #elif defined IGRAPHICS_GL
408  NSOpenGLPixelFormatAttribute profile = NSOpenGLProfileVersionLegacy;
409  #if defined IGRAPHICS_GL3
410  profile = (NSOpenGLPixelFormatAttribute)NSOpenGLProfileVersion3_2Core;
411  #endif
412  const NSOpenGLPixelFormatAttribute attrs[] = {
413  NSOpenGLPFAAccelerated,
414  NSOpenGLPFANoRecovery,
415  NSOpenGLPFADoubleBuffer,
416  NSOpenGLPFAAlphaSize, 8,
417  NSOpenGLPFAColorSize, 24,
418  NSOpenGLPFADepthSize, 0,
419  NSOpenGLPFAStencilSize, 8,
420  NSOpenGLPFAOpenGLProfile, profile,
421  (NSOpenGLPixelFormatAttribute) 0
422  };
423  NSOpenGLPixelFormat* pPixelFormat = [[NSOpenGLPixelFormat alloc] initWithAttributes:attrs];
424  NSOpenGLContext* pGLContext = [[NSOpenGLContext alloc] initWithFormat:pPixelFormat shareContext:nil];
425 
426  #ifdef DEBUG
427  // CGLEnable([context CGLContextObj], kCGLCECrashOnRemovedFunctions); //SKIA_GL2 will crash
428  #endif
429 
430  self.pixelFormat = pPixelFormat;
431  self.openGLContext = pGLContext;
432  self.wantsBestResolutionOpenGLSurface = YES;
433  #endif // IGRAPHICS_GL
434 
435  #if !defined IGRAPHICS_GL
436  [self setTimer];
437  #endif
438 
439  return self;
440 }
441 
442 #ifdef IGRAPHICS_GL
443 - (void) prepareOpenGL
444 {
445  [super prepareOpenGL];
446 
447  [[self openGLContext] makeCurrentContext];
448 
449  // Synchronize buffer swaps with vertical refresh rate
450  GLint swapInt = 1;
451  [[self openGLContext] setValues:&swapInt forParameter:NSOpenGLCPSwapInterval];
452 
453  [self setTimer];
454 }
455 #endif
456 
457 static CVReturn displayLinkCallback(CVDisplayLinkRef displayLink, const CVTimeStamp* now, const CVTimeStamp* outputTime, CVOptionFlags flagsIn, CVOptionFlags* flagsOut, void* displayLinkContext)
458 {
459  dispatch_source_t source = (dispatch_source_t) displayLinkContext;
460  dispatch_source_merge_data(source, 1);
461 
462  return kCVReturnSuccess;
463 }
464 
465 - (void) onTimer: (NSTimer*) pTimer
466 {
467  [self render];
468 }
469 
470 - (void) setTimer
471 {
472 #ifdef IGRAPHICS_CVDISPLAYLINK
473  mDisplaySource = dispatch_source_create(DISPATCH_SOURCE_TYPE_DATA_ADD, 0, 0, dispatch_get_main_queue());
474  dispatch_source_set_event_handler(mDisplaySource, ^(){
475  [self render];
476  });
477  dispatch_resume(mDisplaySource);
478 
479  CVReturn cvReturn;
480 
481  cvReturn = CVDisplayLinkCreateWithActiveCGDisplays(&mDisplayLink);
482 
483  assert(cvReturn == kCVReturnSuccess);
484 
485  cvReturn = CVDisplayLinkSetOutputCallback(mDisplayLink, &displayLinkCallback, (void*) mDisplaySource);
486  assert(cvReturn == kCVReturnSuccess);
487 
488  #ifdef IGRAPHICS_GL
489  CGLContextObj cglContext = [[self openGLContext] CGLContextObj];
490  CGLPixelFormatObj cglPixelFormat = [[self pixelFormat] CGLPixelFormatObj];
491  CVDisplayLinkSetCurrentCGDisplayFromOpenGLContext(mDisplayLink, cglContext, cglPixelFormat);
492  #endif
493 
494  CGDirectDisplayID viewDisplayID =
495  (CGDirectDisplayID) [self.window.screen.deviceDescription[@"NSScreenNumber"] unsignedIntegerValue];;
496 
497  cvReturn = CVDisplayLinkSetCurrentCGDisplay(mDisplayLink, viewDisplayID);
498 
499  assert(cvReturn == kCVReturnSuccess);
500 
501  CVDisplayLinkStart(mDisplayLink);
502 #else
503  double sec = 1.0 / (double) mGraphics->FPS();
504  mTimer = [NSTimer timerWithTimeInterval:sec target:self selector:@selector(onTimer:) userInfo:nil repeats:YES];
505  [[NSRunLoop currentRunLoop] addTimer: mTimer forMode: (NSString*) kCFRunLoopCommonModes];
506 #endif
507 }
508 
509 - (void) killTimer
510 {
511 #ifdef IGRAPHICS_CVDISPLAYLINK
512  CVDisplayLinkStop(mDisplayLink);
513  dispatch_source_cancel(mDisplaySource);
514  CVDisplayLinkRelease(mDisplayLink);
515  mDisplayLink = nil;
516 #else
517  [mTimer invalidate];
518  mTimer = nullptr;
519 #endif
520 }
521 
522 - (void) dealloc
523 {
524  if([NSColorPanel sharedColorPanelExists])
525  [[NSColorPanel sharedColorPanel] close];
526 
527  mColorPickerFunc = nullptr;
528  [mMoveCursor release];
529  [mTrackingArea release];
530  [[NSNotificationCenter defaultCenter] removeObserver:self];
531  [super dealloc];
532 }
533 
534 
535 - (BOOL) isOpaque
536 {
537  return mGraphics ? YES : NO;
538 }
539 
540 - (BOOL) isFlipped
541 {
542  return YES;
543 }
544 
545 - (BOOL) acceptsFirstResponder
546 {
547  return YES;
548 }
549 
550 - (BOOL) acceptsFirstMouse: (NSEvent*) pEvent
551 {
552  return YES;
553 }
554 
555 - (void) viewDidMoveToWindow
556 {
557  NSWindow* pWindow = [self window];
558 
559  if (pWindow)
560  {
561  [pWindow makeFirstResponder: self];
562  [pWindow setAcceptsMouseMovedEvents: YES];
563 
564  CGFloat newScale = [pWindow backingScaleFactor];
565 
566  if (mGraphics)
567  mGraphics->SetScreenScale(newScale);
568 
569  #ifdef IGRAPHICS_METAL
570  [[NSNotificationCenter defaultCenter] addObserver:self
571  selector:@selector(frameDidChange:)
572  name:NSViewFrameDidChangeNotification
573  object:self];
574  #endif
575 
576 // [[NSNotificationCenter defaultCenter] addObserver:self
577 // selector:@selector(windowResized:) name:NSWindowDidEndLiveResizeNotification
578 // object:pWindow];
579 //
580 // [[NSNotificationCenter defaultCenter] addObserver:self
581 // selector:@selector(windowFullscreened:) name:NSWindowDidEnterFullScreenNotification
582 // object:pWindow];
583 //
584 // [[NSNotificationCenter defaultCenter] addObserver:self
585 // selector:@selector(windowFullscreened:) name:NSWindowDidExitFullScreenNotification
586 // object:pWindow];
587  }
588 }
589 
590 - (void) viewDidChangeBackingProperties:(NSNotification*) pNotification
591 {
592  NSWindow* pWindow = [self window];
593 
594  if (!pWindow)
595  return;
596 
597  CGFloat newScale = [pWindow backingScaleFactor];
598 
599  mGraphics->SetPlatformContext(nullptr);
600 
601  if (newScale != mGraphics->GetScreenScale())
602  mGraphics->SetScreenScale(newScale);
603 
604 #if defined IGRAPHICS_GL
605  self.layer.contentsScale = 1./newScale;
606 #elif defined IGRAPHICS_METAL
607  [(CAMetalLayer*)[self layer] setDrawableSize:CGSizeMake(self.frame.size.width * newScale,
608  self.frame.size.height * newScale)];
609 #endif
610 }
611 
612 - (CGContextRef) getCGContextRef
613 {
614  CGContextRef pCGC = [NSGraphicsContext currentContext].CGContext;
615  return [NSGraphicsContext graphicsContextWithCGContext: pCGC flipped: YES].CGContext;
616 }
617 
618 // not called for layer backed views
619 - (void) drawRect: (NSRect) bounds
620 {
621  #if !defined IGRAPHICS_GL && !defined IGRAPHICS_METAL
622  if (mGraphics)
623  {
624  mGraphics->SetPlatformContext([self getCGContextRef]);
625 
626  if (mGraphics->GetPlatformContext())
627  {
628  const NSRect *rects;
629  NSInteger numRects;
630  [self getRectsBeingDrawn:&rects count:&numRects];
631  IRECTList drawRects;
632 
633  for (int i = 0; i < numRects; i++)
634  drawRects.Add(ToIRECT(mGraphics, &rects[i]));
635 
636  mGraphics->Draw(drawRects);
637  }
638  }
639  #else // this gets called on resize
640  //TODO: set GL context/flush?
641  //mGraphics->Draw(mDirtyRects);
642  #endif
643 }
644 
645 - (void) render
646 {
647  mDirtyRects.Clear();
648 
649  if (mGraphics->IsDirty(mDirtyRects))
650  {
651  mGraphics->SetAllControlsClean();
652 
653  #if !defined IGRAPHICS_GL && !defined IGRAPHICS_METAL // for layer-backed views setNeedsDisplayInRect/drawRect is not called
654  for (int i = 0; i < mDirtyRects.Size(); i++)
655  [self setNeedsDisplayInRect:ToNSRect(mGraphics, mDirtyRects.Get(i))];
656  #else
657  #ifdef IGRAPHICS_GL
658  [[self openGLContext] makeCurrentContext];
659  #endif
660  // so just draw on each frame, if something is dirty
661  mGraphics->Draw(mDirtyRects);
662  #endif
663  #ifdef IGRAPHICS_GL
664  [[self openGLContext] flushBuffer];
665  #endif
666  }
667 }
668 
669 - (void) getMouseXY: (NSEvent*) pEvent : (float&) x : (float&) y
670 {
671  if (mGraphics)
672  {
673  NSPoint pt = [self convertPoint:[pEvent locationInWindow] fromView:nil];
674  x = pt.x / mGraphics->GetDrawScale();
675  y = pt.y / mGraphics->GetDrawScale();
676 
677  mGraphics->DoCursorLock(x, y, mPrevX, mPrevY);
678  mGraphics->SetTabletInput(pEvent.subtype == NSTabletPointEventSubtype);
679  }
680 }
681 
682 - (IMouseInfo) getMouseLeft: (NSEvent*) pEvent
683 {
684  IMouseInfo info;
685  [self getMouseXY:pEvent : info.x : info.y];
686  int mods = (int) [pEvent modifierFlags];
687  info.ms = IMouseMod(true, (mods & NSCommandKeyMask), (mods & NSShiftKeyMask), (mods & NSControlKeyMask), (mods & NSAlternateKeyMask));
688 
689  return info;
690 }
691 
692 - (IMouseInfo) getMouseRight: (NSEvent*) pEvent
693 {
694  IMouseInfo info;
695  [self getMouseXY:pEvent : info.x : info.y];
696  int mods = (int) [pEvent modifierFlags];
697  info.ms = IMouseMod(false, true, (mods & NSShiftKeyMask), (mods & NSControlKeyMask), (mods & NSAlternateKeyMask));
698 
699  return info;
700 }
701 
702 - (void) updateTrackingAreas
703 {
704  [super updateTrackingAreas]; // This is needed to get mouseEntered and mouseExited
705 
706  if (mTrackingArea != nil)
707  {
708  [self removeTrackingArea:mTrackingArea];
709  [mTrackingArea release];
710  }
711 
712  int opts = (NSTrackingMouseEnteredAndExited | NSTrackingActiveAlways);
713  mTrackingArea = [ [NSTrackingArea alloc] initWithRect:[self bounds] options:opts owner:self userInfo:nil];
714  [self addTrackingArea:mTrackingArea];
715 }
716 
717 - (void) mouseEntered: (NSEvent*) pEvent
718 {
719  mMouseOutDuringDrag = false;
720 
721  if (mGraphics)
722  {
723  mGraphics->OnSetCursor();
724  }
725 }
726 
727 - (void) mouseExited: (NSEvent*) pEvent
728 {
729  if (mGraphics)
730  {
731  if (!mGraphics->ControlIsCaptured())
732  {
733  mGraphics->OnMouseOut();
734  }
735  else
736  {
737  mMouseOutDuringDrag = true;
738  }
739  }
740 }
741 
742 - (void) mouseDown: (NSEvent*) pEvent
743 {
744  IMouseInfo info = [self getMouseLeft:pEvent];
745  if (mGraphics)
746  {
747  if (([pEvent clickCount] - 1) % 2)
748  {
749  mGraphics->OnMouseDblClick(info.x, info.y, info.ms);
750  }
751  else
752  {
753  std::vector<IMouseInfo> list {info};
754  mGraphics->OnMouseDown(list);
755  }
756  }
757 }
758 
759 - (void) mouseUp: (NSEvent*) pEvent
760 {
761  IMouseInfo info = [self getMouseLeft:pEvent];
762  if (mGraphics)
763  {
764  std::vector<IMouseInfo> list {info};
765  mGraphics->OnMouseUp(list);
766 
767  if (mMouseOutDuringDrag)
768  {
769  mGraphics->OnMouseOut();
770  mMouseOutDuringDrag = false;
771  }
772  }
773 }
774 
775 - (void) mouseDragged: (NSEvent*) pEvent
776 {
777  // Cache previous values before retrieving the new mouse position (which will update them)
778  float prevX = mPrevX;
779  float prevY = mPrevY;
780  IMouseInfo info = [self getMouseLeft:pEvent];
781  if (mGraphics && !mGraphics->IsInPlatformTextEntry())
782  {
783  info.dX = info.x - prevX;
784  info.dY = info.y - prevY;
785  std::vector<IMouseInfo> list {info};
786  mGraphics->OnMouseDrag(list);
787  }
788 }
789 
790 - (void) rightMouseDown: (NSEvent*) pEvent
791 {
792  IMouseInfo info = [self getMouseRight:pEvent];
793  if (mGraphics)
794  {
795  std::vector<IMouseInfo> list {info};
796  mGraphics->OnMouseDown(list);
797  }
798 }
799 
800 - (void) rightMouseUp: (NSEvent*) pEvent
801 {
802  IMouseInfo info = [self getMouseRight:pEvent];
803  if (mGraphics)
804  {
805  std::vector<IMouseInfo> list {info};
806  mGraphics->OnMouseUp(list);
807  }
808 }
809 
810 - (void) rightMouseDragged: (NSEvent*) pEvent
811 {
812  // Cache previous values before retrieving the new mouse position (which will update them)
813  float prevX = mPrevX;
814  float prevY = mPrevY;
815  IMouseInfo info = [self getMouseRight:pEvent];
816 
817  if (mGraphics && !mTextFieldView)
818  {
819  info.dX = info.x - prevX;
820  info.dY = info.y - prevY;
821  std::vector<IMouseInfo> list {info};
822  mGraphics->OnMouseDrag(list);
823  }
824 }
825 
826 - (void) mouseMoved: (NSEvent*) pEvent
827 {
828  IMouseInfo info = [self getMouseLeft:pEvent];
829  if (mGraphics)
830  mGraphics->OnMouseOver(info.x, info.y, info.ms);
831 }
832 
833 - (void) keyDown: (NSEvent*) pEvent
834 {
835  int flag = 0;
836  int code = MacKeyEventToVK(pEvent, flag);
837  NSString *s = [pEvent charactersIgnoringModifiers];
838 
839  unichar c = 0;
840 
841  if ([s length] == 1)
842  c = [s characterAtIndex:0];
843 
844  if(!static_cast<bool>(flag & kFVIRTKEY))
845  {
846  code = kVK_NONE;
847  }
848 
849  char utf8[5];
850  WDL_MakeUTFChar(utf8, c, 4);
851 
852  IKeyPress keyPress {utf8, code, static_cast<bool>(flag & kFSHIFT),
853  static_cast<bool>(flag & kFCONTROL),
854  static_cast<bool>(flag & kFALT)};
855 
856  bool handle = mGraphics->OnKeyDown(mPrevX, mPrevY, keyPress);
857 
858  if (!handle)
859  {
860  [[self nextResponder] keyDown:pEvent];
861  }
862 }
863 
864 - (void) keyUp: (NSEvent*) pEvent
865 {
866  int flag = 0;
867  int code = MacKeyEventToVK(pEvent, flag);
868  NSString *s = [pEvent charactersIgnoringModifiers];
869 
870  unichar c = 0;
871 
872  if ([s length] == 1)
873  c = [s characterAtIndex:0];
874 
875  if(!static_cast<bool>(flag & kFVIRTKEY))
876  {
877  code = kVK_NONE;
878  }
879 
880  char utf8[5];
881  WDL_MakeUTFChar(utf8, c, 4);
882 
883  IKeyPress keyPress {utf8, code, static_cast<bool>(flag & kFSHIFT),
884  static_cast<bool>(flag & kFCONTROL),
885  static_cast<bool>(flag & kFALT)};
886 
887  bool handle = mGraphics->OnKeyUp(mPrevX, mPrevY, keyPress);
888 
889  if (!handle)
890  {
891  [[self nextResponder] keyUp:pEvent];
892  }
893 }
894 
895 - (void) scrollWheel: (NSEvent*) pEvent
896 {
897  if (mTextFieldView) [self endUserInput ];
898  IMouseInfo info = [self getMouseLeft:pEvent];
899  float d = [pEvent deltaY];
900  if (mGraphics)
901  mGraphics->OnMouseWheel(info.x, info.y, info.ms, d);
902 }
903 
904 static void MakeCursorFromName(NSCursor*& cursor, const char *name)
905 {
906  // get paths and intialise images etc.
907  const char* basePath = "/System/Library/Frameworks/ApplicationServices.framework/Versions/A/Frameworks/HIServices.framework/Versions/A/Resources/cursors/";
908 
909  NSString* imagePath = [NSString stringWithFormat:@"%s%s/cursor.pdf", basePath, name];
910  NSString* infoPath = [NSString stringWithFormat:@"file:%s%s/info.plist", basePath, name];
911  NSImage* fileImage = [[NSImage alloc] initByReferencingFile: imagePath];
912  NSImage *cursorImage = [[NSImage alloc] initWithSize:[fileImage size]];
913  NSDictionary* info = [NSDictionary dictionaryWithContentsOfURL:[NSURL URLWithString:infoPath]];
914 
915  // get info from dictionary
916  double hotX = [info[@"hotx-scaled"] doubleValue];
917  double hotY = [info[@"hoty-scaled"] doubleValue];
918  double blur = [info[@"blur"] doubleValue];
919  double offsetX = [info[@"shadowoffsetx"] doubleValue];
920  double offsetY = [info[@"shadowoffsety"] doubleValue];
921  double red = [info[@"shadowcolor"][0] doubleValue];
922  double green = [info[@"shadowcolor"][1] doubleValue];
923  double blue = [info[@"shadowcolor"][2] doubleValue];
924  double alpha = [info[@"shadowcolor"][3] doubleValue];
925  CGColorRef shadowColor = CGColorCreateGenericRGB(red, green, blue, alpha);
926 
927  for (int scale = 1; scale <= 4; scale++)
928  {
929  // scale
930  NSAffineTransform* xform = [NSAffineTransform transform];
931  [xform scaleBy:scale];
932  id hints = @{ NSImageHintCTM: xform };
933  CGImageRef rasterCGImage = [fileImage CGImageForProposedRect:NULL context:nil hints:hints];
934 
935  // apply shadow
936  size_t width = CGImageGetWidth(rasterCGImage);
937  size_t height = CGImageGetHeight(rasterCGImage);
938  CGSize offset = CGSize { static_cast<CGFloat>(offsetX * scale), static_cast<CGFloat>(offsetY * scale) };
939  CGContextRef shadowContext = CGBitmapContextCreate(NULL, width, height, CGImageGetBitsPerComponent(rasterCGImage), 0, CGImageGetColorSpace(rasterCGImage), CGImageGetBitmapInfo(rasterCGImage));
940  CGContextSetShadowWithColor(shadowContext, offset, blur * scale, shadowColor);
941  CGContextDrawImage(shadowContext, CGRectMake(0, 0, width, height), rasterCGImage);
942  CGImageRef shadowCGImage = CGBitmapContextCreateImage(shadowContext);
943 
944  // add to cursor inmge
945  NSBitmapImageRep *rep = [[NSBitmapImageRep alloc] initWithCGImage:shadowCGImage];
946  [rep setSize:[fileImage size]];
947  [cursorImage addRepresentation:rep];
948 
949  // release
950  [rep release];
951  CGContextRelease(shadowContext);
952  CGImageRelease(shadowCGImage);
953  }
954 
955  // create cursor
956  cursor = [[NSCursor alloc] initWithImage:cursorImage hotSpot:NSMakePoint(hotX, hotY)];
957 
958  // release
959  [cursorImage release];
960  [fileImage release];
961  CGColorRelease(shadowColor);
962 }
963 
964 - (void) setMouseCursor: (ECursor) cursorType
965 {
966  NSCursor* pCursor = nullptr;
967 
968  bool helpCurrent = false;
969  bool helpRequested = false;
970 
971  switch (cursorType)
972  {
973  case ECursor::ARROW: pCursor = [NSCursor arrowCursor]; break;
974  case ECursor::IBEAM: pCursor = [NSCursor IBeamCursor]; break;
975  case ECursor::WAIT:
976  if ([NSCursor respondsToSelector:@selector(busyButClickableCursor)])
977  pCursor = [NSCursor performSelector:@selector(busyButClickableCursor)];
978  break;
979  case ECursor::CROSS: pCursor = [NSCursor crosshairCursor]; break;
980  case ECursor::UPARROW:
981  if ([NSCursor respondsToSelector:@selector(_windowResizeNorthCursor)])
982  pCursor = [NSCursor performSelector:@selector(_windowResizeNorthCursor)];
983  else
984  pCursor = [NSCursor resizeUpCursor];
985  break;
986  case ECursor::SIZENWSE:
987  if ([NSCursor respondsToSelector:@selector(_windowResizeNorthWestSouthEastCursor)])
988  pCursor = [NSCursor performSelector:@selector(_windowResizeNorthWestSouthEastCursor)];
989  break;
990  case ECursor::SIZENESW:
991  if ([NSCursor respondsToSelector:@selector(_windowResizeNorthEastSouthWestCursor)])
992  pCursor = [NSCursor performSelector:@selector(_windowResizeNorthEastSouthWestCursor)];
993  break;
994  case ECursor::SIZEWE:
995  if ([NSCursor respondsToSelector:@selector(_windowResizeEastWestCursor)])
996  pCursor = [NSCursor performSelector:@selector(_windowResizeEastWestCursor)];
997  else
998  pCursor = [NSCursor resizeLeftRightCursor];
999  break;
1000  case ECursor::SIZENS:
1001  if ([NSCursor respondsToSelector:@selector(_windowResizeNorthSouthCursor)])
1002  pCursor = [NSCursor performSelector:@selector(_windowResizeNorthSouthCursor)];
1003  else
1004  pCursor = [NSCursor resizeUpDownCursor];
1005  break;
1006  case ECursor::SIZEALL:
1007  {
1008  if (!mMoveCursor)
1009  MakeCursorFromName(mMoveCursor, "move");
1010  pCursor = mMoveCursor;
1011  break;
1012  }
1013  case ECursor::INO: pCursor = [NSCursor operationNotAllowedCursor]; break;
1014  case ECursor::HAND: pCursor = [NSCursor pointingHandCursor]; break;
1015  case ECursor::APPSTARTING:
1016  if ([NSCursor respondsToSelector:@selector(busyButClickableCursor)])
1017  pCursor = [NSCursor performSelector:@selector(busyButClickableCursor)];
1018  break;
1019  case ECursor::HELP:
1020  if ([NSCursor respondsToSelector:@selector(_helpCursor)])
1021  pCursor = [NSCursor performSelector:@selector(_helpCursor)];
1022  helpRequested = true;
1023  break;
1024  default: pCursor = [NSCursor arrowCursor]; break;
1025  }
1026 
1027  if ([NSCursor respondsToSelector:@selector(helpCursorShown)])
1028  helpCurrent = [NSCursor performSelector:@selector(helpCursorShown)];
1029 
1030  if (helpCurrent && !helpRequested)
1031  {
1032  // N.B. - suppress warnings for this call only
1033 #pragma clang diagnostic push
1034 #pragma clang diagnostic ignored "-Wobjc-method-access"
1035  [NSCursor _setHelpCursor : false];
1036 #pragma clang diagnostic pop
1037  }
1038 
1039  if (!pCursor)
1040  pCursor = [NSCursor arrowCursor];
1041 
1042  [pCursor set];
1043 }
1044 
1045 - (void) removeFromSuperview
1046 {
1047  if (mTextFieldView)
1048  [self endUserInput ];
1049 
1050  mGraphics->SetPlatformContext(nullptr);
1051 
1052  //For some APIs (AUv2) this is where we know about the window being closed, close via delegate
1053  mGraphics->GetDelegate()->CloseWindow();
1054  [super removeFromSuperview];
1055 }
1056 
1057 - (void) controlTextDidEndEditing: (NSNotification*) aNotification
1058 {
1059  char* txt = (char*)[[mTextFieldView stringValue] UTF8String];
1060 
1061  mGraphics->SetControlValueAfterTextEdit(txt);
1062  mGraphics->SetAllControlsDirty();
1063 
1064  [self endUserInput ];
1065 }
1066 
1067 - (IPopupMenu*) createPopupMenu: (IPopupMenu&) menu : (NSRect) bounds;
1068 {
1069  IGRAPHICS_MENU_RCVR* pDummyView = [[[IGRAPHICS_MENU_RCVR alloc] initWithFrame:bounds] autorelease];
1070  NSMenu* pNSMenu = [[[IGRAPHICS_MENU alloc] initWithIPopupMenuAndReceiver:&menu : pDummyView] autorelease];
1071  NSPoint wp = {bounds.origin.x, bounds.origin.y + bounds.size.height + 4};
1072 
1073  [pNSMenu popUpMenuPositioningItem:nil atLocation:wp inView:self];
1074 
1075  NSMenuItem* pChosenItem = [pDummyView menuItem];
1076  NSMenu* pChosenMenu = [pChosenItem menu];
1077  IPopupMenu* pIPopupMenu = [(IGRAPHICS_MENU*) pChosenMenu iPopupMenu];
1078 
1079  long chosenItemIdx = [pChosenMenu indexOfItem: pChosenItem];
1080 
1081  if (chosenItemIdx > -1 && pIPopupMenu)
1082  {
1083  pIPopupMenu->SetChosenItemIdx((int) chosenItemIdx);
1084  return pIPopupMenu;
1085  }
1086  else
1087  return nullptr;
1088 }
1089 
1090 - (void) createTextEntry: (int) paramIdx : (const IText&) text : (const char*) str : (int) length : (NSRect) areaRect;
1091 {
1092  if (mTextFieldView)
1093  return;
1094 
1095  mTextFieldView = [[IGRAPHICS_TEXTFIELD alloc] initWithFrame: areaRect];
1096 
1097  if (text.mVAlign == EVAlign::Middle)
1098  {
1099  IGRAPHICS_TEXTFIELDCELL* pCell = [[IGRAPHICS_TEXTFIELDCELL alloc] initTextCell:@"textfield"];
1100  [mTextFieldView setCell: pCell];
1101  [mTextFieldView setEditable: TRUE];
1102  [mTextFieldView setDrawsBackground: TRUE];
1103  }
1104 
1105  CoreTextFontDescriptor* CTFontDescriptor = CoreTextHelpers::GetCTFontDescriptor(text, sFontDescriptorCache);
1106  double ratio = CTFontDescriptor->GetEMRatio() * mGraphics->GetDrawScale();
1107  NSFontDescriptor* fontDescriptor = (NSFontDescriptor*) CTFontDescriptor->GetDescriptor();
1108  NSFont* font = [NSFont fontWithDescriptor: fontDescriptor size: text.mSize * ratio];
1109  [mTextFieldView setFont: font];
1110 
1111  switch (text.mAlign)
1112  {
1113  case EAlign::Near:
1114  [mTextFieldView setAlignment: NSLeftTextAlignment];
1115  break;
1116  case EAlign::Center:
1117  [mTextFieldView setAlignment: NSCenterTextAlignment];
1118  break;
1119  case EAlign::Far:
1120  [mTextFieldView setAlignment: NSRightTextAlignment];
1121  break;
1122  default:
1123  break;
1124  }
1125 
1126  const IParam* pParam = paramIdx > kNoParameter ? mGraphics->GetDelegate()->GetParam(paramIdx) : nullptr;
1127 
1128  // set up formatter
1129  if (pParam)
1130  {
1131  NSMutableCharacterSet *characterSet = [[NSMutableCharacterSet alloc] init];
1132 
1133  switch ( pParam->Type() )
1134  {
1135  case IParam::kTypeEnum:
1136  case IParam::kTypeInt:
1137  case IParam::kTypeBool:
1138  [characterSet addCharactersInString:@"0123456789-+"];
1139  break;
1140  case IParam::kTypeDouble:
1141  [characterSet addCharactersInString:@"0123456789.-+"];
1142  break;
1143  default:
1144  break;
1145  }
1146 
1147  [mTextFieldView setFormatter:[[[IGRAPHICS_FORMATTER alloc] init] autorelease]];
1148  [[mTextFieldView formatter] setAcceptableCharacterSet:characterSet];
1149  [[mTextFieldView formatter] setMaximumLength:length];
1150  [characterSet release];
1151  }
1152 
1153  [[mTextFieldView cell] setLineBreakMode: NSLineBreakByTruncatingTail];
1154  [mTextFieldView setAllowsEditingTextAttributes:NO];
1155  [mTextFieldView setTextColor:ToNSColor(text.mTextEntryFGColor)];
1156  [mTextFieldView setBackgroundColor:ToNSColor(text.mTextEntryBGColor)];
1157 
1158  [mTextFieldView setStringValue: [NSString stringWithCString:str encoding:NSUTF8StringEncoding]];
1159 
1160 #ifndef COCOA_TEXTENTRY_BORDERED
1161  [mTextFieldView setBordered: NO];
1162  [mTextFieldView setFocusRingType:NSFocusRingTypeNone];
1163 #endif
1164 
1165  [mTextFieldView setDelegate: self];
1166 
1167  [self addSubview: mTextFieldView];
1168  NSWindow* pWindow = [self window];
1169  [pWindow makeKeyAndOrderFront:nil];
1170  [pWindow makeFirstResponder: mTextFieldView];
1171 }
1172 
1173 - (void) endUserInput
1174 {
1175  [mTextFieldView setDelegate: nil];
1176  [mTextFieldView removeFromSuperview];
1177 
1178  NSWindow* pWindow = [self window];
1179  [pWindow makeFirstResponder: self];
1180 
1181  mTextFieldView = nullptr;
1182 }
1183 
1184 - (BOOL) promptForColor: (IColor&) color : (IColorPickerHandlerFunc) func;
1185 {
1186  NSColorPanel* colorPanel = [NSColorPanel sharedColorPanel];
1187  mColorPickerFunc = func;
1188 
1189  [colorPanel setTarget:self];
1190  [colorPanel setShowsAlpha: TRUE];
1191  [colorPanel setAction:@selector(onColorPicked:)];
1192  [colorPanel setColor:ToNSColor(color)];
1193  [colorPanel orderFront:nil];
1194 
1195  return colorPanel != nil;
1196 }
1197 
1198 - (void) onColorPicked: (NSColorPanel*) pColorPanel
1199 {
1200  mColorPickerFunc(FromNSColor([pColorPanel color]));
1201 }
1202 
1203 - (NSString*) view: (NSView*) pView stringForToolTip: (NSToolTipTag) tag point: (NSPoint) point userData: (void*) pData
1204 {
1205  int c = mGraphics ? GetMouseOver(mGraphics) : -1;
1206  if (c < 0) return @"";
1207 
1208  const char* tooltip = mGraphics->GetControl(c)->GetTooltip();
1209  return CStringHasContents(tooltip) ? [NSString stringWithCString:tooltip encoding:NSUTF8StringEncoding] : @"";
1210 }
1211 
1212 - (void) registerToolTip: (IRECT&) bounds
1213 {
1214  [self addToolTipRect: ToNSRect(mGraphics, bounds) owner: self userData: nil];
1215 }
1216 
1217 - (NSDragOperation) draggingEntered: (id<NSDraggingInfo>) sender
1218 {
1219  NSPasteboard *pPasteBoard = [sender draggingPasteboard];
1220 
1221  if ([[pPasteBoard types] containsObject:NSFilenamesPboardType])
1222  return NSDragOperationGeneric;
1223  else
1224  return NSDragOperationNone;
1225 }
1226 
1227 - (BOOL) performDragOperation: (id<NSDraggingInfo>) sender
1228 {
1229  NSPasteboard *pPasteBoard = [sender draggingPasteboard];
1230 
1231  if ([[pPasteBoard types] containsObject:NSFilenamesPboardType])
1232  {
1233  NSArray *pFiles = [pPasteBoard propertyListForType:NSFilenamesPboardType];
1234  NSString *pFirstFile = [pFiles firstObject];
1235  NSPoint point = [sender draggingLocation];
1236  NSPoint relativePoint = [self convertPoint: point fromView:nil];
1237  // TODO - fix or remove these values
1238  float x = relativePoint.x;// - 2.f;
1239  float y = relativePoint.y;// - 3.f;
1240  mGraphics->OnDrop([pFirstFile UTF8String], x, y);
1241  }
1242 
1243  return YES;
1244 }
1245 
1246 #ifdef IGRAPHICS_METAL
1247 - (void) frameDidChange:(NSNotification*) pNotification
1248 {
1249  CGFloat scale = [[self window] backingScaleFactor];
1250 
1251  [(CAMetalLayer*)[self layer] setDrawableSize:CGSizeMake(self.frame.size.width * scale,
1252  self.frame.size.height * scale)];
1253 }
1254 #endif
1255 
1256 //- (void)windowResized: (NSNotification *) notification;
1257 //{
1258 // if(!mGraphics)
1259 // return;
1260 //
1261 // NSSize windowSize = [[self window] frame].size;
1262 // NSRect viewFrameInWindowCoords = [self convertRect: [self bounds] toView: nil];
1263 //
1264 // float width = windowSize.width - viewFrameInWindowCoords.origin.x;
1265 // float height = windowSize.height - viewFrameInWindowCoords.origin.y;
1266 //
1267 // float scaleX = width / mGraphics->Width();
1268 // float scaleY = height / mGraphics->Height();
1269 //
1270 // if(mGraphics->GetUIResizerMode() == EUIResizerMode::Scale)
1271 // mGraphics->Resize(width, height, mGraphics->GetDrawScale());
1272 // else // EUIResizerMode::Size
1273 // mGraphics->Resize(mGraphics->Width(), mGraphics->Height(), Clip(std::min(scaleX, scaleY), 0.1f, 10.f));
1274 //}
1275 //
1276 //- (void) windowFullscreened: (NSNotification*) pNotification;
1277 //{
1278 // NSSize windowSize = [[self window] frame].size;
1279 // NSRect viewFrameInWindowCoords = [self convertRect: [self bounds] toView: nil];
1280 //
1281 // float width = windowSize.width - viewFrameInWindowCoords.origin.x;
1282 // float height = windowSize.height - viewFrameInWindowCoords.origin.y;
1283 //
1284 // float scaleX = width / mGraphics->Width();
1285 // float scaleY = height / mGraphics->Height();
1286 //
1287 // if(mGraphics->GetUIResizerMode() == EUIResizerMode::Scale)
1288 // mGraphics->Resize(width, height, mGraphics->GetDrawScale());
1289 // else // EUIResizerMode::Size
1290 // mGraphics->Resize(mGraphics->Width(), mGraphics->Height(), Clip(std::min(scaleX, scaleY), 0.1f, 10.f));
1291 //}
1292 
1293 @end
1294 
1295 #if defined IGRAPHICS_IMGUI
1296 
1297 @implementation IGRAPHICS_IMGUIVIEW
1298 {
1299 }
1300 
1301 - (id) initWithIGraphicsView: (IGRAPHICS_VIEW*) pView;
1302 {
1303  mView = pView;
1304  self = [super initWithFrame:[pView frame] device: MTLCreateSystemDefaultDevice()];
1305  if(self) {
1306  _commandQueue = [self.device newCommandQueue];
1307  self.layer.opaque = NO;
1308  }
1309 
1310  return self;
1311 }
1312 
1313 - (void) drawRect: (NSRect) dirtyRect
1314 {
1315  id<MTLCommandBuffer> commandBuffer = [self.commandQueue commandBuffer];
1316 
1317  MTLRenderPassDescriptor *renderPassDescriptor = self.currentRenderPassDescriptor;
1318  if (renderPassDescriptor != nil)
1319  {
1320  renderPassDescriptor.colorAttachments[0].clearColor = MTLClearColorMake(0,0,0,0);
1321 
1322  id <MTLRenderCommandEncoder> renderEncoder = [commandBuffer renderCommandEncoderWithDescriptor:renderPassDescriptor];
1323  [renderEncoder pushDebugGroup:@"ImGui IGraphics"];
1324 
1325  ImGui_ImplMetal_NewFrame(renderPassDescriptor);
1326 
1327  mView->mGraphics->mImGuiRenderer->DoFrame();
1328 
1329  ImDrawData *drawData = ImGui::GetDrawData();
1330  ImGui_ImplMetal_RenderDrawData(drawData, commandBuffer, renderEncoder);
1331 
1332  [renderEncoder popDebugGroup];
1333  [renderEncoder endEncoding];
1334 
1335  [commandBuffer presentDrawable:self.currentDrawable];
1336  }
1337  [commandBuffer commit];
1338 }
1339 
1340 @end
1341 
1342 #endif
Used to manage a list of rectangular areas and optimize them for drawing to the screen.
Used to manage a rectangular area, independent of draw class/platform.
Used to manage mouse modifiers i.e.
IPlug&#39;s parameter class.
Used to manage color data, independent of draw class/platform.
A class to specify an item of a pop up menu.
IPlug&#39;s parameter class.
This file contains the base IControl implementation, along with some base classes for specific types ...
IPlug logging a.k.a tracing functionality.
IGraphics platform class for macOS.
Definition: IGraphicsMac.h:23
A class for setting the contents of a pop up menu.
IText is used to manage font and text/text entry style for a piece of text on the UI...
Used to group mouse coordinates with mouse modifier information.
void Clear()
Set all fields of this IRECT to 0.
EParamType Type() const
Get the parameter&#39;s type.
Used for key press info, such as ASCII representation, virtual key (mapped to win32 codes) and modifi...
Definition: IPlugStructs.h:612