From ab2a3500337a1437f5553dad85165af5df426dd9 Mon Sep 17 00:00:00 2001 From: Alex Szpakowski Date: Fri, 25 Sep 2015 15:17:20 -0300 Subject: [PATCH] iOS: show message boxes using the new UIAlertController APIs when supported, rather than the deprecated UIAlertView. UIAlertController is also supported on tvOS, whereas UIAlertView is not. --- src/joystick/iphoneos/SDL_sysjoystick.m | 14 +- src/video/uikit/SDL_uikitmessagebox.m | 178 +++++++++++++++++----- src/video/uikit/SDL_uikitopengles.m | 2 - src/video/uikit/SDL_uikitviewcontroller.h | 2 - src/video/uikit/SDL_uikitviewcontroller.m | 6 - 5 files changed, 147 insertions(+), 55 deletions(-) diff --git a/src/joystick/iphoneos/SDL_sysjoystick.m b/src/joystick/iphoneos/SDL_sysjoystick.m index e9ad04963..38c0ffe17 100644 --- a/src/joystick/iphoneos/SDL_sysjoystick.m +++ b/src/joystick/iphoneos/SDL_sysjoystick.m @@ -181,7 +181,7 @@ SDL_SYS_AddJoystickDevice(GCController *controller, SDL_bool accelerometer) #endif /* !SDL_EVENTS_DISABLED */ } -SDL_JoystickDeviceItem * +static SDL_JoystickDeviceItem * SDL_SYS_RemoveJoystickDevice(SDL_JoystickDeviceItem *device) { SDL_JoystickDeviceItem *prev = NULL; @@ -374,12 +374,14 @@ SDL_SYS_JoystickOpen(SDL_Joystick * joystick, int device_index) } /* Function to determine if this joystick is attached to the system right now */ -SDL_bool SDL_SYS_JoystickAttached(SDL_Joystick *joystick) +SDL_bool +SDL_SYS_JoystickAttached(SDL_Joystick *joystick) { return joystick->hwdata != NULL; } -static void SDL_SYS_AccelerometerUpdate(SDL_Joystick * joystick) +static void +SDL_SYS_AccelerometerUpdate(SDL_Joystick * joystick) { const float maxgforce = SDL_IPHONE_MAX_GFORCE; const SInt16 maxsint16 = 0x7FFF; @@ -579,7 +581,8 @@ SDL_SYS_JoystickQuit(void) numjoysticks = 0; } -SDL_JoystickGUID SDL_SYS_JoystickGetDeviceGUID( int device_index ) +SDL_JoystickGUID +SDL_SYS_JoystickGetDeviceGUID( int device_index ) { SDL_JoystickDeviceItem *device = GetDeviceForIndex(device_index); SDL_JoystickGUID guid; @@ -591,7 +594,8 @@ SDL_JoystickGUID SDL_SYS_JoystickGetDeviceGUID( int device_index ) return guid; } -SDL_JoystickGUID SDL_SYS_JoystickGetGUID(SDL_Joystick * joystick) +SDL_JoystickGUID +SDL_SYS_JoystickGetGUID(SDL_Joystick * joystick) { SDL_JoystickGUID guid; if (joystick->hwdata) { diff --git a/src/video/uikit/SDL_uikitmessagebox.m b/src/video/uikit/SDL_uikitmessagebox.m index dea8bdc69..6c980d472 100644 --- a/src/video/uikit/SDL_uikitmessagebox.m +++ b/src/video/uikit/SDL_uikitmessagebox.m @@ -24,68 +24,166 @@ #include "SDL.h" #include "SDL_uikitvideo.h" - +#include "SDL_uikitwindow.h" /* Display a UIKit message box */ static SDL_bool s_showingMessageBox = SDL_FALSE; -@interface SDLAlertViewDelegate : NSObject - -@property (nonatomic, assign) int clickedIndex; - -@end - -@implementation SDLAlertViewDelegate - -- (void)alertView:(UIAlertView *)alertView didDismissWithButtonIndex:(NSInteger)buttonIndex -{ - _clickedIndex = (int)buttonIndex; -} - -@end - - SDL_bool UIKit_ShowingMessageBox() { return s_showingMessageBox; } -int -UIKit_ShowMessageBox(const SDL_MessageBoxData *messageboxdata, int *buttonid) +static void +UIKit_WaitUntilMessageBoxClosed(const SDL_MessageBoxData *messageboxdata, int *clickedindex) { - int i; - const SDL_MessageBoxButtonData *buttons = messageboxdata->buttons; + *clickedindex = messageboxdata->numbuttons; @autoreleasepool { - UIAlertView *alert = [[UIAlertView alloc] init]; - SDLAlertViewDelegate *delegate = [[SDLAlertViewDelegate alloc] init]; - - alert.delegate = delegate; - alert.title = @(messageboxdata->title); - alert.message = @(messageboxdata->message); - - for (i = 0; i < messageboxdata->numbuttons; ++i) { - [alert addButtonWithTitle:@(buttons[i].text)]; - } - - /* Set up for showing the alert */ - delegate.clickedIndex = messageboxdata->numbuttons; - - [alert show]; - /* Run the main event loop until the alert has finished */ /* Note that this needs to be done on the main thread */ s_showingMessageBox = SDL_TRUE; - while (delegate.clickedIndex == messageboxdata->numbuttons) { + while ((*clickedindex) == messageboxdata->numbuttons) { [[NSRunLoop currentRunLoop] runMode:NSDefaultRunLoopMode beforeDate:[NSDate distantFuture]]; } s_showingMessageBox = SDL_FALSE; + } +} - *buttonid = messageboxdata->buttons[delegate.clickedIndex].buttonid; +static BOOL +UIKit_ShowMessageBoxAlertController(const SDL_MessageBoxData *messageboxdata, int *buttonid) +{ +#ifdef __IPHONE_8_0 + int i; + int __block clickedindex = messageboxdata->numbuttons; + const SDL_MessageBoxButtonData *buttons = messageboxdata->buttons; + UIWindow *window = nil; + UIWindow *alertwindow = nil; - alert.delegate = nil; + if (![UIAlertController class]) { + return NO; + } + + UIAlertController *alert; + alert = [UIAlertController alertControllerWithTitle:@(messageboxdata->title) + message:@(messageboxdata->message) + preferredStyle:UIAlertControllerStyleAlert]; + + for (i = 0; i < messageboxdata->numbuttons; i++) { + UIAlertAction *action; + UIAlertActionStyle style = UIAlertActionStyleDefault; + + if (buttons[i].flags & SDL_MESSAGEBOX_BUTTON_ESCAPEKEY_DEFAULT) { + style = UIAlertActionStyleCancel; + } + + action = [UIAlertAction actionWithTitle:@(buttons[i].text) + style:style + handler:^(UIAlertAction *action) { + clickedindex = i; + }]; + [alert addAction:action]; + } + + if (messageboxdata->window) { + SDL_WindowData *data = (__bridge SDL_WindowData *) messageboxdata->window->driverdata; + window = data.uiwindow; + } + + if (window == nil || window.rootViewController == nil) { + alertwindow = [[UIWindow alloc] initWithFrame:[UIScreen mainScreen].bounds]; + alertwindow.rootViewController = [UIViewController new]; + alertwindow.windowLevel = UIWindowLevelAlert; + + window = alertwindow; + + [alertwindow makeKeyAndVisible]; + } + + [window.rootViewController presentViewController:alert animated:YES completion:nil]; + UIKit_WaitUntilMessageBoxClosed(messageboxdata, &clickedindex); + + if (alertwindow) { + alertwindow.hidden = YES; + } + + *buttonid = messageboxdata->buttons[clickedindex].buttonid; + return YES; +#else + return NO; +#endif /* __IPHONE_8_0 */ +} + +/* UIAlertView is deprecated in iOS 8+ in favor of UIAlertController. */ +#if __IPHONE_OS_VERSION_MIN_REQUIRED < 80000 +@interface SDLAlertViewDelegate : NSObject + +@property (nonatomic, assign) int *clickedIndex; + +@end + +@implementation SDLAlertViewDelegate + +- (void)alertView:(UIAlertView *)alertView didDismissWithButtonIndex:(NSInteger)buttonIndex +{ + if (_clickedIndex != NULL) { + *_clickedIndex = (int) buttonIndex; + } +} + +@end +#endif /* __IPHONE_OS_VERSION_MIN_REQUIRED < 80000 */ + +static BOOL +UIKit_ShowMessageBoxAlertView(const SDL_MessageBoxData *messageboxdata, int *buttonid) +{ + /* UIAlertView is deprecated in iOS 8+ in favor of UIAlertController. */ +#if __IPHONE_OS_VERSION_MIN_REQUIRED < 80000 + int i; + int clickedindex = messageboxdata->numbuttons; + const SDL_MessageBoxButtonData *buttons = messageboxdata->buttons; + UIAlertView *alert = [[UIAlertView alloc] init]; + SDLAlertViewDelegate *delegate = [[SDLAlertViewDelegate alloc] init]; + + alert.delegate = delegate; + alert.title = @(messageboxdata->title); + alert.message = @(messageboxdata->message); + + for (i = 0; i < messageboxdata->numbuttons; i++) { + [alert addButtonWithTitle:@(buttons[i].text)]; + } + + delegate.clickedIndex = &clickedindex; + + [alert show]; + + UIKit_WaitUntilMessageBoxClosed(messageboxdata, &clickedindex); + + alert.delegate = nil; + + *buttonid = messageboxdata->buttons[clickedindex].buttonid; + return YES; +#else + return NO; +#endif /* __IPHONE_OS_VERSION_MIN_REQUIRED < 80000 */ +} + +int +UIKit_ShowMessageBox(const SDL_MessageBoxData *messageboxdata, int *buttonid) +{ + BOOL success = NO; + + @autoreleasepool { + success = UIKit_ShowMessageBoxAlertController(messageboxdata, buttonid); + if (!success) { + success = UIKit_ShowMessageBoxAlertView(messageboxdata, buttonid); + } + } + + if (!success) { + return SDL_SetError("Could not show message box."); } return 0; diff --git a/src/video/uikit/SDL_uikitopengles.m b/src/video/uikit/SDL_uikitopengles.m index e9c26e318..ef901247f 100644 --- a/src/video/uikit/SDL_uikitopengles.m +++ b/src/video/uikit/SDL_uikitopengles.m @@ -52,8 +52,6 @@ @end -static int UIKit_GL_Initialize(_THIS); - void * UIKit_GL_GetProcAddress(_THIS, const char *proc) { diff --git a/src/video/uikit/SDL_uikitviewcontroller.h b/src/video/uikit/SDL_uikitviewcontroller.h index 17db0b26a..e8462b8e2 100644 --- a/src/video/uikit/SDL_uikitviewcontroller.h +++ b/src/video/uikit/SDL_uikitviewcontroller.h @@ -47,9 +47,7 @@ - (void)loadView; - (void)viewDidLayoutSubviews; - (NSUInteger)supportedInterfaceOrientations; -- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)orient; - (BOOL)prefersStatusBarHidden; -- (UIStatusBarStyle)preferredStatusBarStyle; #if SDL_IPHONE_KEYBOARD - (void)showKeyboard; diff --git a/src/video/uikit/SDL_uikitviewcontroller.m b/src/video/uikit/SDL_uikitviewcontroller.m index e1667aac8..112638eb2 100644 --- a/src/video/uikit/SDL_uikitviewcontroller.m +++ b/src/video/uikit/SDL_uikitviewcontroller.m @@ -135,12 +135,6 @@ return (window->flags & (SDL_WINDOW_FULLSCREEN|SDL_WINDOW_BORDERLESS)) != 0; } -- (UIStatusBarStyle)preferredStatusBarStyle -{ - /* We assume most SDL apps don't have a bright white background. */ - return UIStatusBarStyleLightContent; -} - /* ---- Keyboard related functionality below this line ---- */