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@implementation IGRAPHICS_MENU_RCVR
136
137- (NSMenuItem*) menuItem
138{
139 return nsMenuItem;
140}
141
142- (void) onMenuSelection:(id) sender
143{
144 nsMenuItem = sender;
145}
146
147@end
148
149@implementation IGRAPHICS_MENU
150
151- (id) initWithIPopupMenuAndReceiver: (IPopupMenu*) pMenu : (NSView*) pView
152{
153 [self initWithTitle: @""];
154
155 NSMenuItem* nsMenuItem = nil;
156 NSMutableString* nsMenuItemTitle = nil;
157
158 [self setAutoenablesItems:NO];
159
160 int numItems = pMenu->NItems();
161
162 for (int i = 0; i < numItems; ++i)
163 {
164 IPopupMenu::Item* pMenuItem = pMenu->GetItem(i);
165
166 nsMenuItemTitle = [[[NSMutableString alloc] initWithCString:pMenuItem->GetText() encoding:NSUTF8StringEncoding] autorelease];
167
168 if (pMenu->GetPrefix())
169 {
170 NSString* prefixString = 0;
171
172 switch (pMenu->GetPrefix())
173 {
174 case 0: prefixString = [NSString stringWithUTF8String:""]; break;
175 case 1: prefixString = [NSString stringWithFormat:@"%1d: ", i+1]; break;
176 case 2: prefixString = [NSString stringWithFormat:@"%02d: ", i+1]; break;
177 case 3: prefixString = [NSString stringWithFormat:@"%03d: ", i+1]; break;
178 }
179
180 [nsMenuItemTitle insertString:prefixString atIndex:0];
181 }
182
183 if (pMenuItem->GetIsSeparator())
184 {
185 [self addItem:[NSMenuItem separatorItem]];
186 }
187 else if (pMenuItem->GetSubmenu())
188 {
189 nsMenuItem = [self addItemWithTitle:nsMenuItemTitle action:nil keyEquivalent:@""];
190 NSMenu* subMenu = [[IGRAPHICS_MENU alloc] initWithIPopupMenuAndReceiver:pMenuItem->GetSubmenu() :pView];
191 [self setSubmenu: subMenu forItem:nsMenuItem];
192 [subMenu release];
193 }
194 else
195 {
196 nsMenuItem = [self addItemWithTitle:nsMenuItemTitle action:@selector(onMenuSelection:) keyEquivalent:@""];
197
198 [nsMenuItem setTarget:pView];
199 }
200
201 if (nsMenuItem && !pMenuItem->GetIsSeparator())
202 {
203 [nsMenuItem setIndentationLevel:pMenuItem->GetIsTitle() ? 1 : 0 ];
204 [nsMenuItem setEnabled:pMenuItem->GetEnabled() ? YES : NO];
205 [nsMenuItem setState:pMenuItem->GetChecked() ? NSOnState : NSOffState];
206 }
207 }
208
209 mIPopupMenu = pMenu;
210
211 return self;
212}
213
214- (IPopupMenu*) iPopupMenu
215{
216 return mIPopupMenu;
217}
218
219@end
220
221@implementation IGRAPHICS_TEXTFIELD
222
223- (bool) becomeFirstResponder;
224{
225 bool success = [super becomeFirstResponder];
226 if (success)
227 {
228 NSTextView *textField = (NSTextView*) [self currentEditor];
229 if( [textField respondsToSelector: @selector(setInsertionPointColor:)] )
230 [textField setInsertionPointColor: [self textColor]];
231 }
232 return success;
233}
234
235@end
236
237// IGRAPHICS_TEXTFIELDCELL based on...
238
239// https://red-sweater.com/blog/148/what-a-difference-a-cell-makes
240
241// This source code is provided to you compliments of Red Sweater Software under the license as described below. NOTE: This is the MIT License.
242//
243// Copyright (c) 2006 Red Sweater Software
244//
245// 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:
246//
247// The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
248//
249// 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.
250
251@implementation IGRAPHICS_TEXTFIELDCELL
252
253- (NSRect) drawingRectForBounds: (NSRect) inRect
254{
255 // Get the parent's idea of where we should draw
256 NSRect outRect = [super drawingRectForBounds:inRect];
257
258 // When the text field is being
259 // edited or selected, we have to turn off the magic because it screws up
260 // the configuration of the field editor. We sneak around this by
261 // intercepting selectWithFrame and editWithFrame and sneaking a
262 // reduced, centered rect in at the last minute.
263 if (mIsEditingOrSelecting == NO)
264 {
265 // Get our ideal size for current text
266 NSSize textSize = [self cellSize];
267
268 // Center that in the proposed rect
269 float heightDelta = outRect.size.height - textSize.height;
270
271 outRect.origin.x += 3;
272 outRect.size.width -= 6;
273
274 if (heightDelta > 0)
275 {
276 outRect.size.height -= heightDelta;
277 outRect.origin.y += (heightDelta / 2);
278 }
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
382extern 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
457static 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- (void) viewDidChangeEffectiveAppearance
546{
547 if (@available(macOS 10.14, *)) {
548 BOOL isDarkMode = [[[self effectiveAppearance] name] isEqualToString: (NSAppearanceNameDarkAqua)];
549 mGraphics->OnAppearanceChanged(isDarkMode ? EUIAppearance::Dark : EUIAppearance::Light);
550 }
551}
552
553- (BOOL) acceptsFirstResponder
554{
555 return YES;
556}
557
558- (BOOL) acceptsFirstMouse: (NSEvent*) pEvent
559{
560 return YES;
561}
562
563- (void) viewDidMoveToWindow
564{
565 NSWindow* pWindow = [self window];
566
567 if (pWindow)
568 {
569 [pWindow makeFirstResponder: self];
570 [pWindow setAcceptsMouseMovedEvents: YES];
571
572 CGFloat newScale = [pWindow backingScaleFactor];
573
574 if (mGraphics)
575 mGraphics->SetScreenScale(newScale);
576
577 #ifdef IGRAPHICS_METAL
578 [[NSNotificationCenter defaultCenter] addObserver:self
579 selector:@selector(frameDidChange:)
580 name:NSViewFrameDidChangeNotification
581 object:self];
582 #endif
583
584// [[NSNotificationCenter defaultCenter] addObserver:self
585// selector:@selector(windowResized:) name:NSWindowDidEndLiveResizeNotification
586// object:pWindow];
587//
588// [[NSNotificationCenter defaultCenter] addObserver:self
589// selector:@selector(windowFullscreened:) name:NSWindowDidEnterFullScreenNotification
590// object:pWindow];
591//
592// [[NSNotificationCenter defaultCenter] addObserver:self
593// selector:@selector(windowFullscreened:) name:NSWindowDidExitFullScreenNotification
594// object:pWindow];
595 }
596}
597
598- (void) viewDidChangeBackingProperties:(NSNotification*) pNotification
599{
600 NSWindow* pWindow = [self window];
601
602 if (!pWindow)
603 return;
604
605 CGFloat newScale = [pWindow backingScaleFactor];
606
607 mGraphics->SetPlatformContext(nullptr);
608
609 if (newScale != mGraphics->GetScreenScale())
610 mGraphics->SetScreenScale(newScale);
611
612#if defined IGRAPHICS_GL
613 self.layer.contentsScale = 1./newScale;
614#elif defined IGRAPHICS_METAL
615 [(CAMetalLayer*)[self layer] setDrawableSize:CGSizeMake(self.frame.size.width * newScale,
616 self.frame.size.height * newScale)];
617#endif
618}
619
620- (CGContextRef) getCGContextRef
621{
622 CGContextRef pCGC = [NSGraphicsContext currentContext].CGContext;
623 return [NSGraphicsContext graphicsContextWithCGContext: pCGC flipped: YES].CGContext;
624}
625
626// not called for layer backed views
627- (void) drawRect: (NSRect) bounds
628{
629 #if !defined IGRAPHICS_GL && !defined IGRAPHICS_METAL
630 if (mGraphics)
631 {
632 mGraphics->SetPlatformContext([self getCGContextRef]);
633
634 if (mGraphics->GetPlatformContext())
635 {
636 const NSRect *rects;
637 NSInteger numRects;
638 [self getRectsBeingDrawn:&rects count:&numRects];
639 IRECTList drawRects;
640
641 for (int i = 0; i < numRects; i++)
642 drawRects.Add(ToIRECT(mGraphics, &rects[i]));
643
644 mGraphics->Draw(drawRects);
645 }
646 }
647 #else // this gets called on resize
648 //TODO: set GL context/flush?
649 //mGraphics->Draw(mDirtyRects);
650 #endif
651}
652
653- (void) render
654{
655 mDirtyRects.Clear();
656
657 if (mGraphics->IsDirty(mDirtyRects))
658 {
659 mGraphics->SetAllControlsClean();
660
661 #if !defined IGRAPHICS_GL && !defined IGRAPHICS_METAL // for layer-backed views setNeedsDisplayInRect/drawRect is not called
662 for (int i = 0; i < mDirtyRects.Size(); i++)
663 [self setNeedsDisplayInRect:ToNSRect(mGraphics, mDirtyRects.Get(i))];
664 #else
665 #ifdef IGRAPHICS_GL
666 [[self openGLContext] makeCurrentContext];
667 #endif
668 // so just draw on each frame, if something is dirty
669 mGraphics->Draw(mDirtyRects);
670 #endif
671 #ifdef IGRAPHICS_GL
672 [[self openGLContext] flushBuffer];
673 #endif
674 }
675}
676
677- (void) getMouseXY: (NSEvent*) pEvent : (float&) x : (float&) y
678{
679 if (mGraphics)
680 {
681 NSPoint pt = [self convertPoint:[pEvent locationInWindow] fromView:nil];
682 x = pt.x / mGraphics->GetDrawScale();
683 y = pt.y / mGraphics->GetDrawScale();
684
685 mGraphics->DoCursorLock(x, y, mPrevX, mPrevY);
686 mGraphics->SetTabletInput(pEvent.subtype == NSTabletPointEventSubtype);
687 }
688}
689
690- (IMouseInfo) getMouseLeft: (NSEvent*) pEvent
691{
692 IMouseInfo info;
693 [self getMouseXY:pEvent : info.x : info.y];
694 int mods = (int) [pEvent modifierFlags];
695 info.ms = IMouseMod(true, (mods & NSCommandKeyMask), (mods & NSShiftKeyMask), (mods & NSControlKeyMask), (mods & NSAlternateKeyMask));
696
697 return info;
698}
699
700- (IMouseInfo) getMouseRight: (NSEvent*) pEvent
701{
702 IMouseInfo info;
703 [self getMouseXY:pEvent : info.x : info.y];
704 int mods = (int) [pEvent modifierFlags];
705 info.ms = IMouseMod(false, true, (mods & NSShiftKeyMask), (mods & NSControlKeyMask), (mods & NSAlternateKeyMask));
706
707 return info;
708}
709
710- (void) updateTrackingAreas
711{
712 [super updateTrackingAreas]; // This is needed to get mouseEntered and mouseExited
713
714 if (mTrackingArea != nil)
715 {
716 [self removeTrackingArea:mTrackingArea];
717 [mTrackingArea release];
718 }
719
720 int opts = (NSTrackingMouseEnteredAndExited | NSTrackingActiveAlways | NSTrackingEnabledDuringMouseDrag);
721 mTrackingArea = [ [NSTrackingArea alloc] initWithRect:[self bounds] options:opts owner:self userInfo:nil];
722 [self addTrackingArea:mTrackingArea];
723}
724
725- (void) mouseEntered: (NSEvent*) pEvent
726{
727 mMouseOutDuringDrag = false;
728
729 if (mGraphics)
730 {
731 mGraphics->OnSetCursor();
732 }
733}
734
735- (void) mouseExited: (NSEvent*) pEvent
736{
737 if (mGraphics)
738 {
739 if (!mGraphics->ControlIsCaptured())
740 {
741 mGraphics->OnMouseOut();
742 }
743 else
744 {
745 mMouseOutDuringDrag = true;
746 }
747 }
748}
749
750- (void) mouseDown: (NSEvent*) pEvent
751{
752 IMouseInfo info = [self getMouseLeft:pEvent];
753 if (mGraphics)
754 {
755 if (([pEvent clickCount] - 1) % 2)
756 {
757 mGraphics->OnMouseDblClick(info.x, info.y, info.ms);
758 }
759 else
760 {
761 std::vector<IMouseInfo> list {info};
762 mGraphics->OnMouseDown(list);
763 }
764 }
765}
766
767- (void) mouseUp: (NSEvent*) pEvent
768{
769 IMouseInfo info = [self getMouseLeft:pEvent];
770 if (mGraphics)
771 {
772 std::vector<IMouseInfo> list {info};
773 mGraphics->OnMouseUp(list);
774
775 if (mMouseOutDuringDrag)
776 {
777 mGraphics->OnMouseOut();
778 mMouseOutDuringDrag = false;
779 }
780 }
781}
782
783- (void) mouseDragged: (NSEvent*) pEvent
784{
785 // Cache previous values before retrieving the new mouse position (which will update them)
786 float prevX = mPrevX;
787 float prevY = mPrevY;
788 IMouseInfo info = [self getMouseLeft:pEvent];
789 if (mGraphics && !mGraphics->IsInPlatformTextEntry())
790 {
791 info.dX = info.x - prevX;
792 info.dY = info.y - prevY;
793 std::vector<IMouseInfo> list {info};
794 mGraphics->OnMouseDrag(list);
795 }
796}
797
798- (void) rightMouseDown: (NSEvent*) pEvent
799{
800 IMouseInfo info = [self getMouseRight:pEvent];
801 if (mGraphics)
802 {
803 if (([pEvent clickCount] - 1) % 2)
804 {
805 mGraphics->OnMouseDblClick(info.x, info.y, info.ms);
806 }
807 else
808 {
809 std::vector<IMouseInfo> list {info};
810 mGraphics->OnMouseDown(list);
811 }
812 }
813}
814
815- (void) rightMouseUp: (NSEvent*) pEvent
816{
817 IMouseInfo info = [self getMouseRight:pEvent];
818 if (mGraphics)
819 {
820 std::vector<IMouseInfo> list {info};
821 mGraphics->OnMouseUp(list);
822 }
823}
824
825- (void) rightMouseDragged: (NSEvent*) pEvent
826{
827 // Cache previous values before retrieving the new mouse position (which will update them)
828 float prevX = mPrevX;
829 float prevY = mPrevY;
830 IMouseInfo info = [self getMouseRight:pEvent];
831
832 if (mGraphics && !mTextFieldView)
833 {
834 info.dX = info.x - prevX;
835 info.dY = info.y - prevY;
836 std::vector<IMouseInfo> list {info};
837 mGraphics->OnMouseDrag(list);
838 }
839}
840
841- (void) mouseMoved: (NSEvent*) pEvent
842{
843 IMouseInfo info = [self getMouseLeft:pEvent];
844 if (mGraphics)
845 mGraphics->OnMouseOver(info.x, info.y, info.ms);
846}
847
848- (void) keyDown: (NSEvent*) pEvent
849{
850 int flag = 0;
851 int code = MacKeyEventToVK(pEvent, flag);
852 NSString *s = [pEvent charactersIgnoringModifiers];
853
854 unichar c = 0;
855
856 if ([s length] == 1)
857 c = [s characterAtIndex:0];
858
859 if(!static_cast<bool>(flag & kFVIRTKEY))
860 {
861 code = kVK_NONE;
862 }
863
864 char utf8[5];
865 WDL_MakeUTFChar(utf8, c, 4);
866
867 IKeyPress keyPress {utf8, code, static_cast<bool>(flag & kFSHIFT),
868 static_cast<bool>(flag & kFCONTROL),
869 static_cast<bool>(flag & kFALT)};
870
871 bool handle = mGraphics->OnKeyDown(mPrevX, mPrevY, keyPress);
872
873 if (!handle)
874 {
875 [[self nextResponder] keyDown:pEvent];
876 }
877}
878
879- (void) keyUp: (NSEvent*) pEvent
880{
881 int flag = 0;
882 int code = MacKeyEventToVK(pEvent, flag);
883 NSString *s = [pEvent charactersIgnoringModifiers];
884
885 unichar c = 0;
886
887 if ([s length] == 1)
888 c = [s characterAtIndex:0];
889
890 if(!static_cast<bool>(flag & kFVIRTKEY))
891 {
892 code = kVK_NONE;
893 }
894
895 char utf8[5];
896 WDL_MakeUTFChar(utf8, c, 4);
897
898 IKeyPress keyPress {utf8, code, static_cast<bool>(flag & kFSHIFT),
899 static_cast<bool>(flag & kFCONTROL),
900 static_cast<bool>(flag & kFALT)};
901
902 bool handle = mGraphics->OnKeyUp(mPrevX, mPrevY, keyPress);
903
904 if (!handle)
905 {
906 [[self nextResponder] keyUp:pEvent];
907 }
908}
909
910- (void) scrollWheel: (NSEvent*) pEvent
911{
912 if (mTextFieldView) [self endUserInput ];
913 IMouseInfo info = [self getMouseLeft:pEvent];
914 float d = [pEvent deltaY];
915 if (mGraphics)
916 mGraphics->OnMouseWheel(info.x, info.y, info.ms, d);
917}
918
919static void MakeCursorFromName(NSCursor*& cursor, const char *name)
920{
921 // get paths and intialise images etc.
922 const char* basePath = "/System/Library/Frameworks/ApplicationServices.framework/Versions/A/Frameworks/HIServices.framework/Versions/A/Resources/cursors/";
923
924 NSString* imagePath = [NSString stringWithFormat:@"%s%s/cursor.pdf", basePath, name];
925 NSString* infoPath = [NSString stringWithFormat:@"file:%s%s/info.plist", basePath, name];
926 NSImage* fileImage = [[NSImage alloc] initByReferencingFile: imagePath];
927 NSImage *cursorImage = [[NSImage alloc] initWithSize:[fileImage size]];
928 NSDictionary* info = [NSDictionary dictionaryWithContentsOfURL:[NSURL URLWithString:infoPath]];
929
930 // get info from dictionary
931 double hotX = [info[@"hotx-scaled"] doubleValue];
932 double hotY = [info[@"hoty-scaled"] doubleValue];
933 double blur = [info[@"blur"] doubleValue];
934 double offsetX = [info[@"shadowoffsetx"] doubleValue];
935 double offsetY = [info[@"shadowoffsety"] doubleValue];
936 double red = [info[@"shadowcolor"][0] doubleValue];
937 double green = [info[@"shadowcolor"][1] doubleValue];
938 double blue = [info[@"shadowcolor"][2] doubleValue];
939 double alpha = [info[@"shadowcolor"][3] doubleValue];
940 CGColorRef shadowColor = CGColorCreateGenericRGB(red, green, blue, alpha);
941
942 for (int scale = 1; scale <= 4; scale++)
943 {
944 // scale
945 NSAffineTransform* xform = [NSAffineTransform transform];
946 [xform scaleBy:scale];
947 id hints = @{ NSImageHintCTM: xform };
948 CGImageRef rasterCGImage = [fileImage CGImageForProposedRect:NULL context:nil hints:hints];
949
950 // apply shadow
951 size_t width = CGImageGetWidth(rasterCGImage);
952 size_t height = CGImageGetHeight(rasterCGImage);
953 CGSize offset = CGSize { static_cast<CGFloat>(offsetX * scale), static_cast<CGFloat>(offsetY * scale) };
954 CGContextRef shadowContext = CGBitmapContextCreate(NULL, width, height, CGImageGetBitsPerComponent(rasterCGImage), 0, CGImageGetColorSpace(rasterCGImage), CGImageGetBitmapInfo(rasterCGImage));
955 CGContextSetShadowWithColor(shadowContext, offset, blur * scale, shadowColor);
956 CGContextDrawImage(shadowContext, CGRectMake(0, 0, width, height), rasterCGImage);
957 CGImageRef shadowCGImage = CGBitmapContextCreateImage(shadowContext);
958
959 // add to cursor inmge
960 NSBitmapImageRep *rep = [[NSBitmapImageRep alloc] initWithCGImage:shadowCGImage];
961 [rep setSize:[fileImage size]];
962 [cursorImage addRepresentation:rep];
963
964 // release
965 [rep release];
966 CGContextRelease(shadowContext);
967 CGImageRelease(shadowCGImage);
968 }
969
970 // create cursor
971 cursor = [[NSCursor alloc] initWithImage:cursorImage hotSpot:NSMakePoint(hotX, hotY)];
972
973 // release
974 [cursorImage release];
975 [fileImage release];
976 CGColorRelease(shadowColor);
977}
978
979- (void) setMouseCursor: (ECursor) cursorType
980{
981 NSCursor* pCursor = nullptr;
982
983 bool helpCurrent = false;
984 bool helpRequested = false;
985
986 switch (cursorType)
987 {
988 case ECursor::ARROW: pCursor = [NSCursor arrowCursor]; break;
989 case ECursor::IBEAM: pCursor = [NSCursor IBeamCursor]; break;
990 case ECursor::WAIT:
991 if ([NSCursor respondsToSelector:@selector(busyButClickableCursor)])
992 pCursor = [NSCursor performSelector:@selector(busyButClickableCursor)];
993 break;
994 case ECursor::CROSS: pCursor = [NSCursor crosshairCursor]; break;
995 case ECursor::UPARROW:
996 if ([NSCursor respondsToSelector:@selector(_windowResizeNorthCursor)])
997 pCursor = [NSCursor performSelector:@selector(_windowResizeNorthCursor)];
998 else
999 pCursor = [NSCursor resizeUpCursor];
1000 break;
1001 case ECursor::SIZENWSE:
1002 if ([NSCursor respondsToSelector:@selector(_windowResizeNorthWestSouthEastCursor)])
1003 pCursor = [NSCursor performSelector:@selector(_windowResizeNorthWestSouthEastCursor)];
1004 break;
1005 case ECursor::SIZENESW:
1006 if ([NSCursor respondsToSelector:@selector(_windowResizeNorthEastSouthWestCursor)])
1007 pCursor = [NSCursor performSelector:@selector(_windowResizeNorthEastSouthWestCursor)];
1008 break;
1009 case ECursor::SIZEWE:
1010 if ([NSCursor respondsToSelector:@selector(_windowResizeEastWestCursor)])
1011 pCursor = [NSCursor performSelector:@selector(_windowResizeEastWestCursor)];
1012 else
1013 pCursor = [NSCursor resizeLeftRightCursor];
1014 break;
1015 case ECursor::SIZENS:
1016 if ([NSCursor respondsToSelector:@selector(_windowResizeNorthSouthCursor)])
1017 pCursor = [NSCursor performSelector:@selector(_windowResizeNorthSouthCursor)];
1018 else
1019 pCursor = [NSCursor resizeUpDownCursor];
1020 break;
1021 case ECursor::SIZEALL:
1022 {
1023 if (!mMoveCursor)
1024 MakeCursorFromName(mMoveCursor, "move");
1025 pCursor = mMoveCursor;
1026 break;
1027 }
1028 case ECursor::INO: pCursor = [NSCursor operationNotAllowedCursor]; break;
1029 case ECursor::HAND: pCursor = [NSCursor pointingHandCursor]; break;
1030 case ECursor::APPSTARTING:
1031 if ([NSCursor respondsToSelector:@selector(busyButClickableCursor)])
1032 pCursor = [NSCursor performSelector:@selector(busyButClickableCursor)];
1033 break;
1034 case ECursor::HELP:
1035 if ([NSCursor respondsToSelector:@selector(_helpCursor)])
1036 pCursor = [NSCursor performSelector:@selector(_helpCursor)];
1037 helpRequested = true;
1038 break;
1039 default: pCursor = [NSCursor arrowCursor]; break;
1040 }
1041
1042 if ([NSCursor respondsToSelector:@selector(helpCursorShown)])
1043 helpCurrent = [NSCursor performSelector:@selector(helpCursorShown)];
1044
1045 if (helpCurrent && !helpRequested)
1046 {
1047 // N.B. - suppress warnings for this call only
1048#pragma clang diagnostic push
1049#pragma clang diagnostic ignored "-Wobjc-method-access"
1050 [NSCursor _setHelpCursor : false];
1051#pragma clang diagnostic pop
1052 }
1053
1054 if (!pCursor)
1055 pCursor = [NSCursor arrowCursor];
1056
1057 [pCursor set];
1058}
1059
1060- (void) removeFromSuperview
1061{
1062 if (mTextFieldView)
1063 [self endUserInput ];
1064
1065 mGraphics->SetPlatformContext(nullptr);
1066
1067 //For some APIs (AUv2) this is where we know about the window being closed, close via delegate
1068 mGraphics->GetDelegate()->CloseWindow();
1069 [super removeFromSuperview];
1070}
1071
1072- (void) controlTextDidEndEditing: (NSNotification*) aNotification
1073{
1074 char* txt = (char*)[[mTextFieldView stringValue] UTF8String];
1075
1076 mGraphics->SetControlValueAfterTextEdit(txt);
1077 mGraphics->SetAllControlsDirty();
1078
1079 [self endUserInput ];
1080}
1081
1082- (IPopupMenu*) createPopupMenu: (IPopupMenu&) menu : (NSRect) bounds;
1083{
1084 IGRAPHICS_MENU_RCVR* pDummyView = [[[IGRAPHICS_MENU_RCVR alloc] initWithFrame:bounds] autorelease];
1085 NSMenu* pNSMenu = [[[IGRAPHICS_MENU alloc] initWithIPopupMenuAndReceiver:&menu : pDummyView] autorelease];
1086 NSPoint wp = {bounds.origin.x, bounds.origin.y + bounds.size.height + 4};
1087
1088 NSMenuItem* pSelectedItem = nil;
1089
1090 auto selectedItemIdx = menu.GetChosenItemIdx();
1091
1092 if (selectedItemIdx > -1)
1093 {
1094 pSelectedItem = [pNSMenu itemAtIndex:selectedItemIdx];
1095 }
1096
1097 if (pSelectedItem != nil)
1098 {
1099 wp = {bounds.origin.x, bounds.origin.y};
1100 }
1101
1102 [pNSMenu popUpMenuPositioningItem:pSelectedItem atLocation:wp inView:self];
1103
1104 NSMenuItem* pChosenItem = [pDummyView menuItem];
1105 NSMenu* pChosenMenu = [pChosenItem menu];
1106 IPopupMenu* pIPopupMenu = [(IGRAPHICS_MENU*) pChosenMenu iPopupMenu];
1107
1108 long chosenItemIdx = [pChosenMenu indexOfItem: pChosenItem];
1109
1110 if (chosenItemIdx > -1 && pIPopupMenu)
1111 {
1112 pIPopupMenu->SetChosenItemIdx((int) chosenItemIdx);
1113 return pIPopupMenu;
1114 }
1115 else
1116 return nullptr;
1117}
1118
1119- (void) createTextEntry: (int) paramIdx : (const IText&) text : (const char*) str : (int) length : (NSRect) areaRect;
1120{
1121 if (mTextFieldView)
1122 return;
1123
1124 mTextFieldView = [[IGRAPHICS_TEXTFIELD alloc] initWithFrame: areaRect];
1125
1126 if (text.mVAlign == EVAlign::Middle)
1127 {
1128 IGRAPHICS_TEXTFIELDCELL* pCell = [[IGRAPHICS_TEXTFIELDCELL alloc] initTextCell:@"textfield"];
1129 [mTextFieldView setCell: pCell];
1130 [mTextFieldView setEditable: TRUE];
1131 [mTextFieldView setDrawsBackground: TRUE];
1132 }
1133
1134 CoreTextFontDescriptor* CTFontDescriptor = CoreTextHelpers::GetCTFontDescriptor(text, sFontDescriptorCache);
1135 double ratio = CTFontDescriptor->GetEMRatio() * mGraphics->GetDrawScale();
1136 NSFontDescriptor* fontDescriptor = (NSFontDescriptor*) CTFontDescriptor->GetDescriptor();
1137 NSFont* font = [NSFont fontWithDescriptor: fontDescriptor size: text.mSize * ratio];
1138 [mTextFieldView setFont: font];
1139
1140 switch (text.mAlign)
1141 {
1142 case EAlign::Near:
1143 [mTextFieldView setAlignment: NSLeftTextAlignment];
1144 break;
1145 case EAlign::Center:
1146 [mTextFieldView setAlignment: NSCenterTextAlignment];
1147 break;
1148 case EAlign::Far:
1149 [mTextFieldView setAlignment: NSRightTextAlignment];
1150 break;
1151 default:
1152 break;
1153 }
1154
1155 const IParam* pParam = paramIdx > kNoParameter ? mGraphics->GetDelegate()->GetParam(paramIdx) : nullptr;
1156
1157 // set up formatter
1158 if (pParam)
1159 {
1160 NSMutableCharacterSet *characterSet = [[NSMutableCharacterSet alloc] init];
1161
1162 switch ( pParam->Type() )
1163 {
1164 case IParam::kTypeEnum:
1165 case IParam::kTypeInt:
1166 case IParam::kTypeBool:
1167 [characterSet addCharactersInString:@"0123456789-+"];
1168 break;
1169 case IParam::kTypeDouble:
1170 [characterSet addCharactersInString:@"0123456789.-+"];
1171 break;
1172 default:
1173 break;
1174 }
1175
1176 [mTextFieldView setFormatter:[[[IGRAPHICS_FORMATTER alloc] init] autorelease]];
1177 [[mTextFieldView formatter] setAcceptableCharacterSet:characterSet];
1178 [[mTextFieldView formatter] setMaximumLength:length];
1179 [characterSet release];
1180 }
1181
1182 [[mTextFieldView cell] setLineBreakMode: NSLineBreakByTruncatingTail];
1183 [mTextFieldView setAllowsEditingTextAttributes:NO];
1184 [mTextFieldView setTextColor:ToNSColor(text.mTextEntryFGColor)];
1185 [mTextFieldView setBackgroundColor:ToNSColor(text.mTextEntryBGColor)];
1186
1187 [mTextFieldView setStringValue: [NSString stringWithCString:str encoding:NSUTF8StringEncoding]];
1188
1189#ifndef COCOA_TEXTENTRY_BORDERED
1190 [mTextFieldView setBordered: NO];
1191 [mTextFieldView setFocusRingType:NSFocusRingTypeNone];
1192#endif
1193
1194 [mTextFieldView setDelegate: self];
1195
1196 [self addSubview: mTextFieldView];
1197 NSWindow* pWindow = [self window];
1198 [pWindow makeKeyAndOrderFront:nil];
1199 [pWindow makeFirstResponder: mTextFieldView];
1200}
1201
1202- (void) endUserInput
1203{
1204 [mTextFieldView setDelegate: nil];
1205 [mTextFieldView removeFromSuperview];
1206
1207 NSWindow* pWindow = [self window];
1208 [pWindow makeFirstResponder: self];
1209
1210 mTextFieldView = nullptr;
1211 mGraphics->ClearInTextEntryControl();
1212}
1213
1214- (BOOL) promptForColor: (IColor&) color : (IColorPickerHandlerFunc) func;
1215{
1216 NSColorPanel* colorPanel = [NSColorPanel sharedColorPanel];
1217 mColorPickerFunc = func;
1218
1219 [colorPanel setTarget:self];
1220 [colorPanel setShowsAlpha: TRUE];
1221 [colorPanel setAction:@selector(onColorPicked:)];
1222 [colorPanel setColor:ToNSColor(color)];
1223 [colorPanel orderFront:nil];
1224
1225 return colorPanel != nil;
1226}
1227
1228- (void) onColorPicked: (NSColorPanel*) pColorPanel
1229{
1230 mColorPickerFunc(FromNSColor([pColorPanel color]));
1231}
1232
1233- (NSString*) view: (NSView*) pView stringForToolTip: (NSToolTipTag) tag point: (NSPoint) point userData: (void*) pData
1234{
1235 int c = mGraphics ? GetMouseOver(mGraphics) : -1;
1236 if (c < 0) return @"";
1237
1238 const char* tooltip = mGraphics->GetControl(c)->GetTooltip();
1239 return CStringHasContents(tooltip) ? [NSString stringWithCString:tooltip encoding:NSUTF8StringEncoding] : @"";
1240}
1241
1242- (void) registerToolTip: (IRECT&) bounds
1243{
1244 [self addToolTipRect: ToNSRect(mGraphics, bounds) owner: self userData: nil];
1245}
1246
1247- (NSDragOperation) draggingEntered: (id<NSDraggingInfo>) sender
1248{
1249 NSPasteboard *pPasteBoard = [sender draggingPasteboard];
1250
1251 if ([[pPasteBoard types] containsObject:NSFilenamesPboardType])
1252 return NSDragOperationGeneric;
1253 else
1254 return NSDragOperationNone;
1255}
1256
1257- (BOOL) performDragOperation: (id<NSDraggingInfo>) sender
1258{
1259 NSPasteboard* pPasteBoard = [sender draggingPasteboard];
1260
1261 if ([[pPasteBoard types] containsObject:NSFilenamesPboardType])
1262 {
1263 NSArray* pFiles = [pPasteBoard propertyListForType:NSFilenamesPboardType];
1264 NSPoint point = [sender draggingLocation];
1265 NSPoint relativePoint = [self convertPoint: point fromView:nil];
1266 // TODO - fix or remove these values
1267 float x = relativePoint.x;// - 2.f;
1268 float y = relativePoint.y;// - 3.f;
1269 if ([pFiles count] == 1)
1270 {
1271 NSString* pFirstFile = [pFiles firstObject];
1272 mGraphics->OnDrop([pFirstFile UTF8String], x, y);
1273 }
1274 else if ([pFiles count] > 1)
1275 {
1276 std::vector<const char*> paths([pFiles count]);
1277 for (auto i = 0; i < [pFiles count]; i++)
1278 {
1279 NSString* pFile = [pFiles objectAtIndex: i];
1280 paths[i] = [pFile UTF8String];
1281 }
1282 mGraphics->OnDropMultiple(paths, x, y);
1283 }
1284 }
1285 return YES;
1286}
1287
1288- (NSDragOperation)draggingSession:(NSDraggingSession*) session sourceOperationMaskForDraggingContext:(NSDraggingContext)context
1289{
1290 return NSDragOperationCopy;
1291}
1292
1293#ifdef IGRAPHICS_METAL
1294- (void) frameDidChange:(NSNotification*) pNotification
1295{
1296 CGFloat scale = [[self window] backingScaleFactor];
1297
1298 [(CAMetalLayer*)[self layer] setDrawableSize:CGSizeMake(self.frame.size.width * scale,
1299 self.frame.size.height * scale)];
1300}
1301#endif
1302
1303//- (void) windowResized: (NSNotification*) notification;
1304//{
1305// if(!mGraphics)
1306// return;
1307//
1308// NSSize windowSize = [[self window] frame].size;
1309// NSRect viewFrameInWindowCoords = [self convertRect: [self bounds] toView: nil];
1310//
1311// float width = windowSize.width - viewFrameInWindowCoords.origin.x;
1312// float height = windowSize.height - viewFrameInWindowCoords.origin.y;
1313//
1314// float scaleX = width / mGraphics->Width();
1315// float scaleY = height / mGraphics->Height();
1316//
1317// if(mGraphics->GetUIResizerMode() == EUIResizerMode::Scale)
1318// mGraphics->Resize(width, height, mGraphics->GetDrawScale());
1319// else // EUIResizerMode::Size
1320// mGraphics->Resize(mGraphics->Width(), mGraphics->Height(), Clip(std::min(scaleX, scaleY), 0.1f, 10.f));
1321//}
1322//
1323//- (void) windowFullscreened: (NSNotification*) pNotification;
1324//{
1325// NSSize windowSize = [[self window] frame].size;
1326// NSRect viewFrameInWindowCoords = [self convertRect: [self bounds] toView: nil];
1327//
1328// float width = windowSize.width - viewFrameInWindowCoords.origin.x;
1329// float height = windowSize.height - viewFrameInWindowCoords.origin.y;
1330//
1331// float scaleX = width / mGraphics->Width();
1332// float scaleY = height / mGraphics->Height();
1333//
1334// if(mGraphics->GetUIResizerMode() == EUIResizerMode::Scale)
1335// mGraphics->Resize(width, height, mGraphics->GetDrawScale());
1336// else // EUIResizerMode::Size
1337// mGraphics->Resize(mGraphics->Width(), mGraphics->Height(), Clip(std::min(scaleX, scaleY), 0.1f, 10.f));
1338//}
1339
1340@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.
void Clear()
Set all fields of this IRECT to 0.
IText is used to manage font and text/text entry style for a piece of text on the UI,...