1/* 2 Simple DirectMedia Layer 3 Copyright (C) 1997-2016 Sam Lantinga <slouken@libsdl.org> 4 5 This software is provided 'as-is', without any express or implied 6 warranty. In no event will the authors be held liable for any damages 7 arising from the use of this software. 8 9 Permission is granted to anyone to use this software for any purpose, 10 including commercial applications, and to alter it and redistribute it 11 freely, subject to the following restrictions: 12 13 1. The origin of this software must not be misrepresented; you must not 14 claim that you wrote the original software. If you use this software 15 in a product, an acknowledgment in the product documentation would be 16 appreciated but is not required. 17 2. Altered source versions must be plainly marked as such, and must not be 18 misrepresented as being the original software. 19 3. This notice may not be removed or altered from any source distribution. 20*/ 21#include "../../SDL_internal.h" 22 23#if SDL_VIDEO_DRIVER_UIKIT 24 25#include "SDL.h" 26#include "SDL_uikitvideo.h" 27#include "SDL_uikitwindow.h" 28 29/* Display a UIKit message box */ 30 31static SDL_bool s_showingMessageBox = SDL_FALSE; 32 33SDL_bool 34UIKit_ShowingMessageBox() 35{ 36 return s_showingMessageBox; 37} 38 39static void 40UIKit_WaitUntilMessageBoxClosed(const SDL_MessageBoxData *messageboxdata, int *clickedindex) 41{ 42 *clickedindex = messageboxdata->numbuttons; 43 44 @autoreleasepool { 45 /* Run the main event loop until the alert has finished */ 46 /* Note that this needs to be done on the main thread */ 47 s_showingMessageBox = SDL_TRUE; 48 while ((*clickedindex) == messageboxdata->numbuttons) { 49 [[NSRunLoop currentRunLoop] runMode:NSDefaultRunLoopMode beforeDate:[NSDate distantFuture]]; 50 } 51 s_showingMessageBox = SDL_FALSE; 52 } 53} 54 55static BOOL 56UIKit_ShowMessageBoxAlertController(const SDL_MessageBoxData *messageboxdata, int *buttonid) 57{ 58#ifdef __IPHONE_8_0 59 int i; 60 int __block clickedindex = messageboxdata->numbuttons; 61 const SDL_MessageBoxButtonData *buttons = messageboxdata->buttons; 62 UIWindow *window = nil; 63 UIWindow *alertwindow = nil; 64 65 if (![UIAlertController class]) { 66 return NO; 67 } 68 69 UIAlertController *alert; 70 alert = [UIAlertController alertControllerWithTitle:@(messageboxdata->title) 71 message:@(messageboxdata->message) 72 preferredStyle:UIAlertControllerStyleAlert]; 73 74 for (i = 0; i < messageboxdata->numbuttons; i++) { 75 UIAlertAction *action; 76 UIAlertActionStyle style = UIAlertActionStyleDefault; 77 78 if (buttons[i].flags & SDL_MESSAGEBOX_BUTTON_ESCAPEKEY_DEFAULT) { 79 style = UIAlertActionStyleCancel; 80 } 81 82 action = [UIAlertAction actionWithTitle:@(buttons[i].text) 83 style:style 84 handler:^(UIAlertAction *action) { 85 clickedindex = i; 86 }]; 87 [alert addAction:action]; 88 } 89 90 if (messageboxdata->window) { 91 SDL_WindowData *data = (__bridge SDL_WindowData *) messageboxdata->window->driverdata; 92 window = data.uiwindow; 93 } 94 95 if (window == nil || window.rootViewController == nil) { 96 alertwindow = [[UIWindow alloc] initWithFrame:[UIScreen mainScreen].bounds]; 97 alertwindow.rootViewController = [UIViewController new]; 98 alertwindow.windowLevel = UIWindowLevelAlert; 99 100 window = alertwindow; 101 102 [alertwindow makeKeyAndVisible]; 103 } 104 105 [window.rootViewController presentViewController:alert animated:YES completion:nil]; 106 UIKit_WaitUntilMessageBoxClosed(messageboxdata, &clickedindex); 107 108 if (alertwindow) { 109 alertwindow.hidden = YES; 110 } 111 112 *buttonid = messageboxdata->buttons[clickedindex].buttonid; 113 return YES; 114#else 115 return NO; 116#endif /* __IPHONE_8_0 */ 117} 118 119/* UIAlertView is deprecated in iOS 8+ in favor of UIAlertController. */ 120#if __IPHONE_OS_VERSION_MIN_REQUIRED < 80000 121@interface SDLAlertViewDelegate : NSObject <UIAlertViewDelegate> 122 123@property (nonatomic, assign) int *clickedIndex; 124 125@end 126 127@implementation SDLAlertViewDelegate 128 129- (void)alertView:(UIAlertView *)alertView didDismissWithButtonIndex:(NSInteger)buttonIndex 130{ 131 if (_clickedIndex != NULL) { 132 *_clickedIndex = (int) buttonIndex; 133 } 134} 135 136@end 137#endif /* __IPHONE_OS_VERSION_MIN_REQUIRED < 80000 */ 138 139static BOOL 140UIKit_ShowMessageBoxAlertView(const SDL_MessageBoxData *messageboxdata, int *buttonid) 141{ 142 /* UIAlertView is deprecated in iOS 8+ in favor of UIAlertController. */ 143#if __IPHONE_OS_VERSION_MIN_REQUIRED < 80000 144 int i; 145 int clickedindex = messageboxdata->numbuttons; 146 const SDL_MessageBoxButtonData *buttons = messageboxdata->buttons; 147 UIAlertView *alert = [[UIAlertView alloc] init]; 148 SDLAlertViewDelegate *delegate = [[SDLAlertViewDelegate alloc] init]; 149 150 alert.delegate = delegate; 151 alert.title = @(messageboxdata->title); 152 alert.message = @(messageboxdata->message); 153 154 for (i = 0; i < messageboxdata->numbuttons; i++) { 155 [alert addButtonWithTitle:@(buttons[i].text)]; 156 } 157 158 delegate.clickedIndex = &clickedindex; 159 160 [alert show]; 161 162 UIKit_WaitUntilMessageBoxClosed(messageboxdata, &clickedindex); 163 164 alert.delegate = nil; 165 166 *buttonid = messageboxdata->buttons[clickedindex].buttonid; 167 return YES; 168#else 169 return NO; 170#endif /* __IPHONE_OS_VERSION_MIN_REQUIRED < 80000 */ 171} 172 173int 174UIKit_ShowMessageBox(const SDL_MessageBoxData *messageboxdata, int *buttonid) 175{ 176 BOOL success = NO; 177 178 @autoreleasepool { 179 success = UIKit_ShowMessageBoxAlertController(messageboxdata, buttonid); 180 if (!success) { 181 success = UIKit_ShowMessageBoxAlertView(messageboxdata, buttonid); 182 } 183 } 184 185 if (!success) { 186 return SDL_SetError("Could not show message box."); 187 } 188 189 return 0; 190} 191 192#endif /* SDL_VIDEO_DRIVER_UIKIT */ 193 194/* vi: set ts=4 sw=4 expandtab: */ 195