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