From 096930b02eb6c27501e262a68a9e69d1ba8b24c7 Mon Sep 17 00:00:00 2001 From: omigamedev Date: Mon, 9 Sep 2019 15:31:47 +0200 Subject: [PATCH] implement file picker in iOS with .ext to UTI filtering --- PanoPainter.xcodeproj/project.pbxproj | 4 ++ PanoPainter/GameViewController.h | 5 +++ PanoPainter/GameViewController.m | 63 ++++++++++++++++++++++++--- src/app_events.cpp | 22 ++++------ src/app_layout.cpp | 35 ++++----------- 5 files changed, 83 insertions(+), 46 deletions(-) diff --git a/PanoPainter.xcodeproj/project.pbxproj b/PanoPainter.xcodeproj/project.pbxproj index 83c6616..deedb4e 100644 --- a/PanoPainter.xcodeproj/project.pbxproj +++ b/PanoPainter.xcodeproj/project.pbxproj @@ -155,6 +155,7 @@ AD7FB09022470C75005913AB /* node_panel_floating.cpp in Sources */ = {isa = PBXBuildFile; fileRef = AD7FB08E22470C75005913AB /* node_panel_floating.cpp */; }; AD7FB09222470DE5005913AB /* app_vr.cpp in Sources */ = {isa = PBXBuildFile; fileRef = AD7FB09122470DE2005913AB /* app_vr.cpp */; }; AD7FB09322470DE5005913AB /* app_vr.cpp in Sources */ = {isa = PBXBuildFile; fileRef = AD7FB09122470DE2005913AB /* app_vr.cpp */; }; + AD83A0D323268B6F005B0871 /* MobileCoreServices.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = AD83A0D223268B6F005B0871 /* MobileCoreServices.framework */; }; ADA2A57822BE8D8E00C6B6C9 /* node_tool_bucket.cpp in Sources */ = {isa = PBXBuildFile; fileRef = ADA2A57622BE8D8E00C6B6C9 /* node_tool_bucket.cpp */; }; ADA2A57922BE8D8E00C6B6C9 /* node_tool_bucket.cpp in Sources */ = {isa = PBXBuildFile; fileRef = ADA2A57622BE8D8E00C6B6C9 /* node_tool_bucket.cpp */; }; ADA3ABF6222C8C370083B825 /* node_panel_quick.cpp in Sources */ = {isa = PBXBuildFile; fileRef = ADA3ABF4222C8C350083B825 /* node_panel_quick.cpp */; }; @@ -460,6 +461,7 @@ AD7FB08D22470C74005913AB /* node_panel_floating.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = node_panel_floating.h; sourceTree = ""; }; AD7FB08E22470C75005913AB /* node_panel_floating.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = node_panel_floating.cpp; sourceTree = ""; }; AD7FB09122470DE2005913AB /* app_vr.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = app_vr.cpp; sourceTree = ""; }; + AD83A0D223268B6F005B0871 /* MobileCoreServices.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = MobileCoreServices.framework; path = Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS12.4.sdk/System/Library/Frameworks/MobileCoreServices.framework; sourceTree = DEVELOPER_DIR; }; AD8CF71F1E913F0500083FFD /* log.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = log.cpp; sourceTree = ""; }; AD8CF7201E913F0500083FFD /* log.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = log.h; sourceTree = ""; }; AD95AEC31E41EDEC002DD03A /* font.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = font.cpp; sourceTree = ""; }; @@ -588,6 +590,7 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( + AD83A0D323268B6F005B0871 /* MobileCoreServices.framework in Frameworks */, ADC8F77F216678270084ECAD /* CoreTelephony.framework in Frameworks */, ADC8F780216678270084ECAD /* CoreText.framework in Frameworks */, ADC8F781216678270084ECAD /* QuartzCore.framework in Frameworks */, @@ -892,6 +895,7 @@ AD759B631F2793AD00211963 /* Frameworks */ = { isa = PBXGroup; children = ( + AD83A0D223268B6F005B0871 /* MobileCoreServices.framework */, ADF396DB216F6BD800024722 /* AppKit.framework */, ADFD32232166B12A00F46F85 /* Foundation.framework */, AD06989820CC6C3E0010825F /* OSX */, diff --git a/PanoPainter/GameViewController.h b/PanoPainter/GameViewController.h index aeaa846..41f69f9 100644 --- a/PanoPainter/GameViewController.h +++ b/PanoPainter/GameViewController.h @@ -16,19 +16,24 @@ @interface GameViewController : UIViewController< UIKeyInput, UIImagePickerControllerDelegate, + UIDocumentPickerDelegate, UINavigationControllerDelegate, UIDocumentInteractionControllerDelegate > { @public GameView* glview; @public EAGLContext* context; +@public bool input_enabled; } +- (void)show_keyboard; +- (void)hide_keyboard; - (void)display_file:(std::string)filename; - (void)reset_touch; - (void)async_lock; - (void)async_unlock; - (void)async_swap; - (void)pick_photo:(std::function) callback; +- (void)pick_file:(NSArray*)types then:(std::function)callback; - (void)registerForKeyboardNotifications; - (void)unregisterForKeyboardNotifications; - (void)crash; diff --git a/PanoPainter/GameViewController.m b/PanoPainter/GameViewController.m index 48610c4..259641e 100644 --- a/PanoPainter/GameViewController.m +++ b/PanoPainter/GameViewController.m @@ -12,6 +12,7 @@ #include "app.h" #include "settings.h" #import "objc_utils.h" +#import std::mutex render_mutex; std::condition_variable render_cv; @@ -25,6 +26,15 @@ std::condition_variable render_cv; @implementation GameImagePicker @end +@interface GameFilePicker : UIDocumentPickerViewController +{ + @public std::promise promise; + @public std::function callback; +} +@end +@implementation GameFilePicker +@end + //std::map< bool pen_down = false; int t_count = 0; @@ -152,15 +162,41 @@ std::recursive_mutex lock_mutex; GameImagePicker* p = static_cast(picker); std::string path = [chosenImage cStringUsingEncoding:NSUTF8StringEncoding]; p->callback(path); - [picker dismissViewControllerAnimated:YES completion:^{ - [self keyboardWasHidden:nil]; - }]; + [picker dismissViewControllerAnimated:YES completion:NULL]; } - (void)imagePickerControllerDidCancel:(UIImagePickerController *)picker { - [picker dismissViewControllerAnimated:YES completion:^{ - [self keyboardWasHidden:nil]; - }]; + [picker dismissViewControllerAnimated:YES completion:NULL]; +} + +- (void)pick_file:(NSArray*)types then:(std::function)callback +{ + // convert extension into UTIs from the system database + NSMutableArray* UTIs = [NSMutableArray arrayWithCapacity:types.count]; + for (NSString* ext : types) + { + NSString *typeForExt = (__bridge NSString*) + UTTypeCreatePreferredIdentifierForTag(kUTTagClassFilenameExtension, + (__bridge CFStringRef)ext, NULL); + [UTIs addObject:typeForExt]; + } + + GameFilePicker *picker = [[GameFilePicker alloc] initWithDocumentTypes:UTIs inMode:UIDocumentPickerModeImport]; + picker.delegate = self; + picker->callback = callback; + [self presentViewController:picker animated:YES completion:NULL]; +} +-(void)documentPicker:(UIDocumentPickerViewController *)controller didPickDocumentAtURL:(NSURL *)url +{ + NSString *chosenImage = [url path]; + GameFilePicker* p = static_cast(controller); + std::string path = [chosenImage cStringUsingEncoding:NSUTF8StringEncoding]; + p->callback(path); + [controller dismissViewControllerAnimated:YES completion:NULL]; +} +-(void)documentPickerWasCancelled:(UIDocumentPickerViewController *)controller +{ + [controller dismissViewControllerAnimated:YES completion:NULL]; } - (void)insertText:(NSString *)text @@ -185,7 +221,19 @@ std::recursive_mutex lock_mutex; return YES; } - (BOOL)canBecomeFirstResponder { - return YES; + return input_enabled; +} + +-(void)show_keyboard +{ + input_enabled = YES; + [self becomeFirstResponder]; +} + +-(void)hide_keyboard +{ + input_enabled = NO; + [self resignFirstResponder]; } // Call this method somewhere in your view controller setup code. @@ -416,6 +464,7 @@ std::set ignored_touch; - (void)viewDidLoad { [super viewDidLoad]; + input_enabled = NO; App::I = new App; App::I->ios_view = self; App::I->initLog(); diff --git a/src/app_events.cpp b/src/app_events.cpp index e9eb409..1293b29 100644 --- a/src/app_events.cpp +++ b/src/app_events.cpp @@ -105,8 +105,7 @@ void App::showKeyboard() redraw = true; #ifdef __IOS__ dispatch_async(dispatch_get_main_queue(), ^{ - //[ios_view registerForKeyboardNotifications]; - [ios_view becomeFirstResponder]; + [ios_view show_keyboard]; }); #elif __ANDROID__ displayKeyboard(true); @@ -119,8 +118,7 @@ void App::hideKeyboard() redraw = true; #ifdef __IOS__ dispatch_async(dispatch_get_main_queue(), ^{ - [ios_view resignFirstResponder]; - // [ios_view unregisterForKeyboardNotifications]; + [ios_view hide_keyboard]; }); #elif __ANDROID__ displayKeyboard(false); @@ -154,14 +152,14 @@ void App::pick_file(std::vector types, std::function* fileTypes = [NSMutableArray arrayWithCapacity:types.size()]; + for (const auto& t : types) + [fileTypes addObject:[NSString stringWithCString:t.c_str() encoding:NSUTF8StringEncoding]]; + [ios_view pick_file:fileTypes then:callback]; }); #elif __OSX__ dispatch_async(dispatch_get_main_queue(), ^{ - //NSArray* fileTypes = [NSArray arrayWithObjects:@"ppi", @"PPI", nil]; NSMutableArray* fileTypes = [NSMutableArray arrayWithCapacity:types.size()]; for (const auto& t : types) [fileTypes addObject:[NSString stringWithCString:t.c_str() encoding:NSUTF8StringEncoding]]; @@ -198,11 +196,9 @@ void App::pick_file_save(std::vector types, std::functionfind("file-import")) b->on_click = [this, popup](Node*) { - pick_file({ "JPG", "PNG", "ABR" }, [this](std::string path){ - std::string name, base, ext; - std::regex r(R"((.*)[\\/]([^\\/]+)\.(\w+)$)"); - std::smatch m; - if (!std::regex_search(path, m, r)) - return; - base = m[1].str(); - name = m[2].str(); - ext = m[3].str(); - - if (str_iequals(ext, "abr")) + pick_image([this](std::string path){ + Image img; + img.load_file(path); + if (img.width == img.height / 6 || img.width == img.height * 2) { - std::thread([this,path] { presets->import_abr(path); }).detach(); + Canvas::I->import_equirectangular(path); } else { - Image img; - img.load_file(path); - if (img.width == img.height / 6 || img.width == img.height * 2) - { - Canvas::I->import_equirectangular(path); - } - else - { - auto m = static_cast(canvas->m_canvas->modes[(int)kCanvasMode::Import][0]); - m->m_action = CanvasModeTransform::ActionType::Import; - m->m_source_image = std::move(img); - Canvas::set_mode(kCanvasMode::Import); - } - async_redraw(); + auto m = static_cast(canvas->m_canvas->modes[(int)kCanvasMode::Import][0]); + m->m_action = CanvasModeTransform::ActionType::Import; + m->m_source_image = std::move(img); + Canvas::set_mode(kCanvasMode::Import); } }); popup->mouse_release();