iPlug2 - C++ Audio Plug-in Framework
Loading...
Searching...
No Matches
IGraphicsIOS.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#import <MetalKit/MetalKit.h>
13#import <UniformTypeIdentifiers/UniformTypeIdentifiers.h>
14
15#include "IGraphicsIOS.h"
16#include "IGraphicsCoreText.h"
17
18#import "IGraphicsIOS_view.h"
19
20#include <map>
21#include <string>
22#include <cassert>
23
24#pragma clang diagnostic ignored "-Wdeprecated-declarations"
25
26BEGIN_IPLUG_NAMESPACE
27BEGIN_IGRAPHICS_NAMESPACE
28
29#if !TARGET_OS_VISION
30void GetScreenDimensions(int& width, int& height)
31{
32 CGRect bounds = [[UIScreen mainScreen] bounds];
33 width = bounds.size.width;
34 height = bounds.size.height;
35}
36
37float GetScaleForScreen(int plugWidth, int plugHeight)
38{
39 int width, height;
40 GetScreenDimensions(width, height);
41 return std::min((float) width / (float) plugWidth, (float) height / (float) plugHeight);
42}
43#else
44float GetScaleForScreen(int plugWidth, int plugHeight)
45{
46 return 1.0;
47}
48#endif
49
50END_IGRAPHICS_NAMESPACE
51END_IPLUG_NAMESPACE
52
53using namespace iplug;
54using namespace igraphics;
55
56StaticStorage<CoreTextFontDescriptor> sFontDescriptorCache;
57
58#pragma mark -
59
60std::map<std::string, MTLTexturePtr> gTextureMap;
61NSArray<id<MTLTexture>>* gTextures;
62
63IGraphicsIOS::IGraphicsIOS(IGEditorDelegate& dlg, int w, int h, int fps, float scale)
64: IGRAPHICS_DRAW_CLASS(dlg, w, h, fps, scale)
65{
66
67#if defined IGRAPHICS_METAL && !defined IGRAPHICS_SKIA
68 if(!gTextureMap.size())
69 {
70 NSBundle* pBundle = [NSBundle mainBundle];
71
72 if(IsOOPAuv3AppExtension())
73 pBundle = [NSBundle bundleWithPath: [[[pBundle bundlePath] stringByDeletingLastPathComponent] stringByDeletingLastPathComponent]];
74
75 NSArray<NSURL*>* pTextureFiles = [pBundle URLsForResourcesWithExtension:@"ktx" subdirectory:@""];
76
77 if ([pTextureFiles count])
78 {
79 MTKTextureLoader* textureLoader = [[MTKTextureLoader alloc] initWithDevice:MTLCreateSystemDefaultDevice()];
80
81 NSError* pError = nil;
82 NSDictionary* textureOptions = @{ MTKTextureLoaderOptionSRGB: [NSNumber numberWithBool:NO] };
83
84 gTextures = [textureLoader newTexturesWithContentsOfURLs:pTextureFiles options:textureOptions error:&pError];
85
86 for(int i=0; i < gTextures.count; i++)
87 {
88 gTextureMap.insert(std::make_pair([[[pTextureFiles[i] lastPathComponent] stringByDeletingPathExtension] UTF8String], (MTLTexturePtr) gTextures[i]));
89 }
90
91 DBGMSG("Preloaded %i textures\n", (int) [pTextureFiles count]);
92
93 [textureLoader release];
94 textureLoader = nil;
95 }
96 }
97#endif
98}
99
100IGraphicsIOS::~IGraphicsIOS()
101{
102 CloseWindow();
103}
104
105void* IGraphicsIOS::OpenWindow(void* pParent)
106{
107 TRACE
108 CloseWindow();
109 IGRAPHICS_VIEW* view = [[IGRAPHICS_VIEW alloc] initWithIGraphics: this];
110 mView = (void*) view;
111
112 IGraphics::ScopedGLContext scopedGLContext{this};
113 OnViewInitialized((void*) [view layer]);
114
115#if !TARGET_OS_VISION
116 CGFloat scale = [UIScreen mainScreen].scale;
117#else
118 CGFloat scale = 2.0;
119#endif
120
121 SetScreenScale(scale);
122
123 GetDelegate()->LayoutUI(this);
124 GetDelegate()->OnUIOpen();
125
126 [view setMultipleTouchEnabled:MultiTouchEnabled()];
127
128 if (pParent)
129 {
130 [(UIView*) pParent addSubview: view];
131 }
132
133 return mView;
134}
135
136void IGraphicsIOS::CloseWindow()
137{
138 if (mView)
139 {
140 IGRAPHICS_VIEW* pView = (IGRAPHICS_VIEW*) mView;
141 [pView removeFromSuperview];
142 [pView release];
143 mView = nullptr;
144
145 OnViewDestroyed();
146 }
147}
148
149bool IGraphicsIOS::WindowIsOpen()
150{
151 return mView;
152}
153
154void IGraphicsIOS::PlatformResize(bool parentHasResized)
155{
156 if (mView)
157 {
158 CGRect r = CGRectMake(0., 0., static_cast<CGFloat>(WindowWidth()), static_cast<CGFloat>(WindowHeight()));
159 [(IGRAPHICS_VIEW*) mView setFrame: r ];
160 }
161}
162
163void IGraphicsIOS::AttachPlatformView(const IRECT& r, void* pView)
164{
165 IGRAPHICS_VIEW* pMainView = (IGRAPHICS_VIEW*) mView;
166
167 UIView* pNewSubView = (UIView*) pView;
168 [pNewSubView setFrame:ToCGRect(this, r)];
169
170 [pMainView addSubview:pNewSubView];
171}
172
173void IGraphicsIOS::RemovePlatformView(void* pView)
174{
175 [(UIView*) pView removeFromSuperview];
176}
177
178void IGraphicsIOS::HidePlatformView(void* pView, bool hide)
179{
180 [(UIView*) pView setHidden:hide];
181}
182
183EMsgBoxResult IGraphicsIOS::ShowMessageBox(const char* str, const char* title, EMsgBoxType type, IMsgBoxCompletionHandlerFunc completionHandler)
184{
185 ReleaseMouseCapture();
186 [(IGRAPHICS_VIEW*) mView showMessageBox:str : title : type : completionHandler];
187 return EMsgBoxResult::kNoResult; // we need to rely on completionHandler
188}
189
190void IGraphicsIOS::AttachGestureRecognizer(EGestureType type)
191{
193 [(IGRAPHICS_VIEW*) mView attachGestureRecognizer:type];
194}
195
196void IGraphicsIOS::ForceEndUserEdit()
197{
198 if (mView)
199 {
200 [(IGRAPHICS_VIEW*) mView endUserInput];
201 }
202}
203
204const char* IGraphicsIOS::GetPlatformAPIStr()
205{
206 return "iOS";
207}
208
209void IGraphicsIOS::GetMouseLocation(float& x, float&y) const
210{
211 [(IGRAPHICS_VIEW*) mView getLastTouchLocation: x : y];
212}
213
214void IGraphicsIOS::PromptForFile(WDL_String& fileName, WDL_String& path, EFileAction action, const char* ext, IFileDialogCompletionHandlerFunc completionHandler)
215{
216 assert(completionHandler != nullptr && "You must provide a completion handler on iOS");
217
218 NSString* pDefaultFileName = nil;
219 NSString* pDefaultPath = nil;
220 NSMutableArray* pFileTypes = [[NSMutableArray alloc] init];
221
222 if (fileName.GetLength())
223 pDefaultFileName = [NSString stringWithUTF8String:fileName.Get()];
224 else
225 pDefaultFileName = @"";
226
227 if (path.GetLength())
228 pDefaultPath = [NSString stringWithUTF8String:path.Get()];
229 else
230 pDefaultPath = @"";
231
232 fileName.Set(""); // reset it
233
234 if (CStringHasContents(ext))
235 {
236 NSArray* pFileExtensions = [[NSString stringWithUTF8String:ext] componentsSeparatedByString: @" "];
237
238 for (NSString* pFileExtension in pFileExtensions)
239 {
240 UTType* pUTType = [UTType typeWithFilenameExtension:pFileExtension];
241 [pFileTypes addObject:pUTType];
242 }
243 }
244
245 [(IGRAPHICS_VIEW*) mView promptForFile: pDefaultFileName : pDefaultPath : action : pFileTypes : completionHandler];
246}
247
248void IGraphicsIOS::PromptForDirectory(WDL_String& path, IFileDialogCompletionHandlerFunc completionHandler)
249{
250 assert(completionHandler != nullptr && "You must provide a completion handler on iOS");
251
252 NSString* pDefaultPath = nil;
253
254 if (path.GetLength())
255 pDefaultPath = [NSString stringWithUTF8String:path.Get()];
256 else
257 pDefaultPath = @"";
258
259 path.Set(""); // reset it
260
261 [(IGRAPHICS_VIEW*) mView promptForDirectory:pDefaultPath : completionHandler];
262}
263
264bool IGraphicsIOS::PromptForColor(IColor& color, const char* str, IColorPickerHandlerFunc func)
265{
266 [(IGRAPHICS_VIEW*) mView promptForColor: color: str: func];
267 return false;
268}
269
270IPopupMenu* IGraphicsIOS::CreatePlatformPopupMenu(IPopupMenu& menu, const IRECT bounds, bool& isAsync)
271{
272 IPopupMenu* pReturnMenu = nullptr;
273 isAsync = true;
274 if (mView)
275 {
276 CGRect areaRect = ToCGRect(this, bounds);
277 pReturnMenu = [(IGRAPHICS_VIEW*) mView createPopupMenu: menu: areaRect];
278 }
279
280 //synchronous
281 if(pReturnMenu && pReturnMenu->GetFunction())
282 pReturnMenu->ExecFunction();
283
284 return pReturnMenu;
285}
286
287void IGraphicsIOS::CreatePlatformTextEntry(int paramIdx, const IText& text, const IRECT& bounds, int length, const char* str)
288{
289 ReleaseMouseCapture();
290 CGRect areaRect = ToCGRect(this, bounds);
291 [(IGRAPHICS_VIEW*) mView createTextEntry: paramIdx : text: str: length: areaRect];
292}
293
294bool IGraphicsIOS::OpenURL(const char* url, const char* msgWindowTitle, const char* confirmMsg, const char* errMsgOnFailure)
295{
296 NSURL* pNSURL = nullptr;
297 if (strstr(url, "http"))
298 pNSURL = [NSURL URLWithString:[NSString stringWithUTF8String:url]];
299 else
300 pNSURL = [NSURL fileURLWithPath:[NSString stringWithUTF8String:url]];
301
302 if (pNSURL)
303 {
304 UIResponder* pResponder = (UIResponder*) mView;
305 while(pResponder) {
306 if ([pResponder respondsToSelector: @selector(openURL:)])
307 [pResponder performSelector: @selector(openURL:) withObject: pNSURL];
308
309 pResponder = [pResponder nextResponder];
310 }
311 return true;
312 }
313 return false;
314}
315
316void* IGraphicsIOS::GetWindow()
317{
318 if (mView)
319 return mView;
320 else
321 return 0;
322}
323
324// static
325int IGraphicsIOS::GetUserOSVersion()
326{
327 return (int) 0; //TODO
328}
329
330bool IGraphicsIOS::GetTextFromClipboard(WDL_String& str)
331{
332 return false;
333}
334
335bool IGraphicsIOS::SetTextInClipboard(const char* str)
336{
337 return false;
338}
339
340PlatformFontPtr IGraphicsIOS::LoadPlatformFont(const char* fontID, const char* fileNameOrResID)
341{
342 return CoreTextHelpers::LoadPlatformFont(fontID, fileNameOrResID, GetBundleID());
343}
344
345PlatformFontPtr IGraphicsIOS::LoadPlatformFont(const char* fontID, const char* fontName, ETextStyle style)
346{
347 return CoreTextHelpers::LoadPlatformFont(fontID, fontName, style);
348}
349
350PlatformFontPtr IGraphicsIOS::LoadPlatformFont(const char* fontID, void* pData, int dataSize)
351{
352 return CoreTextHelpers::LoadPlatformFont(fontID, pData, dataSize);
353}
354
355void IGraphicsIOS::CachePlatformFont(const char* fontID, const PlatformFontPtr& font)
356{
357 CoreTextHelpers::CachePlatformFont(fontID, font, sFontDescriptorCache);
358}
359
360void IGraphicsIOS::LaunchBluetoothMidiDialog(float x, float y)
361{
362 ReleaseMouseCapture();
363 NSDictionary* dic = @{@"x": @(x), @"y": @(y)};
364 [[NSNotificationCenter defaultCenter] postNotificationName:@"LaunchBTMidiDialog" object:nil userInfo:dic];
365}
366
367EUIAppearance IGraphicsIOS::GetUIAppearance() const
368{
369 IGRAPHICS_VIEW* pView = (IGRAPHICS_VIEW*) mView;
370
371 if (pView)
372 {
373 return [[pView traitCollection] userInterfaceStyle] == UIUserInterfaceStyleDark ? EUIAppearance::Dark
374 : EUIAppearance::Light;
375 }
376 else
377 {
378 return EUIAppearance::Light;
379 }
380}
381
382void IGraphicsIOS::ActivateGLContext()
383{
384 IGRAPHICS_VIEW* pView = (IGRAPHICS_VIEW*) mView;
385 [pView activateGLContext];
386}
387
388void IGraphicsIOS::DeactivateGLContext()
389{
390 IGRAPHICS_VIEW* pView = (IGRAPHICS_VIEW*) mView;
391 [pView deactivateGLContext];
392}
393
394
395#if defined IGRAPHICS_NANOVG
396 #include "IGraphicsNanoVG.cpp"
397#elif defined IGRAPHICS_SKIA
398 #include "IGraphicsSkia.cpp"
399#else
400 #error Either NO_IGRAPHICS or one and only one choice of graphics library must be defined!
401#endif
An editor delegate base class that uses IGraphics for the UI.
virtual void AttachGestureRecognizer(EGestureType type)
Registers a gesture recognizer with the graphics context.
Definition: IGraphics.cpp:2396
A class for setting the contents of a pop up menu.
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,...