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 [[pView openGLContext] makeCurrentContext];
100 OnViewInitialized([pView layer]);
101 SetScreenScale([[NSScreen mainScreen] backingScaleFactor]);
102 GetDelegate()->LayoutUI(
this);
104 GetDelegate()->OnUIOpen();
108 [(NSView*) pParent addSubview: pView];
114void IGraphicsMac::AttachPlatformView(
const IRECT& r,
void* pView)
116 NSView* pNewSubView = (NSView*) pView;
117 [pNewSubView setFrame:ToNSRect(
this, r)];
119 [(IGRAPHICS_VIEW*) mView addSubview:(NSView*) pNewSubView];
122void IGraphicsMac::RemovePlatformView(
void* pView)
124 [(NSView*) pView removeFromSuperview];
127void IGraphicsMac::HidePlatformView(
void* pView,
bool hide)
129 [(NSView*) pView setHidden:hide];
132void IGraphicsMac::CloseWindow()
136 IGRAPHICS_VIEW* pView = (IGRAPHICS_VIEW*) mView;
139 [[pView pixelFormat] release];
140 [[pView openGLContext] release];
143 [pView removeAllToolTips];
145 [pView removeFromSuperview];
153bool IGraphicsMac::WindowIsOpen()
158void IGraphicsMac::PlatformResize(
bool parentHasResized)
162 NSSize size = {
static_cast<CGFloat
>(WindowWidth()),
static_cast<CGFloat
>(WindowHeight()) };
164 [NSAnimationContext beginGrouping];
165 [[NSAnimationContext currentContext] setDuration:0.0];
166 [(IGRAPHICS_VIEW*) mView setFrameSize: size ];
168 [NSAnimationContext endGrouping];
174void IGraphicsMac::PointToScreen(
float& x,
float& y)
const
180 NSWindow* pWindow = [(IGRAPHICS_VIEW*) mView window];
181 NSPoint wndpt = [(IGRAPHICS_VIEW*) mView convertPoint:NSMakePoint(x, y) toView:nil];
182 NSPoint pt = [pWindow convertRectToScreen: NSMakeRect(wndpt.x, wndpt.y, 0.0, 0.0)].origin;
189void IGraphicsMac::ScreenToPoint(
float& x,
float& y)
const
193 NSWindow* pWindow = [(IGRAPHICS_VIEW*) mView window];
194 NSPoint wndpt = [pWindow convertRectFromScreen: NSMakeRect(x, y, 0.0, 0.0)].origin;
195 NSPoint pt = [(IGRAPHICS_VIEW*) mView convertPoint:NSMakePoint(wndpt.x, wndpt.y) fromView:nil];
197 x = pt.x / GetDrawScale();
198 y = pt.y / GetDrawScale();
202void IGraphicsMac::HideMouseCursor(
bool hide,
bool lock)
206#elif defined AUv3_API
207 if (!IsOOPAuv3AppExtension())
210 if (mCursorHidden == hide)
213 mCursorHidden = hide;
217 StoreCursorPosition();
218 CGDisplayHideCursor(kCGDirectMainDisplay);
223 DoCursorLock(mCursorX, mCursorY, mCursorX, mCursorY);
224 CGDisplayShowCursor(kCGDirectMainDisplay);
230void IGraphicsMac::MoveMouseCursor(
float x,
float y)
236 RepositionCursor(CGPoint{x, y});
237 StoreCursorPosition();
240void IGraphicsMac::DoCursorLock(
float x,
float y,
float& prevX,
float& prevY)
242 if (mCursorHidden && mCursorLock && !mTabletInput)
244 RepositionCursor(mCursorLockPosition);
250 mCursorX = prevX = x;
251 mCursorY = prevY = y;
255void IGraphicsMac::RepositionCursor(CGPoint point)
257 point = CGPoint{point.x, CGDisplayPixelsHigh(CGMainDisplayID()) - point.y};
258 CGAssociateMouseAndMouseCursorPosition(
false);
259 CGDisplayMoveCursorToPoint(CGMainDisplayID(), point);
260 CGAssociateMouseAndMouseCursorPosition(
true);
263void IGraphicsMac::StoreCursorPosition()
266 NSPoint mouse = [NSEvent mouseLocation];
267 mCursorX = mouse.x = std::round(mouse.x);
268 mCursorY = mouse.y = std::round(mouse.y);
269 mCursorLockPosition = CGPoint{mouse.x, mouse.y};
272 ScreenToPoint(mCursorX, mCursorY);
275void IGraphicsMac::GetMouseLocation(
float& x,
float&y)
const
278 NSPoint mouse = [NSEvent mouseLocation];
286EMsgBoxResult IGraphicsMac::ShowMessageBox(
const char* str,
const char* title, EMsgBoxType type, IMsgBoxCompletionHandlerFunc completionHandler)
288 ReleaseMouseCapture();
290 NSString* messageContent = @(str ? str :
"");
291 NSString* alertTitle = @(title ? title :
"");
293 NSAlert* alert = [[NSAlert alloc] init];
294 [alert setMessageText:alertTitle];
295 [alert setInformativeText:messageContent];
297 EMsgBoxResult result = kCANCEL;
302 [alert addButtonWithTitle:
@"OK"];
306 [alert addButtonWithTitle:
@"OK"];
307 [alert addButtonWithTitle:
@"Cancel"];
311 [alert addButtonWithTitle:
@"Yes"];
312 [alert addButtonWithTitle:
@"No"];
315 case kMB_RETRYCANCEL:
316 [alert addButtonWithTitle:
@"Retry"];
317 [alert addButtonWithTitle:
@"Cancel"];
320 case kMB_YESNOCANCEL:
321 [alert addButtonWithTitle:
@"Yes"];
322 [alert addButtonWithTitle:
@"No"];
323 [alert addButtonWithTitle:
@"Cancel"];
328 NSModalResponse response = [alert runModal];
336 result = (response == NSAlertFirstButtonReturn) ? kOK : kCANCEL;
339 result = (response == NSAlertFirstButtonReturn) ? kYES : kNO;
341 case kMB_RETRYCANCEL:
342 result = (response == NSAlertFirstButtonReturn) ? kRETRY : kCANCEL;
344 case kMB_YESNOCANCEL:
345 if (response == NSAlertFirstButtonReturn) result = kYES;
346 else if (response == NSAlertSecondButtonReturn) result = kNO;
347 else result = kCANCEL;
351 if (completionHandler)
353 completionHandler(result);
361void IGraphicsMac::ForceEndUserEdit()
365 [(IGRAPHICS_VIEW*) mView endUserInput];
369void IGraphicsMac::UpdateTooltips()
371 if (!(mView && TooltipsEnabled()))
376 [(IGRAPHICS_VIEW*) mView removeAllToolTips];
378 if (GetPopupMenuControl() && GetPopupMenuControl()->GetState() > IPopupMenuControl::kCollapsed)
383 auto func = [
this](
IControl* pControl)
385 if (pControl->GetTooltip() && !pControl->IsHidden())
387 IRECT pR = pControl->GetTargetRECT();
390 [(IGRAPHICS_VIEW*) mView registerToolTip: pR];
395 ForStandardControlsFunc(func);
400const char* IGraphicsMac::GetPlatformAPIStr()
405bool IGraphicsMac::RevealPathInExplorerOrFinder(WDL_String& path,
bool select)
407 BOOL success = FALSE;
413 NSString* pPath = [NSString stringWithUTF8String:path.Get()];
415 if([[NSFileManager defaultManager] fileExistsAtPath : pPath] == YES)
419 NSString* pParentDirectoryPath = [pPath stringByDeletingLastPathComponent];
421 if (pParentDirectoryPath)
423 success = [[NSWorkspace sharedWorkspace] openFile:pParentDirectoryPath];
426 success = [[NSWorkspace sharedWorkspace] selectFile: pPath inFileViewerRootedAtPath:pParentDirectoryPath];
430 success = [[NSWorkspace sharedWorkspace] openFile:pPath];
437 return (
bool) success;
440void IGraphicsMac::PromptForFile(WDL_String& fileName, WDL_String& path, EFileAction action,
const char* ext, IFileDialogCompletionHandlerFunc completionHandler)
448 NSString* pDefaultFileName = nil;
449 NSString* pDefaultPath = nil;
450 NSArray* pFileTypes = nil;
452 if (fileName.GetLength())
453 pDefaultFileName = [NSString stringWithUTF8String:fileName.Get()];
455 pDefaultFileName =
@"";
457 if (path.GetLength())
458 pDefaultPath = [NSString stringWithUTF8String:path.Get()];
464 if (CStringHasContents(ext))
465 pFileTypes = [[NSString stringWithUTF8String:ext] componentsSeparatedByString:
@" "];
467 auto doHandleResponse = [](NSPanel* pPanel, NSModalResponse response, WDL_String& fileName, WDL_String& path, IFileDialogCompletionHandlerFunc completionHandler){
468 if (response == NSOKButton)
470 NSString* pFullPath = [(NSSavePanel*) pPanel filename] ;
471 fileName.Set([pFullPath UTF8String]);
473 NSString* pTruncatedPath = [pFullPath stringByDeletingLastPathComponent];
477 path.Set([pTruncatedPath UTF8String]);
482 if (completionHandler)
483 completionHandler(fileName, path);
486 NSPanel* pPanel =
nullptr;
488 if (action == EFileAction::Save)
490 pPanel = [NSSavePanel savePanel];
492 [(NSSavePanel*) pPanel setAllowedFileTypes: pFileTypes];
493 [(NSSavePanel*) pPanel setDirectoryURL: [NSURL fileURLWithPath: pDefaultPath]];
494 [(NSSavePanel*) pPanel setNameFieldStringValue: pDefaultFileName];
495 [(NSSavePanel*) pPanel setAllowsOtherFileTypes: NO];
499 pPanel = [NSOpenPanel openPanel];
501 [(NSOpenPanel*) pPanel setAllowedFileTypes: pFileTypes];
502 [(NSOpenPanel*) pPanel setDirectoryURL: [NSURL fileURLWithPath: pDefaultPath]];
503 [(NSOpenPanel*) pPanel setCanChooseFiles:YES];
504 [(NSOpenPanel*) pPanel setCanChooseDirectories:NO];
505 [(NSOpenPanel*) pPanel setResolvesAliases:YES];
507 [pPanel setFloatingPanel: YES];
509 if (completionHandler)
511 NSWindow* pWindow = [(IGRAPHICS_VIEW*) mView window];
513 [(NSSavePanel*) pPanel beginSheetModalForWindow:pWindow completionHandler:^(NSModalResponse response) {
514 WDL_String fileNameAsync, pathAsync;
515 doHandleResponse(pPanel, response, fileNameAsync, pathAsync, completionHandler);
520 NSModalResponse response = [(NSSavePanel*) pPanel runModal];
521 doHandleResponse(pPanel, response, fileName, path,
nullptr);
525void IGraphicsMac::PromptForDirectory(WDL_String& dir, IFileDialogCompletionHandlerFunc completionHandler)
527 NSString* defaultPath;
531 defaultPath = [NSString stringWithUTF8String:dir.Get()];
535 defaultPath = [NSString stringWithUTF8String:DEFAULT_PATH];
536 dir.Set(DEFAULT_PATH);
539 NSOpenPanel* panelOpen = [NSOpenPanel openPanel];
541 [panelOpen setTitle:
@"Choose a Directory"];
542 [panelOpen setCanChooseFiles:NO];
543 [panelOpen setCanChooseDirectories:YES];
544 [panelOpen setResolvesAliases:YES];
545 [panelOpen setCanCreateDirectories:YES];
546 [panelOpen setFloatingPanel: YES];
547 [panelOpen setDirectoryURL: [NSURL fileURLWithPath: defaultPath]];
549 auto doHandleResponse = [](NSOpenPanel* pPanel, NSModalResponse response, WDL_String& pathAsync, IFileDialogCompletionHandlerFunc completionHandler){
550 if (response == NSOKButton)
552 NSString* fullPath = [pPanel filename] ;
553 pathAsync.Set([fullPath UTF8String]);
554 pathAsync.Append(
"/");
561 if (completionHandler)
563 WDL_String fileNameAsync;
564 completionHandler(fileNameAsync, pathAsync);
568 if (completionHandler)
570 NSWindow* pWindow = [(IGRAPHICS_VIEW*) mView window];
572 [panelOpen beginSheetModalForWindow:pWindow completionHandler:^(NSModalResponse response) {
573 WDL_String pathAsync;
574 doHandleResponse(panelOpen, response, pathAsync, completionHandler);
579 NSModalResponse response = [panelOpen runModal];
580 doHandleResponse(panelOpen, response, dir,
nullptr);
584bool IGraphicsMac::PromptForColor(
IColor& color,
const char* str, IColorPickerHandlerFunc func)
587 return [(IGRAPHICS_VIEW*) mView promptForColor:color : func];
596 dispatch_async(dispatch_get_main_queue(), ^{
601 NSRect areaRect = ToNSRect(
this, bounds);
602 pReturnMenu = [(IGRAPHICS_VIEW*) mView createPopupMenu: menu: areaRect];
605 if (pReturnMenu && pReturnMenu->GetFunction())
606 pReturnMenu->ExecFunction();
608 this->SetControlValueAfterPopupMenu(pReturnMenu);
614void IGraphicsMac::CreatePlatformTextEntry(
int paramIdx,
const IText& text,
const IRECT& bounds,
int length,
const char* str)
618 NSRect areaRect = ToNSRect(
this, bounds);
619 [(IGRAPHICS_VIEW*) mView createTextEntry: paramIdx : text: str: length: areaRect];
623ECursor IGraphicsMac::SetMouseCursor(ECursor cursorType)
626 [(IGRAPHICS_VIEW*) mView setMouseCursor: cursorType];
631bool IGraphicsMac::OpenURL(
const char* url,
const char* msgWindowTitle,
const char* confirmMsg,
const char* errMsgOnFailure)
633 #pragma REMINDER("Warning and error messages for OpenURL not implemented")
634 NSURL* pNSURL =
nullptr;
635 if (strstr(url,
"http"))
636 pNSURL = [NSURL URLWithString:[NSString stringWithUTF8String:url]];
638 pNSURL = [NSURL fileURLWithPath:[NSString stringWithUTF8String:url]];
642 bool ok = ([[NSWorkspace sharedWorkspace] openURL:pNSURL]);
648void* IGraphicsMac::GetWindow()
650 if (mView)
return mView;
655int IGraphicsMac::GetUserOSVersion()
657 return (
int) GetSystemVersion();
660bool IGraphicsMac::GetTextFromClipboard(WDL_String& str)
662 NSString* pTextOnClipboard = [[NSPasteboard generalPasteboard] stringForType: NSStringPboardType];
664 if (pTextOnClipboard == nil)
671 str.Set([pTextOnClipboard UTF8String]);
676bool IGraphicsMac::SetTextInClipboard(
const char* str)
678 NSString* pTextForClipboard = [NSString stringWithUTF8String:str];
679 [[NSPasteboard generalPasteboard] clearContents];
680 return [[NSPasteboard generalPasteboard] setString:pTextForClipboard forType:NSStringPboardType];
683bool IGraphicsMac::SetFilePathInClipboard(
const char* path)
685 NSPasteboard* pPasteboard = [NSPasteboard generalPasteboard];
686 [pPasteboard clearContents];
687 NSURL* pFileURL = [NSURL fileURLWithPath: [NSString stringWithUTF8String:path]];
688 BOOL success = [pPasteboard writeObjects: [NSArray arrayWithObject:pFileURL]];
689 return (
bool)success;
692bool IGraphicsMac::InitiateExternalFileDragDrop(
const char* path,
const IRECT& iconBounds)
694 NSPasteboardItem* pasteboardItem = [[NSPasteboardItem alloc] init];
695 NSURL* fileURL = [NSURL fileURLWithPath: [NSString stringWithUTF8String:path]];
696 [pasteboardItem setString:fileURL.absoluteString forType:NSPasteboardTypeFileURL];
698 NSDraggingItem* draggingItem = [[NSDraggingItem alloc] initWithPasteboardWriter:pasteboardItem];
699 NSRect draggingFrame = ToNSRect(
this, iconBounds);
700 NSImage* iconImage = [[NSWorkspace sharedWorkspace] iconForFile:fileURL.path];
701 [iconImage setSize:NSMakeSize(64, 64)];
702 [draggingItem setDraggingFrame:draggingFrame contents: iconImage];
704 IGRAPHICS_VIEW* view = (IGRAPHICS_VIEW*) mView;
705 NSDraggingSession* draggingSession = [view beginDraggingSessionWithItems:@[draggingItem] event:[NSApp currentEvent] source: view];
706 draggingSession.animatesToStartingPositionsOnCancelOrFail = YES;
707 draggingSession.draggingFormation = NSDraggingFormationNone;
709 ReleaseMouseCapture();
714EUIAppearance IGraphicsMac::GetUIAppearance()
const
716 if (@available(macOS 10.14, *)) {
719 IGRAPHICS_VIEW* pView = (IGRAPHICS_VIEW*) mView;
720 BOOL isDarkMode = [[[pView effectiveAppearance] name] isEqualToString: (NSAppearanceNameDarkAqua)];
721 return isDarkMode ? EUIAppearance::Dark : EUIAppearance::Light;
725 return EUIAppearance::Light;
728void IGraphicsMac::ActivateGLContext()
731 IGRAPHICS_VIEW* pView = (IGRAPHICS_VIEW*) mView;
732 [[pView openGLContext] makeCurrentContext];
736void IGraphicsMac::DeactivateGLContext()
739 [NSOpenGLContext clearCurrentContext];
743#if defined IGRAPHICS_NANOVG
744 #include "IGraphicsNanoVG.cpp"
745#elif defined IGRAPHICS_SKIA
746 #include "IGraphicsSkia.cpp"
748 #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,...