11#include "IGraphicsMac.h"
12#import "IGraphicsMac_view.h"
17#pragma clang diagnostic ignored "-Wdeprecated-declarations"
20using namespace igraphics;
22static int GetSystemVersion()
27 if (NSAppKitVersionNumber >= 1266.0)
29 if (NSAppKitVersionNumber >= 1404.0)
37 Gestalt(gestaltSystemVersion,&a);
44StaticStorage<CoreTextFontDescriptor> sFontDescriptorCache;
48IGraphicsMac::IGraphicsMac(
IGEditorDelegate& dlg,
int w,
int h,
int fps,
float scale)
49: IGRAPHICS_DRAW_CLASS(dlg, w, h, fps, scale)
52 StaticStorage<CoreTextFontDescriptor>::Accessor storage(sFontDescriptorCache);
56IGraphicsMac::~IGraphicsMac()
58 StaticStorage<CoreTextFontDescriptor>::Accessor storage(sFontDescriptorCache);
64PlatformFontPtr IGraphicsMac::LoadPlatformFont(
const char* fontID,
const char* fileNameOrResID)
66 return CoreTextHelpers::LoadPlatformFont(fontID, fileNameOrResID, GetBundleID(), GetSharedResourcesSubPath());
69PlatformFontPtr IGraphicsMac::LoadPlatformFont(
const char* fontID,
const char* fontName, ETextStyle style)
71 return CoreTextHelpers::LoadPlatformFont(fontID, fontName, style);
74PlatformFontPtr IGraphicsMac::LoadPlatformFont(
const char* fontID,
void* pData,
int dataSize)
76 return CoreTextHelpers::LoadPlatformFont(fontID, pData, dataSize);
79void IGraphicsMac::CachePlatformFont(
const char* fontID,
const PlatformFontPtr& font)
81 CoreTextHelpers::CachePlatformFont(fontID, font, sFontDescriptorCache);
84float IGraphicsMac::MeasureText(
const IText& text,
const char* str,
IRECT& bounds)
const
86 return IGRAPHICS_DRAW_CLASS::MeasureText(text, str, bounds);
89void* IGraphicsMac::OpenWindow(
void* pParent)
93 IGRAPHICS_VIEW* pView = [[IGRAPHICS_VIEW alloc] initWithIGraphics:
this];
94 mView = (
void*) pView;
97 OnViewInitialized([pView layer]);
98 SetScreenScale([[NSScreen mainScreen] backingScaleFactor]);
99 GetDelegate()->LayoutUI(
this);
101 GetDelegate()->OnUIOpen();
105 [(NSView*) pParent addSubview: pView];
111void IGraphicsMac::AttachPlatformView(
const IRECT& r,
void* pView)
113 NSView* pNewSubView = (NSView*) pView;
114 [pNewSubView setFrame:ToNSRect(
this, r)];
116 [(IGRAPHICS_VIEW*) mView addSubview:(NSView*) pNewSubView];
119void IGraphicsMac::RemovePlatformView(
void* pView)
121 [(NSView*) pView removeFromSuperview];
124void IGraphicsMac::HidePlatformView(
void* pView,
bool hide)
126 [(NSView*) pView setHidden:hide];
129void IGraphicsMac::CloseWindow()
133 IGRAPHICS_VIEW* pView = (IGRAPHICS_VIEW*) mView;
136 [[pView pixelFormat] release];
137 [[pView openGLContext] release];
140 [pView removeAllToolTips];
142 [pView removeFromSuperview];
150bool IGraphicsMac::WindowIsOpen()
155void IGraphicsMac::PlatformResize(
bool parentHasResized)
159 NSSize size = {
static_cast<CGFloat
>(WindowWidth()),
static_cast<CGFloat
>(WindowHeight()) };
161 [NSAnimationContext beginGrouping];
162 [[NSAnimationContext currentContext] setDuration:0.0];
163 [(IGRAPHICS_VIEW*) mView setFrameSize: size ];
165 [NSAnimationContext endGrouping];
171void IGraphicsMac::PointToScreen(
float& x,
float& y)
const
177 NSWindow* pWindow = [(IGRAPHICS_VIEW*) mView window];
178 NSPoint wndpt = [(IGRAPHICS_VIEW*) mView convertPoint:NSMakePoint(x, y) toView:nil];
179 NSPoint pt = [pWindow convertRectToScreen: NSMakeRect(wndpt.x, wndpt.y, 0.0, 0.0)].origin;
186void IGraphicsMac::ScreenToPoint(
float& x,
float& y)
const
190 NSWindow* pWindow = [(IGRAPHICS_VIEW*) mView window];
191 NSPoint wndpt = [pWindow convertRectFromScreen: NSMakeRect(x, y, 0.0, 0.0)].origin;
192 NSPoint pt = [(IGRAPHICS_VIEW*) mView convertPoint:NSMakePoint(wndpt.x, wndpt.y) fromView:nil];
194 x = pt.x / GetDrawScale();
195 y = pt.y / GetDrawScale();
199void IGraphicsMac::HideMouseCursor(
bool hide,
bool lock)
203#elif defined AUv3_API
204 if (!IsOOPAuv3AppExtension())
207 if (mCursorHidden == hide)
210 mCursorHidden = hide;
214 StoreCursorPosition();
215 CGDisplayHideCursor(kCGDirectMainDisplay);
220 DoCursorLock(mCursorX, mCursorY, mCursorX, mCursorY);
221 CGDisplayShowCursor(kCGDirectMainDisplay);
227void IGraphicsMac::MoveMouseCursor(
float x,
float y)
233 RepositionCursor(CGPoint{x, y});
234 StoreCursorPosition();
237void IGraphicsMac::DoCursorLock(
float x,
float y,
float& prevX,
float& prevY)
239 if (mCursorHidden && mCursorLock && !mTabletInput)
241 RepositionCursor(mCursorLockPosition);
247 mCursorX = prevX = x;
248 mCursorY = prevY = y;
252void IGraphicsMac::RepositionCursor(CGPoint point)
254 point = CGPoint{point.x, CGDisplayPixelsHigh(CGMainDisplayID()) - point.y};
255 CGAssociateMouseAndMouseCursorPosition(
false);
256 CGDisplayMoveCursorToPoint(CGMainDisplayID(), point);
257 CGAssociateMouseAndMouseCursorPosition(
true);
260void IGraphicsMac::StoreCursorPosition()
263 NSPoint mouse = [NSEvent mouseLocation];
264 mCursorX = mouse.x = std::round(mouse.x);
265 mCursorY = mouse.y = std::round(mouse.y);
266 mCursorLockPosition = CGPoint{mouse.x, mouse.y};
269 ScreenToPoint(mCursorX, mCursorY);
272void IGraphicsMac::GetMouseLocation(
float& x,
float&y)
const
275 NSPoint mouse = [NSEvent mouseLocation];
283EMsgBoxResult IGraphicsMac::ShowMessageBox(
const char* str,
const char* title, EMsgBoxType type, IMsgBoxCompletionHandlerFunc completionHandler)
285 ReleaseMouseCapture();
287 NSString* messageContent = @(str ? str :
"");
288 NSString* alertTitle = @(title ? title :
"");
290 NSAlert* alert = [[NSAlert alloc] init];
291 [alert setMessageText:alertTitle];
292 [alert setInformativeText:messageContent];
294 EMsgBoxResult result = kCANCEL;
299 [alert addButtonWithTitle:
@"OK"];
303 [alert addButtonWithTitle:
@"OK"];
304 [alert addButtonWithTitle:
@"Cancel"];
308 [alert addButtonWithTitle:
@"Yes"];
309 [alert addButtonWithTitle:
@"No"];
312 case kMB_RETRYCANCEL:
313 [alert addButtonWithTitle:
@"Retry"];
314 [alert addButtonWithTitle:
@"Cancel"];
317 case kMB_YESNOCANCEL:
318 [alert addButtonWithTitle:
@"Yes"];
319 [alert addButtonWithTitle:
@"No"];
320 [alert addButtonWithTitle:
@"Cancel"];
325 NSModalResponse response = [alert runModal];
333 result = (response == NSAlertFirstButtonReturn) ? kOK : kCANCEL;
336 result = (response == NSAlertFirstButtonReturn) ? kYES : kNO;
338 case kMB_RETRYCANCEL:
339 result = (response == NSAlertFirstButtonReturn) ? kRETRY : kCANCEL;
341 case kMB_YESNOCANCEL:
342 if (response == NSAlertFirstButtonReturn) result = kYES;
343 else if (response == NSAlertSecondButtonReturn) result = kNO;
344 else result = kCANCEL;
348 if (completionHandler)
350 completionHandler(result);
358void IGraphicsMac::ForceEndUserEdit()
362 [(IGRAPHICS_VIEW*) mView endUserInput];
366void IGraphicsMac::UpdateTooltips()
368 if (!(mView && TooltipsEnabled()))
373 [(IGRAPHICS_VIEW*) mView removeAllToolTips];
375 if (GetPopupMenuControl() && GetPopupMenuControl()->GetState() > IPopupMenuControl::kCollapsed)
380 auto func = [
this](
IControl* pControl)
382 if (pControl->GetTooltip() && !pControl->IsHidden())
384 IRECT pR = pControl->GetTargetRECT();
387 [(IGRAPHICS_VIEW*) mView registerToolTip: pR];
392 ForStandardControlsFunc(func);
397const char* IGraphicsMac::GetPlatformAPIStr()
402bool IGraphicsMac::RevealPathInExplorerOrFinder(WDL_String& path,
bool select)
404 BOOL success = FALSE;
410 NSString* pPath = [NSString stringWithUTF8String:path.Get()];
412 if([[NSFileManager defaultManager] fileExistsAtPath : pPath] == YES)
416 NSString* pParentDirectoryPath = [pPath stringByDeletingLastPathComponent];
418 if (pParentDirectoryPath)
420 success = [[NSWorkspace sharedWorkspace] openFile:pParentDirectoryPath];
423 success = [[NSWorkspace sharedWorkspace] selectFile: pPath inFileViewerRootedAtPath:pParentDirectoryPath];
427 success = [[NSWorkspace sharedWorkspace] openFile:pPath];
434 return (
bool) success;
437void IGraphicsMac::PromptForFile(WDL_String& fileName, WDL_String& path, EFileAction action,
const char* ext, IFileDialogCompletionHandlerFunc completionHandler)
445 NSString* pDefaultFileName = nil;
446 NSString* pDefaultPath = nil;
447 NSArray* pFileTypes = nil;
449 if (fileName.GetLength())
450 pDefaultFileName = [NSString stringWithUTF8String:fileName.Get()];
452 pDefaultFileName =
@"";
454 if (path.GetLength())
455 pDefaultPath = [NSString stringWithUTF8String:path.Get()];
461 if (CStringHasContents(ext))
462 pFileTypes = [[NSString stringWithUTF8String:ext] componentsSeparatedByString:
@" "];
464 auto doHandleResponse = [](NSPanel* pPanel, NSModalResponse response, WDL_String& fileName, WDL_String& path, IFileDialogCompletionHandlerFunc completionHandler){
465 if (response == NSOKButton)
467 NSString* pFullPath = [(NSSavePanel*) pPanel filename] ;
468 fileName.Set([pFullPath UTF8String]);
470 NSString* pTruncatedPath = [pFullPath stringByDeletingLastPathComponent];
474 path.Set([pTruncatedPath UTF8String]);
479 if (completionHandler)
480 completionHandler(fileName, path);
483 NSPanel* pPanel =
nullptr;
485 if (action == EFileAction::Save)
487 pPanel = [NSSavePanel savePanel];
489 [(NSSavePanel*) pPanel setAllowedFileTypes: pFileTypes];
490 [(NSSavePanel*) pPanel setDirectoryURL: [NSURL fileURLWithPath: pDefaultPath]];
491 [(NSSavePanel*) pPanel setNameFieldStringValue: pDefaultFileName];
492 [(NSSavePanel*) pPanel setAllowsOtherFileTypes: NO];
496 pPanel = [NSOpenPanel openPanel];
498 [(NSOpenPanel*) pPanel setAllowedFileTypes: pFileTypes];
499 [(NSOpenPanel*) pPanel setDirectoryURL: [NSURL fileURLWithPath: pDefaultPath]];
500 [(NSOpenPanel*) pPanel setCanChooseFiles:YES];
501 [(NSOpenPanel*) pPanel setCanChooseDirectories:NO];
502 [(NSOpenPanel*) pPanel setResolvesAliases:YES];
504 [pPanel setFloatingPanel: YES];
506 if (completionHandler)
508 NSWindow* pWindow = [(IGRAPHICS_VIEW*) mView window];
510 [(NSSavePanel*) pPanel beginSheetModalForWindow:pWindow completionHandler:^(NSModalResponse response) {
511 WDL_String fileNameAsync, pathAsync;
512 doHandleResponse(pPanel, response, fileNameAsync, pathAsync, completionHandler);
517 NSModalResponse response = [(NSSavePanel*) pPanel runModal];
518 doHandleResponse(pPanel, response, fileName, path,
nullptr);
522void IGraphicsMac::PromptForDirectory(WDL_String& dir, IFileDialogCompletionHandlerFunc completionHandler)
524 NSString* defaultPath;
528 defaultPath = [NSString stringWithUTF8String:dir.Get()];
532 defaultPath = [NSString stringWithUTF8String:DEFAULT_PATH];
533 dir.Set(DEFAULT_PATH);
536 NSOpenPanel* panelOpen = [NSOpenPanel openPanel];
538 [panelOpen setTitle:
@"Choose a Directory"];
539 [panelOpen setCanChooseFiles:NO];
540 [panelOpen setCanChooseDirectories:YES];
541 [panelOpen setResolvesAliases:YES];
542 [panelOpen setCanCreateDirectories:YES];
543 [panelOpen setFloatingPanel: YES];
544 [panelOpen setDirectoryURL: [NSURL fileURLWithPath: defaultPath]];
546 auto doHandleResponse = [](NSOpenPanel* pPanel, NSModalResponse response, WDL_String& pathAsync, IFileDialogCompletionHandlerFunc completionHandler){
547 if (response == NSOKButton)
549 NSString* fullPath = [pPanel filename] ;
550 pathAsync.Set([fullPath UTF8String]);
551 pathAsync.Append(
"/");
558 if (completionHandler)
560 WDL_String fileNameAsync;
561 completionHandler(fileNameAsync, pathAsync);
565 if (completionHandler)
567 NSWindow* pWindow = [(IGRAPHICS_VIEW*) mView window];
569 [panelOpen beginSheetModalForWindow:pWindow completionHandler:^(NSModalResponse response) {
570 WDL_String pathAsync;
571 doHandleResponse(panelOpen, response, pathAsync, completionHandler);
576 NSModalResponse response = [panelOpen runModal];
577 doHandleResponse(panelOpen, response, dir,
nullptr);
581bool IGraphicsMac::PromptForColor(
IColor& color,
const char* str, IColorPickerHandlerFunc func)
584 return [(IGRAPHICS_VIEW*) mView promptForColor:color : func];
593 dispatch_async(dispatch_get_main_queue(), ^{
598 NSRect areaRect = ToNSRect(
this, bounds);
599 pReturnMenu = [(IGRAPHICS_VIEW*) mView createPopupMenu: menu: areaRect];
602 if (pReturnMenu && pReturnMenu->GetFunction())
603 pReturnMenu->ExecFunction();
605 this->SetControlValueAfterPopupMenu(pReturnMenu);
611void IGraphicsMac::CreatePlatformTextEntry(
int paramIdx,
const IText& text,
const IRECT& bounds,
int length,
const char* str)
615 NSRect areaRect = ToNSRect(
this, bounds);
616 [(IGRAPHICS_VIEW*) mView createTextEntry: paramIdx : text: str: length: areaRect];
620ECursor IGraphicsMac::SetMouseCursor(ECursor cursorType)
623 [(IGRAPHICS_VIEW*) mView setMouseCursor: cursorType];
628bool IGraphicsMac::OpenURL(
const char* url,
const char* msgWindowTitle,
const char* confirmMsg,
const char* errMsgOnFailure)
630 #pragma REMINDER("Warning and error messages for OpenURL not implemented")
631 NSURL* pNSURL =
nullptr;
632 if (strstr(url,
"http"))
633 pNSURL = [NSURL URLWithString:[NSString stringWithUTF8String:url]];
635 pNSURL = [NSURL fileURLWithPath:[NSString stringWithUTF8String:url]];
639 bool ok = ([[NSWorkspace sharedWorkspace] openURL:pNSURL]);
645void* IGraphicsMac::GetWindow()
647 if (mView)
return mView;
652int IGraphicsMac::GetUserOSVersion()
654 return (
int) GetSystemVersion();
657bool IGraphicsMac::GetTextFromClipboard(WDL_String& str)
659 NSString* pTextOnClipboard = [[NSPasteboard generalPasteboard] stringForType: NSStringPboardType];
661 if (pTextOnClipboard == nil)
668 str.Set([pTextOnClipboard UTF8String]);
673bool IGraphicsMac::SetTextInClipboard(
const char* str)
675 NSString* pTextForClipboard = [NSString stringWithUTF8String:str];
676 [[NSPasteboard generalPasteboard] clearContents];
677 return [[NSPasteboard generalPasteboard] setString:pTextForClipboard forType:NSStringPboardType];
680bool IGraphicsMac::SetFilePathInClipboard(
const char* path)
682 NSPasteboard* pPasteboard = [NSPasteboard generalPasteboard];
683 [pPasteboard clearContents];
684 NSURL* pFileURL = [NSURL fileURLWithPath: [NSString stringWithUTF8String:path]];
685 BOOL success = [pPasteboard writeObjects: [NSArray arrayWithObject:pFileURL]];
686 return (
bool)success;
689bool IGraphicsMac::InitiateExternalFileDragDrop(
const char* path,
const IRECT& iconBounds)
691 NSPasteboardItem* pasteboardItem = [[NSPasteboardItem alloc] init];
692 NSURL* fileURL = [NSURL fileURLWithPath: [NSString stringWithUTF8String:path]];
693 [pasteboardItem setString:fileURL.absoluteString forType:NSPasteboardTypeFileURL];
695 NSDraggingItem* draggingItem = [[NSDraggingItem alloc] initWithPasteboardWriter:pasteboardItem];
696 NSRect draggingFrame = ToNSRect(
this, iconBounds);
697 NSImage* iconImage = [[NSWorkspace sharedWorkspace] iconForFile:fileURL.path];
698 [iconImage setSize:NSMakeSize(64, 64)];
699 [draggingItem setDraggingFrame:draggingFrame contents: iconImage];
701 IGRAPHICS_VIEW* view = (IGRAPHICS_VIEW*) mView;
702 NSDraggingSession* draggingSession = [view beginDraggingSessionWithItems:@[draggingItem] event:[NSApp currentEvent] source: view];
703 draggingSession.animatesToStartingPositionsOnCancelOrFail = YES;
704 draggingSession.draggingFormation = NSDraggingFormationNone;
706 ReleaseMouseCapture();
711EUIAppearance IGraphicsMac::GetUIAppearance()
const
713 if (@available(macOS 10.14, *)) {
716 IGRAPHICS_VIEW* pView = (IGRAPHICS_VIEW*) mView;
717 BOOL isDarkMode = [[[pView effectiveAppearance] name] isEqualToString: (NSAppearanceNameDarkAqua)];
718 return isDarkMode ? EUIAppearance::Dark : EUIAppearance::Light;
722 return EUIAppearance::Light;
725void IGraphicsMac::ActivateGLContext()
727 IGRAPHICS_VIEW* pView = (IGRAPHICS_VIEW*) mView;
728 [pView activateGLContext];
731void IGraphicsMac::DeactivateGLContext()
733 IGRAPHICS_VIEW* pView = (IGRAPHICS_VIEW*) mView;
734 [pView deactivateGLContext];
737#if defined IGRAPHICS_NANOVG
738 #include "IGraphicsNanoVG.cpp"
739#elif defined IGRAPHICS_SKIA
740 #include "IGraphicsSkia.cpp"
742 #error Either NO_IGRAPHICS or one and only one choice of graphics library must be defined!
This file contains the base IControl implementation, along with some base classes for specific types ...
The lowest level base class of an IGraphics control.
An editor delegate base class that uses IGraphics for the UI.
virtual ECursor SetMouseCursor(ECursor cursorType=ECursor::ARROW)
Sets the mouse cursor to one of ECursor (implementations should return the result of the base impleme...
Used to manage color data, independent of draw class/platform.
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,...