11 #import <QuartzCore/QuartzCore.h> 13 #if defined IGRAPHICS_METAL 14 #import <Metal/Metal.h> 17 #if defined IGRAPHICS_IMGUI 18 #import <Metal/Metal.h> 20 #import "imgui_impl_metal.h" 25 #import "IGraphicsMac_view.h" 30 using namespace iplug;
31 using namespace igraphics;
33 static int MacKeyCodeToVK(
int code)
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;
86 static int MacKeyEventToVK(NSEvent* pEvent,
int& flag)
90 const NSInteger mod = [pEvent modifierFlags];
92 if (mod & NSShiftKeyMask) flag |= kFSHIFT;
93 if (mod & NSCommandKeyMask) flag |= kFCONTROL;
94 if (mod & NSAlternateKeyMask) flag |= kFALT;
95 if ((mod & NSControlKeyMask) ) flag |= kFLWIN;
97 int rawcode = [pEvent keyCode];
99 code = MacKeyCodeToVK(rawcode);
100 if (code == kVK_NONE)
102 NSString *str = NULL;
104 if (!str || ![str length]) str = [pEvent charactersIgnoringModifiers];
106 if (!str || ![str length])
110 code = 1024 + rawcode;
116 code = [str characterAtIndex:0];
117 if (code >= NSF1FunctionKey && code <= NSF24FunctionKey)
120 code += kVK_F1 - NSF1FunctionKey;
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;
133 if (code == 8) code =
'\b';
136 if (!(flag & kFVIRTKEY)) flag &= ~kFSHIFT;
141 @implementation IGRAPHICS_MENU_RCVR
143 - (NSMenuItem*) menuItem
148 - (void) onMenuSelection:(
id) sender
155 @implementation IGRAPHICS_MENU
157 - (id) initWithIPopupMenuAndReceiver: (
IPopupMenu*) pMenu : (NSView*) pView
159 [
self initWithTitle: @""];
161 NSMenuItem* nsMenuItem;
162 NSMutableString* nsMenuItemTitle;
164 [
self setAutoenablesItems:NO];
166 int numItems = pMenu->NItems();
168 for (
int i = 0; i < numItems; ++i)
172 nsMenuItemTitle = [[[NSMutableString alloc] initWithCString:pMenuItem->GetText() encoding:NSUTF8StringEncoding] autorelease];
174 if (pMenu->GetPrefix())
176 NSString* prefixString = 0;
178 switch (pMenu->GetPrefix())
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;
186 [nsMenuItemTitle insertString:prefixString atIndex:0];
189 if (pMenuItem->GetIsSeparator())
191 [
self addItem:[NSMenuItem separatorItem]];
193 else if (pMenuItem->GetSubmenu())
195 nsMenuItem = [
self addItemWithTitle:nsMenuItemTitle action:nil keyEquivalent:@""];
196 NSMenu* subMenu = [[IGRAPHICS_MENU alloc] initWithIPopupMenuAndReceiver:pMenuItem->GetSubmenu() :pView];
197 [
self setSubmenu: subMenu forItem:nsMenuItem];
202 nsMenuItem = [
self addItemWithTitle:nsMenuItemTitle action:@selector(onMenuSelection:) keyEquivalent:@""];
204 [nsMenuItem setTarget:pView];
207 if (!pMenuItem->GetIsSeparator())
209 [nsMenuItem setIndentationLevel:pMenuItem->GetIsTitle() ? 1 : 0 ];
210 [nsMenuItem setEnabled:pMenuItem->GetEnabled() ? YES : NO];
211 [nsMenuItem setState:pMenuItem->GetChecked() ? NSOnState : NSOffState];
227 @implementation IGRAPHICS_TEXTFIELD
229 - (bool) becomeFirstResponder;
231 bool success = [
super becomeFirstResponder];
234 NSTextView *textField = (NSTextView*) [
self currentEditor];
235 if( [textField respondsToSelector:
@selector(setInsertionPointColor:)] )
236 [textField setInsertionPointColor: [
self textColor]];
257 @implementation IGRAPHICS_TEXTFIELDCELL
259 - (NSRect) drawingRectForBounds: (NSRect) inRect
262 NSRect outRect = [
super drawingRectForBounds:inRect];
269 if (mIsEditingOrSelecting == NO)
272 NSSize textSize = [
self cellSize];
275 float heightDelta = outRect.size.height - textSize.height;
277 outRect.size.height -= heightDelta;
278 outRect.origin.y += (heightDelta / 2);
284 - (void) selectWithFrame: (NSRect) aRect inView: (NSView*) controlView editor: (NSText*) textObj delegate: (
id) anObject start: (NSInteger) selStart length: (NSInteger) selLength
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;
292 - (void) editWithFrame: (NSRect) aRect inView: (NSView*) controlView editor: (NSText*) textObj delegate: (
id) anObject event: (NSEvent*) theEvent
294 aRect = [
self drawingRectForBounds:aRect];
295 mIsEditingOrSelecting = YES;
296 [
super editWithFrame:aRect inView:controlView editor:textObj delegate:anObject event:theEvent];
297 mIsEditingOrSelecting = NO;
302 @implementation IGRAPHICS_FORMATTER
306 [filterCharacterSet release];
310 - (BOOL) isPartialStringValid:(NSString*) partialString newEditingString:(NSString**) newString errorDescription:(NSString**) error
312 if (filterCharacterSet != nil)
315 int len = (int) [partialString length];
317 for (i = 0; i < len; i++)
319 if (![filterCharacterSet characterIsMember:[partialString characterAtIndex:i]])
328 if ([partialString length] > maxLength)
334 if (maxValue && [partialString intValue] > maxValue)
342 - (void) setAcceptableCharacterSet: (NSCharacterSet*) inCharacterSet
344 [inCharacterSet retain];
345 [filterCharacterSet release];
346 filterCharacterSet = inCharacterSet;
349 - (void) setMaximumLength: (
int) inLength
351 maxLength = inLength;
354 - (void) setMaximumValue: (
int) inValue
359 - (NSString*) stringForObjectValue: (
id) anObject
361 if ([anObject isKindOfClass:[NSString
class]])
369 - (BOOL) getObjectValue: (
id*) anObject forString:(NSString*) string errorDescription: (NSString **) error
371 if (anObject &&
string)
373 *anObject = [NSString stringWithString:string];
382 extern StaticStorage<CoreTextFontDescriptor> sFontDescriptorCache;
384 @implementation IGRAPHICS_VIEW
390 mGraphics = pGraphics;
391 NSRect r = NSMakeRect(0.f, 0.f, (
float) pGraphics->WindowWidth(), (float) pGraphics->WindowHeight());
392 self = [
super initWithFrame:r];
394 mMouseOutDuringDrag =
false;
396 self.wantsLayer = YES;
397 self.layer.opaque = YES;
398 self.layerContentsRedrawPolicy = NSViewLayerContentsRedrawDuringViewResize;
400 [
self registerForDraggedTypes:[NSArray arrayWithObjects: NSFilenamesPboardType, nil]];
402 #if defined IGRAPHICS_METAL 403 self.layer = [CAMetalLayer new];
404 [(CAMetalLayer*)[
self layer] setPixelFormat:MTLPixelFormatBGRA8Unorm];
405 ((CAMetalLayer*)
self.layer).device = MTLCreateSystemDefaultDevice();
407 #elif defined IGRAPHICS_GL 408 NSOpenGLPixelFormatAttribute profile = NSOpenGLProfileVersionLegacy;
409 #if defined IGRAPHICS_GL3 410 profile = (NSOpenGLPixelFormatAttribute)NSOpenGLProfileVersion3_2Core;
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
423 NSOpenGLPixelFormat* pPixelFormat = [[NSOpenGLPixelFormat alloc] initWithAttributes:attrs];
424 NSOpenGLContext* pGLContext = [[NSOpenGLContext alloc] initWithFormat:pPixelFormat shareContext:nil];
430 self.pixelFormat = pPixelFormat;
431 self.openGLContext = pGLContext;
432 self.wantsBestResolutionOpenGLSurface = YES;
433 #endif // IGRAPHICS_GL 435 #if !defined IGRAPHICS_GL 443 - (void) prepareOpenGL
445 [
super prepareOpenGL];
447 [[
self openGLContext] makeCurrentContext];
451 [[
self openGLContext] setValues:&swapInt forParameter:NSOpenGLCPSwapInterval];
457 static CVReturn displayLinkCallback(CVDisplayLinkRef displayLink,
const CVTimeStamp* now,
const CVTimeStamp* outputTime, CVOptionFlags flagsIn, CVOptionFlags* flagsOut,
void* displayLinkContext)
459 dispatch_source_t source = (dispatch_source_t) displayLinkContext;
460 dispatch_source_merge_data(source, 1);
462 return kCVReturnSuccess;
465 - (void) onTimer: (NSTimer*) pTimer
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, ^(){
477 dispatch_resume(mDisplaySource);
481 cvReturn = CVDisplayLinkCreateWithActiveCGDisplays(&mDisplayLink);
483 assert(cvReturn == kCVReturnSuccess);
485 cvReturn = CVDisplayLinkSetOutputCallback(mDisplayLink, &displayLinkCallback, (
void*) mDisplaySource);
486 assert(cvReturn == kCVReturnSuccess);
489 CGLContextObj cglContext = [[
self openGLContext] CGLContextObj];
490 CGLPixelFormatObj cglPixelFormat = [[
self pixelFormat] CGLPixelFormatObj];
491 CVDisplayLinkSetCurrentCGDisplayFromOpenGLContext(mDisplayLink, cglContext, cglPixelFormat);
494 CGDirectDisplayID viewDisplayID =
495 (CGDirectDisplayID) [
self.window.screen.deviceDescription[
@"NSScreenNumber"] unsignedIntegerValue];;
497 cvReturn = CVDisplayLinkSetCurrentCGDisplay(mDisplayLink, viewDisplayID);
499 assert(cvReturn == kCVReturnSuccess);
501 CVDisplayLinkStart(mDisplayLink);
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];
511 #ifdef IGRAPHICS_CVDISPLAYLINK 512 CVDisplayLinkStop(mDisplayLink);
513 dispatch_source_cancel(mDisplaySource);
514 CVDisplayLinkRelease(mDisplayLink);
524 if([NSColorPanel sharedColorPanelExists])
525 [[NSColorPanel sharedColorPanel] close];
527 mColorPickerFunc =
nullptr;
528 [mMoveCursor release];
529 [mTrackingArea release];
530 [[NSNotificationCenter defaultCenter] removeObserver:self];
537 return mGraphics ? YES : NO;
545 - (BOOL) acceptsFirstResponder
550 - (BOOL) acceptsFirstMouse: (NSEvent*) pEvent
555 - (void) viewDidMoveToWindow
557 NSWindow* pWindow = [
self window];
561 [pWindow makeFirstResponder: self];
562 [pWindow setAcceptsMouseMovedEvents: YES];
564 CGFloat newScale = [pWindow backingScaleFactor];
567 mGraphics->SetScreenScale(newScale);
569 #ifdef IGRAPHICS_METAL 570 [[NSNotificationCenter defaultCenter] addObserver:self
571 selector:@selector(frameDidChange:)
572 name:NSViewFrameDidChangeNotification
590 - (void) viewDidChangeBackingProperties:(NSNotification*) pNotification
592 NSWindow* pWindow = [
self window];
597 CGFloat newScale = [pWindow backingScaleFactor];
599 mGraphics->SetPlatformContext(
nullptr);
601 if (newScale != mGraphics->GetScreenScale())
602 mGraphics->SetScreenScale(newScale);
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)];
612 - (CGContextRef) getCGContextRef
614 CGContextRef pCGC = [NSGraphicsContext currentContext].CGContext;
615 return [NSGraphicsContext graphicsContextWithCGContext: pCGC flipped: YES].CGContext;
619 - (void) drawRect: (NSRect) bounds
621 #if !defined IGRAPHICS_GL && !defined IGRAPHICS_METAL 624 mGraphics->SetPlatformContext([
self getCGContextRef]);
626 if (mGraphics->GetPlatformContext())
630 [
self getRectsBeingDrawn:&rects count:&numRects];
633 for (
int i = 0; i < numRects; i++)
634 drawRects.Add(ToIRECT(mGraphics, &rects[i]));
636 mGraphics->Draw(drawRects);
639 #else // this gets called on resize 649 if (mGraphics->IsDirty(mDirtyRects))
651 mGraphics->SetAllControlsClean();
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))];
658 [[
self openGLContext] makeCurrentContext];
661 mGraphics->Draw(mDirtyRects);
664 [[
self openGLContext] flushBuffer];
669 - (void) getMouseXY: (NSEvent*) pEvent : (
float&) x : (
float&) y
673 NSPoint pt = [
self convertPoint:[pEvent locationInWindow] fromView:nil];
674 x = pt.x / mGraphics->GetDrawScale();
675 y = pt.y / mGraphics->GetDrawScale();
677 mGraphics->DoCursorLock(x, y, mPrevX, mPrevY);
678 mGraphics->SetTabletInput(pEvent.subtype == NSTabletPointEventSubtype);
682 - (
IMouseInfo) getMouseLeft: (NSEvent*) pEvent
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));
692 - (
IMouseInfo) getMouseRight: (NSEvent*) pEvent
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));
702 - (void) updateTrackingAreas
704 [
super updateTrackingAreas];
706 if (mTrackingArea != nil)
708 [
self removeTrackingArea:mTrackingArea];
709 [mTrackingArea release];
712 int opts = (NSTrackingMouseEnteredAndExited | NSTrackingActiveAlways);
713 mTrackingArea = [ [NSTrackingArea alloc] initWithRect:[
self bounds] options:opts owner:self userInfo:nil];
714 [
self addTrackingArea:mTrackingArea];
717 - (void) mouseEntered: (NSEvent*) pEvent
719 mMouseOutDuringDrag =
false;
723 mGraphics->OnSetCursor();
727 - (void) mouseExited: (NSEvent*) pEvent
731 if (!mGraphics->ControlIsCaptured())
733 mGraphics->OnMouseOut();
737 mMouseOutDuringDrag =
true;
742 - (void) mouseDown: (NSEvent*) pEvent
747 if (([pEvent clickCount] - 1) % 2)
749 mGraphics->OnMouseDblClick(info.x, info.y, info.ms);
753 std::vector<IMouseInfo> list {info};
754 mGraphics->OnMouseDown(list);
759 - (void) mouseUp: (NSEvent*) pEvent
764 std::vector<IMouseInfo> list {info};
765 mGraphics->OnMouseUp(list);
767 if (mMouseOutDuringDrag)
769 mGraphics->OnMouseOut();
770 mMouseOutDuringDrag =
false;
775 - (void) mouseDragged: (NSEvent*) pEvent
778 float prevX = mPrevX;
779 float prevY = mPrevY;
781 if (mGraphics && !mGraphics->IsInPlatformTextEntry())
783 info.dX = info.x - prevX;
784 info.dY = info.y - prevY;
785 std::vector<IMouseInfo> list {info};
786 mGraphics->OnMouseDrag(list);
790 - (void) rightMouseDown: (NSEvent*) pEvent
792 IMouseInfo info = [
self getMouseRight:pEvent];
795 std::vector<IMouseInfo> list {info};
796 mGraphics->OnMouseDown(list);
800 - (void) rightMouseUp: (NSEvent*) pEvent
802 IMouseInfo info = [
self getMouseRight:pEvent];
805 std::vector<IMouseInfo> list {info};
806 mGraphics->OnMouseUp(list);
810 - (void) rightMouseDragged: (NSEvent*) pEvent
813 float prevX = mPrevX;
814 float prevY = mPrevY;
815 IMouseInfo info = [
self getMouseRight:pEvent];
817 if (mGraphics && !mTextFieldView)
819 info.dX = info.x - prevX;
820 info.dY = info.y - prevY;
821 std::vector<IMouseInfo> list {info};
822 mGraphics->OnMouseDrag(list);
826 - (void) mouseMoved: (NSEvent*) pEvent
830 mGraphics->OnMouseOver(info.x, info.y, info.ms);
833 - (void) keyDown: (NSEvent*) pEvent
836 int code = MacKeyEventToVK(pEvent, flag);
837 NSString *s = [pEvent charactersIgnoringModifiers];
842 c = [s characterAtIndex:0];
844 if(!static_cast<bool>(flag & kFVIRTKEY))
850 WDL_MakeUTFChar(utf8, c, 4);
852 IKeyPress keyPress {utf8, code,
static_cast<bool>(flag & kFSHIFT),
853 static_cast<bool>(flag & kFCONTROL),
854 static_cast<bool>(flag & kFALT)};
856 bool handle = mGraphics->OnKeyDown(mPrevX, mPrevY, keyPress);
860 [[
self nextResponder] keyDown:pEvent];
864 - (void) keyUp: (NSEvent*) pEvent
867 int code = MacKeyEventToVK(pEvent, flag);
868 NSString *s = [pEvent charactersIgnoringModifiers];
873 c = [s characterAtIndex:0];
875 if(!static_cast<bool>(flag & kFVIRTKEY))
881 WDL_MakeUTFChar(utf8, c, 4);
883 IKeyPress keyPress {utf8, code,
static_cast<bool>(flag & kFSHIFT),
884 static_cast<bool>(flag & kFCONTROL),
885 static_cast<bool>(flag & kFALT)};
887 bool handle = mGraphics->OnKeyUp(mPrevX, mPrevY, keyPress);
891 [[
self nextResponder] keyUp:pEvent];
895 - (void) scrollWheel: (NSEvent*) pEvent
897 if (mTextFieldView) [
self endUserInput ];
899 float d = [pEvent deltaY];
901 mGraphics->OnMouseWheel(info.x, info.y, info.ms, d);
904 static void MakeCursorFromName(NSCursor*& cursor,
const char *name)
907 const char* basePath =
"/System/Library/Frameworks/ApplicationServices.framework/Versions/A/Frameworks/HIServices.framework/Versions/A/Resources/cursors/";
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]];
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);
927 for (
int scale = 1; scale <= 4; 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];
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);
945 NSBitmapImageRep *rep = [[NSBitmapImageRep alloc] initWithCGImage:shadowCGImage];
946 [rep setSize:[fileImage size]];
947 [cursorImage addRepresentation:rep];
951 CGContextRelease(shadowContext);
952 CGImageRelease(shadowCGImage);
956 cursor = [[NSCursor alloc] initWithImage:cursorImage hotSpot:NSMakePoint(hotX, hotY)];
959 [cursorImage release];
961 CGColorRelease(shadowColor);
964 - (void) setMouseCursor: (ECursor) cursorType
966 NSCursor* pCursor =
nullptr;
968 bool helpCurrent =
false;
969 bool helpRequested =
false;
973 case ECursor::ARROW: pCursor = [NSCursor arrowCursor];
break;
974 case ECursor::IBEAM: pCursor = [NSCursor IBeamCursor];
break;
976 if ([NSCursor respondsToSelector:
@selector(busyButClickableCursor)])
977 pCursor = [NSCursor performSelector:@selector(busyButClickableCursor)];
979 case ECursor::CROSS: pCursor = [NSCursor crosshairCursor];
break;
980 case ECursor::UPARROW:
981 if ([NSCursor respondsToSelector:
@selector(_windowResizeNorthCursor)])
982 pCursor = [NSCursor performSelector:@selector(_windowResizeNorthCursor)];
984 pCursor = [NSCursor resizeUpCursor];
986 case ECursor::SIZENWSE:
987 if ([NSCursor respondsToSelector:
@selector(_windowResizeNorthWestSouthEastCursor)])
988 pCursor = [NSCursor performSelector:@selector(_windowResizeNorthWestSouthEastCursor)];
990 case ECursor::SIZENESW:
991 if ([NSCursor respondsToSelector:
@selector(_windowResizeNorthEastSouthWestCursor)])
992 pCursor = [NSCursor performSelector:@selector(_windowResizeNorthEastSouthWestCursor)];
994 case ECursor::SIZEWE:
995 if ([NSCursor respondsToSelector:
@selector(_windowResizeEastWestCursor)])
996 pCursor = [NSCursor performSelector:@selector(_windowResizeEastWestCursor)];
998 pCursor = [NSCursor resizeLeftRightCursor];
1000 case ECursor::SIZENS:
1001 if ([NSCursor respondsToSelector:
@selector(_windowResizeNorthSouthCursor)])
1002 pCursor = [NSCursor performSelector:@selector(_windowResizeNorthSouthCursor)];
1004 pCursor = [NSCursor resizeUpDownCursor];
1006 case ECursor::SIZEALL:
1009 MakeCursorFromName(mMoveCursor,
"move");
1010 pCursor = mMoveCursor;
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)];
1020 if ([NSCursor respondsToSelector:
@selector(_helpCursor)])
1021 pCursor = [NSCursor performSelector:@selector(_helpCursor)];
1022 helpRequested =
true;
1024 default: pCursor = [NSCursor arrowCursor];
break;
1027 if ([NSCursor respondsToSelector:
@selector(helpCursorShown)])
1028 helpCurrent = [NSCursor performSelector:@selector(helpCursorShown)];
1030 if (helpCurrent && !helpRequested)
1033 #pragma clang diagnostic push 1034 #pragma clang diagnostic ignored "-Wobjc-method-access" 1035 [NSCursor _setHelpCursor : false];
1036 #pragma clang diagnostic pop 1040 pCursor = [NSCursor arrowCursor];
1045 - (void) removeFromSuperview
1048 [
self endUserInput ];
1050 mGraphics->SetPlatformContext(
nullptr);
1053 mGraphics->GetDelegate()->CloseWindow();
1054 [
super removeFromSuperview];
1057 - (void) controlTextDidEndEditing: (NSNotification*) aNotification
1059 char* txt = (
char*)[[mTextFieldView stringValue] UTF8String];
1061 mGraphics->SetControlValueAfterTextEdit(txt);
1062 mGraphics->SetAllControlsDirty();
1064 [
self endUserInput ];
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};
1073 [pNSMenu popUpMenuPositioningItem:nil atLocation:wp inView:self];
1075 NSMenuItem* pChosenItem = [pDummyView menuItem];
1076 NSMenu* pChosenMenu = [pChosenItem menu];
1077 IPopupMenu* pIPopupMenu = [(IGRAPHICS_MENU*) pChosenMenu iPopupMenu];
1079 long chosenItemIdx = [pChosenMenu indexOfItem: pChosenItem];
1081 if (chosenItemIdx > -1 && pIPopupMenu)
1083 pIPopupMenu->SetChosenItemIdx((
int) chosenItemIdx);
1090 - (void) createTextEntry: (
int) paramIdx : (const
IText&) text : (const
char*) str : (
int) length : (NSRect) areaRect;
1095 mTextFieldView = [[IGRAPHICS_TEXTFIELD alloc] initWithFrame: areaRect];
1097 if (text.mVAlign == EVAlign::Middle)
1099 IGRAPHICS_TEXTFIELDCELL* pCell = [[IGRAPHICS_TEXTFIELDCELL alloc] initTextCell:@"textfield"];
1100 [mTextFieldView setCell: pCell];
1101 [mTextFieldView setEditable: TRUE];
1102 [mTextFieldView setDrawsBackground: TRUE];
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];
1111 switch (text.mAlign)
1114 [mTextFieldView setAlignment: NSLeftTextAlignment];
1116 case EAlign::Center:
1117 [mTextFieldView setAlignment: NSCenterTextAlignment];
1120 [mTextFieldView setAlignment: NSRightTextAlignment];
1126 const IParam* pParam = paramIdx > kNoParameter ? mGraphics->GetDelegate()->GetParam(paramIdx) :
nullptr;
1131 NSMutableCharacterSet *characterSet = [[NSMutableCharacterSet alloc] init];
1133 switch ( pParam->
Type() )
1135 case IParam::kTypeEnum:
1136 case IParam::kTypeInt:
1137 case IParam::kTypeBool:
1138 [characterSet addCharactersInString:@"0123456789-+"];
1140 case IParam::kTypeDouble:
1141 [characterSet addCharactersInString:@"0123456789.-+"];
1147 [mTextFieldView setFormatter:[[[IGRAPHICS_FORMATTER alloc] init] autorelease]];
1148 [[mTextFieldView formatter] setAcceptableCharacterSet:characterSet];
1149 [[mTextFieldView formatter] setMaximumLength:length];
1150 [characterSet release];
1153 [[mTextFieldView cell] setLineBreakMode: NSLineBreakByTruncatingTail];
1154 [mTextFieldView setAllowsEditingTextAttributes:NO];
1155 [mTextFieldView setTextColor:ToNSColor(text.mTextEntryFGColor)];
1156 [mTextFieldView setBackgroundColor:ToNSColor(text.mTextEntryBGColor)];
1158 [mTextFieldView setStringValue: [NSString stringWithCString:str encoding:NSUTF8StringEncoding]];
1160 #ifndef COCOA_TEXTENTRY_BORDERED 1161 [mTextFieldView setBordered: NO];
1162 [mTextFieldView setFocusRingType:NSFocusRingTypeNone];
1165 [mTextFieldView setDelegate: self];
1167 [
self addSubview: mTextFieldView];
1168 NSWindow* pWindow = [
self window];
1169 [pWindow makeKeyAndOrderFront:nil];
1170 [pWindow makeFirstResponder: mTextFieldView];
1173 - (void) endUserInput
1175 [mTextFieldView setDelegate: nil];
1176 [mTextFieldView removeFromSuperview];
1178 NSWindow* pWindow = [
self window];
1179 [pWindow makeFirstResponder: self];
1181 mTextFieldView =
nullptr;
1184 - (BOOL) promptForColor: (
IColor&) color : (IColorPickerHandlerFunc) func;
1186 NSColorPanel* colorPanel = [NSColorPanel sharedColorPanel];
1187 mColorPickerFunc = func;
1189 [colorPanel setTarget:self];
1190 [colorPanel setShowsAlpha: TRUE];
1191 [colorPanel setAction:@selector(onColorPicked:)];
1192 [colorPanel setColor:ToNSColor(color)];
1193 [colorPanel orderFront:nil];
1195 return colorPanel != nil;
1198 - (void) onColorPicked: (NSColorPanel*) pColorPanel
1200 mColorPickerFunc(FromNSColor([pColorPanel color]));
1203 - (NSString*) view: (NSView*) pView stringForToolTip: (NSToolTipTag) tag point: (NSPoint) point userData: (
void*) pData
1205 int c = mGraphics ? GetMouseOver(mGraphics) : -1;
1206 if (c < 0)
return @"";
1208 const char* tooltip = mGraphics->GetControl(c)->GetTooltip();
1209 return CStringHasContents(tooltip) ? [NSString stringWithCString:tooltip encoding:NSUTF8StringEncoding] :
@"";
1212 - (void) registerToolTip: (
IRECT&) bounds
1214 [
self addToolTipRect: ToNSRect(mGraphics, bounds) owner: self userData: nil];
1217 - (NSDragOperation) draggingEntered: (
id<NSDraggingInfo>) sender
1219 NSPasteboard *pPasteBoard = [sender draggingPasteboard];
1221 if ([[pPasteBoard types] containsObject:NSFilenamesPboardType])
1222 return NSDragOperationGeneric;
1224 return NSDragOperationNone;
1227 - (BOOL) performDragOperation: (
id<NSDraggingInfo>) sender
1229 NSPasteboard *pPasteBoard = [sender draggingPasteboard];
1231 if ([[pPasteBoard types] containsObject:NSFilenamesPboardType])
1233 NSArray *pFiles = [pPasteBoard propertyListForType:NSFilenamesPboardType];
1234 NSString *pFirstFile = [pFiles firstObject];
1235 NSPoint point = [sender draggingLocation];
1236 NSPoint relativePoint = [
self convertPoint: point fromView:nil];
1238 float x = relativePoint.x;
1239 float y = relativePoint.y;
1240 mGraphics->OnDrop([pFirstFile UTF8String], x, y);
1246 #ifdef IGRAPHICS_METAL 1247 - (void) frameDidChange:(NSNotification*) pNotification
1249 CGFloat scale = [[
self window] backingScaleFactor];
1251 [(CAMetalLayer*)[
self layer] setDrawableSize:CGSizeMake(self.frame.size.width * scale,
1252 self.frame.size.height * scale)];
1295 #if defined IGRAPHICS_IMGUI 1297 @implementation IGRAPHICS_IMGUIVIEW
1301 - (id) initWithIGraphicsView: (IGRAPHICS_VIEW*) pView;
1304 self = [
super initWithFrame:[pView frame] device: MTLCreateSystemDefaultDevice()];
1306 _commandQueue = [
self.device newCommandQueue];
1307 self.layer.opaque = NO;
1313 - (void) drawRect: (NSRect) dirtyRect
1315 id<MTLCommandBuffer> commandBuffer = [
self.commandQueue commandBuffer];
1317 MTLRenderPassDescriptor *renderPassDescriptor =
self.currentRenderPassDescriptor;
1318 if (renderPassDescriptor != nil)
1320 renderPassDescriptor.colorAttachments[0].clearColor = MTLClearColorMake(0,0,0,0);
1322 id <MTLRenderCommandEncoder> renderEncoder = [commandBuffer renderCommandEncoderWithDescriptor:renderPassDescriptor];
1323 [renderEncoder pushDebugGroup:@"ImGui IGraphics"];
1325 ImGui_ImplMetal_NewFrame(renderPassDescriptor);
1327 mView->mGraphics->mImGuiRenderer->DoFrame();
1329 ImDrawData *drawData = ImGui::GetDrawData();
1330 ImGui_ImplMetal_RenderDrawData(drawData, commandBuffer, renderEncoder);
1332 [renderEncoder popDebugGroup];
1333 [renderEncoder endEncoding];
1335 [commandBuffer presentDrawable:self.currentDrawable];
1337 [commandBuffer commit];
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's parameter class.
Used to manage color data, independent of draw class/platform.
IPlug'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.
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's type.
Used for key press info, such as ASCII representation, virtual key (mapped to win32 codes) and modifi...