comparison ios/dw.m @ 2569:97b30df25fd1

iOS: If DW_FCF_TITLEBAR is passed to dw_window_new() create a UINavigationBar and an options menu similar to how it works on Android. The options menu will only function on iOS 14 or higher, but the Navigation bar like a titlebar will work on iOS 13 without the menu.
author bsmith@81767d24-ef19-dc11-ae90-00e081727c95
date Thu, 20 May 2021 10:06:07 +0000
parents bb75e64e6138
children 2c2941e01b67
comparison
equal deleted inserted replaced
2568:b536b7b21682 2569:97b30df25fd1
772 -(void)layoutSubviews { }; 772 -(void)layoutSubviews { };
773 @end 773 @end
774 774
775 @interface DWWindow : UIWindow 775 @interface DWWindow : UIWindow
776 { 776 {
777 UIMenu *popupmenu; 777 DWMenu *windowmenu, *popupmenu;
778 int redraw; 778 int redraw;
779 int shown; 779 int shown;
780 } 780 }
781 -(void)sendEvent:(UIEvent *)theEvent; 781 -(void)sendEvent:(UIEvent *)theEvent;
782 -(void)keyDown:(UIEvent *)theEvent; 782 -(void)keyDown:(UIEvent *)theEvent;
784 -(int)redraw; 784 -(int)redraw;
785 -(void)setRedraw:(int)val; 785 -(void)setRedraw:(int)val;
786 -(int)shown; 786 -(int)shown;
787 -(void)setShown:(int)val; 787 -(void)setShown:(int)val;
788 -(void)layoutSubviews; 788 -(void)layoutSubviews;
789 -(UIMenu *)popupMenu; 789 -(void)setMenu:(DWMenu *)input;
790 -(void)setPopupMenu:(UIMenu *)input; 790 -(void)setPopupMenu:(DWMenu *)input;
791 -(DWMenu *)menu;
792 -(DWMenu *)popupMenu;
791 @end 793 @end
792 794
793 @implementation DWWindow 795 @implementation DWWindow
794 -(void)sendEvent:(UIEvent *)theEvent 796 -(void)sendEvent:(UIEvent *)theEvent
795 { 797 {
805 -(void)mouseDragged:(UIEvent *)theEvent { _dw_event_handler(self, theEvent, 5); } 807 -(void)mouseDragged:(UIEvent *)theEvent { _dw_event_handler(self, theEvent, 5); }
806 -(int)redraw { return redraw; } 808 -(int)redraw { return redraw; }
807 -(void)setRedraw:(int)val { redraw = val; } 809 -(void)setRedraw:(int)val { redraw = val; }
808 -(int)shown { return shown; } 810 -(int)shown { return shown; }
809 -(void)setShown:(int)val { shown = val; } 811 -(void)setShown:(int)val { shown = val; }
810 -(void)dealloc { dw_signal_disconnect_by_window(self); [super dealloc]; }
811 -(void)layoutSubviews { } 812 -(void)layoutSubviews { }
812 -(UIMenu *)popupMenu { return popupmenu; } 813 -(void)setMenu:(DWMenu *)input { [windowmenu release]; windowmenu = input; [windowmenu retain]; }
813 -(void)setPopupMenu:(UIMenu *)input { [popupmenu release]; popupmenu = input; [popupmenu retain]; } 814 -(void)setPopupMenu:(DWMenu *)input { [popupmenu release]; popupmenu = input; [popupmenu retain]; }
815 -(DWMenu *)menu { return windowmenu; }
816 -(DWMenu *)popupMenu { return popupmenu; }
817 -(void)dealloc
818 {
819 if(windowmenu)
820 [windowmenu release];
821 if(popupmenu)
822 [popupmenu release];
823 dw_signal_disconnect_by_window(self);
824 [super dealloc];
825 }
814 @end 826 @end
815 827
816 @interface DWImage : NSObject 828 @interface DWImage : NSObject
817 { 829 {
818 UIImage *image; 830 UIImage *image;
1343 @end 1355 @end
1344 1356
1345 /* Subclass for a top-level window */ 1357 /* Subclass for a top-level window */
1346 @interface DWView : DWBox /* <UIWindowDelegate> */ 1358 @interface DWView : DWBox /* <UIWindowDelegate> */
1347 { 1359 {
1348 DWMenu *windowmenu, *popupmenu;
1349 CGSize oldsize; 1360 CGSize oldsize;
1350 } 1361 }
1351 -(BOOL)windowShouldClose:(id)sender; 1362 -(BOOL)windowShouldClose:(id)sender;
1352 -(void)setMenu:(DWMenu *)input;
1353 -(void)setPopupMenu:(DWMenu *)input;
1354 -(DWMenu *)menu;
1355 -(DWMenu *)popupMenu;
1356 -(void)windowDidBecomeMain:(id)sender; 1363 -(void)windowDidBecomeMain:(id)sender;
1357 -(void)menuHandler:(id)sender; 1364 -(void)menuHandler:(id)sender;
1358 @end 1365 @end
1359 1366
1360 @implementation DWView 1367 @implementation DWView
1369 if(newSuperview) 1376 if(newSuperview)
1370 [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(windowDidBecomeMain:) name:UIWindowDidBecomeKeyNotification object:[newSuperview window]]; 1377 [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(windowDidBecomeMain:) name:UIWindowDidBecomeKeyNotification object:[newSuperview window]];
1371 } 1378 }
1372 -(void)dealloc 1379 -(void)dealloc
1373 { 1380 {
1374 if(windowmenu)
1375 {
1376 [windowmenu release];
1377 }
1378 [[NSNotificationCenter defaultCenter] removeObserver:self]; 1381 [[NSNotificationCenter defaultCenter] removeObserver:self];
1379 dw_signal_disconnect_by_window(self); 1382 dw_signal_disconnect_by_window(self);
1380 [super dealloc]; 1383 [super dealloc];
1381 } 1384 }
1382 -(void)windowResized:(CGSize)size; 1385 -(void)windowResized:(CGSize)size;
1403 } 1406 }
1404 -(void)windowDidBecomeMain:(id)sender 1407 -(void)windowDidBecomeMain:(id)sender
1405 { 1408 {
1406 _dw_event_handler([self window], nil, 13); 1409 _dw_event_handler([self window], nil, 13);
1407 } 1410 }
1408 -(void)setMenu:(DWMenu *)input { windowmenu = input; [windowmenu retain]; }
1409 -(void)setPopupMenu:(DWMenu *)input { popupmenu = input; [popupmenu retain]; }
1410 -(DWMenu *)menu { return windowmenu; }
1411 -(DWMenu *)popupMenu { return popupmenu; }
1412 -(void)menuHandler:(id)sender 1411 -(void)menuHandler:(id)sender
1413 { 1412 {
1414 [DWObj menuHandler:sender]; 1413 [DWObj menuHandler:sender];
1415 } 1414 }
1416 @end 1415 @end
1423 @implementation DWViewController : UIViewController {} 1422 @implementation DWViewController : UIViewController {}
1424 -(void)viewWillLayoutSubviews 1423 -(void)viewWillLayoutSubviews
1425 { 1424 {
1426 DWWindow *window = (DWWindow *)[[self view] window]; 1425 DWWindow *window = (DWWindow *)[[self view] window];
1427 NSArray *array = [window subviews]; 1426 NSArray *array = [window subviews];
1428 DWView *view = [array firstObject];
1429 CGRect frame = [window frame]; 1427 CGRect frame = [window frame];
1430 /* Hide the UITransitionView which is blocking the screen... 1428 DWView *view = nil;
1431 * This is probably not the correct solution, but it solves the 1429 UINavigationBar *nav = nil;
1432 * problem for the moment. Figure out what to do with this view. 1430 NSInteger sbheight = 0;
1433 */ 1431
1434 id object = [array lastObject]; 1432 for(id obj in array)
1435 if(![object isMemberOfClass:[DWView class]]) 1433 {
1436 [object setHidden:YES]; 1434 if([obj isMemberOfClass:[DWView class]])
1437 /* Adjust the frame to account for the status bar */ 1435 view = obj;
1438 NSInteger sbheight = [[[window windowScene] statusBarManager] statusBarFrame].size.height; 1436 else if([obj isMemberOfClass:[UINavigationBar class]])
1437 nav = obj;
1438 /* Hide the UITransitionView which is blocking the screen...
1439 * This is probably not the correct solution, but it solves the
1440 * problem for the moment. Figure out what to do with this view.
1441 */
1442 else
1443 [obj setHidden:YES];
1444 }
1445 /* Adjust the frame to account for the status bar and navigation bar if it exists */
1446 if(nav)
1447 {
1448 CGRect navrect = [nav frame];
1449
1450 sbheight = navrect.size.height;
1451 navrect.size.width = frame.size.width;
1452 [nav setFrame:navrect];
1453
1454 if (@available(iOS 14.0, *)) {
1455 DWMenu *windowmenu = [window menu];
1456 UINavigationItem *item = [[nav items] firstObject];
1457
1458 if(windowmenu && !item.rightBarButtonItem)
1459 {
1460 UIBarButtonItem *options = [[UIBarButtonItem alloc] initWithImage:[UIImage systemImageNamed:@"list.bullet"]
1461 menu:[windowmenu menu]];
1462 item.rightBarButtonItem = options;
1463 }
1464 } else {
1465 // Fallback on earlier versions
1466 }
1467 }
1468 else
1469 sbheight = [[[window windowScene] statusBarManager] statusBarFrame].size.height;
1439 frame.size.height -= sbheight; 1470 frame.size.height -= sbheight;
1440 /* Account for the special area on iPhone X and iPad Pro 1471 /* Account for the special area on iPhone X and iPad Pro
1441 * https://blog.maxrudberg.com/post/165590234593/ui-design-for-iphone-x-bottom-elements 1472 * https://blog.maxrudberg.com/post/165590234593/ui-design-for-iphone-x-bottom-elements
1442 */ 1473 */
1443 frame.size.height -= 24; 1474 frame.size.height -= 24;
2124 2155
2125 _dw_event_handler(self, (UIEvent *)params, 10); 2156 _dw_event_handler(self, (UIEvent *)params, 10);
2126 2157
2127 if(window) 2158 if(window)
2128 { 2159 {
2129 __block UIMenu *popupmenu = [window popupMenu]; 2160 __block UIMenu *popupmenu = [[window popupMenu] menu];
2130 config = [UIContextMenuConfiguration configurationWithIdentifier:@"DWContextMenu" 2161 config = [UIContextMenuConfiguration configurationWithIdentifier:@"DWContextMenu"
2131 previewProvider:nil 2162 previewProvider:nil
2132 actionProvider:^(NSArray* suggestedAction){return popupmenu;}]; 2163 actionProvider:^(NSArray* suggestedAction){return popupmenu;}];
2133 [window setPopupMenu:nil]; 2164 [window setPopupMenu:nil];
2134 } 2165 }
7547 * Parameters: 7578 * Parameters:
7548 * location: Handle of a window frame to be attached to. 7579 * location: Handle of a window frame to be attached to.
7549 */ 7580 */
7550 HMENUI API dw_menubar_new(HWND location) 7581 HMENUI API dw_menubar_new(HWND location)
7551 { 7582 {
7552 /* TODO: Implement this with UIMenuSystem */ 7583 DWWindow *window = location;
7553 return NULL; 7584 DWMenu *menu = [[[DWMenu alloc] init] retain];
7585
7586 [window setMenu:menu];
7587 return menu;
7554 } 7588 }
7555 7589
7556 /* 7590 /*
7557 * Destroys a menu created with dw_menubar_new or dw_menu_new. 7591 * Destroys a menu created with dw_menubar_new or dw_menu_new.
7558 * Parameters: 7592 * Parameters:
7963 DW_FUNCTION_ADD_PARAM3(hwndOwner, title, flStyle) 7997 DW_FUNCTION_ADD_PARAM3(hwndOwner, title, flStyle)
7964 DW_FUNCTION_RETURN(dw_window_new, HWND) 7998 DW_FUNCTION_RETURN(dw_window_new, HWND)
7965 DW_FUNCTION_RESTORE_PARAM3(DW_UNUSED(hwndOwner), HWND, title, char *, DW_UNUSED(flStyle), ULONG) 7999 DW_FUNCTION_RESTORE_PARAM3(DW_UNUSED(hwndOwner), HWND, title, char *, DW_UNUSED(flStyle), ULONG)
7966 { 8000 {
7967 DW_FUNCTION_INIT; 8001 DW_FUNCTION_INIT;
7968 DWWindow *window = [[DWWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]]; 8002 CGRect screenrect = [[UIScreen mainScreen] bounds];
8003 DWWindow *window = [[DWWindow alloc] initWithFrame:screenrect];
7969 DWView *view = [[DWView alloc] init]; 8004 DWView *view = [[DWView alloc] init];
7970 UIUserInterfaceStyle style = [[DWObj hiddenWindow] overrideUserInterfaceStyle]; 8005 UIUserInterfaceStyle style = [[DWObj hiddenWindow] overrideUserInterfaceStyle];
7971 8006
7972 [window setWindowLevel:UIWindowLevelNormal]; 8007 [window setWindowLevel:UIWindowLevelNormal];
7973 [window setRootViewController:[[DWViewController alloc] init]]; 8008 [window setRootViewController:[[DWViewController alloc] init]];
7974 [window addSubview:view]; 8009 [window addSubview:view];
7975 [window setBackgroundColor:[UIColor systemBackgroundColor]]; 8010 [window setBackgroundColor:[UIColor systemBackgroundColor]];
7976 8011
7977 /* TODO: Handle style flags... if we can? There is no visible frame */ 8012 /* TODO: Handle style flags... if we can? There is no visible frame */
7978 if(@available(iOS 13.0, *)) { 8013 if(@available(iOS 13.0, *)) {
7979 [window setLargeContentTitle:[NSString stringWithUTF8String:title]]; 8014 NSString *nstitle = [NSString stringWithUTF8String:title];
8015 [window setLargeContentTitle:nstitle];
8016 if(flStyle & DW_FCF_TITLEBAR)
8017 {
8018 UINavigationBar* navbar = [[UINavigationBar alloc] initWithFrame:CGRectMake(0, 0, screenrect.size.width, 60)];
8019 UINavigationItem* navItem = [[UINavigationItem alloc] initWithTitle:nstitle];
8020
8021 [navbar setItems:@[navItem]];
8022 [window addSubview:navbar];
8023 }
7980 } 8024 }
7981 /* Copy the overrideUserInterfaceStyle property from the hiddenWindow */ 8025 /* Copy the overrideUserInterfaceStyle property from the hiddenWindow */
7982 if(style != UIUserInterfaceStyleUnspecified) 8026 if(style != UIUserInterfaceStyleUnspecified)
7983 [window setOverrideUserInterfaceStyle:style]; 8027 [window setOverrideUserInterfaceStyle:style];
7984 DW_FUNCTION_RETURN_THIS(window); 8028 DW_FUNCTION_RETURN_THIS(window);
8544 DW_FUNCTION_NO_RETURN(dw_window_set_text) 8588 DW_FUNCTION_NO_RETURN(dw_window_set_text)
8545 DW_FUNCTION_RESTORE_PARAM2(handle, HWND, text, char *) 8589 DW_FUNCTION_RESTORE_PARAM2(handle, HWND, text, char *)
8546 { 8590 {
8547 DW_FUNCTION_INIT; 8591 DW_FUNCTION_INIT;
8548 id object = _dw_text_handle(handle); 8592 id object = _dw_text_handle(handle);
8593 Item *item = NULL;
8549 8594
8550 if([object isKindOfClass:[UILabel class]] || [object isKindOfClass:[UITextField class]]) 8595 if([object isKindOfClass:[UILabel class]] || [object isKindOfClass:[UITextField class]])
8596 {
8551 [object setText:[NSString stringWithUTF8String:text]]; 8597 [object setText:[NSString stringWithUTF8String:text]];
8598 item = _dw_box_item(handle);
8599 }
8600 else if([object isMemberOfClass:[DWWindow class]])
8601 {
8602 DWWindow *window = object;
8603 NSArray *array = [window subviews];
8604
8605 for(id obj in array)
8606 {
8607 if([obj isMemberOfClass:[UINavigationBar class]])
8608 {
8609 UINavigationBar *nav = obj;
8610 UINavigationItem *item = [[nav items] firstObject];
8611
8612 [item setTitle:[NSString stringWithUTF8String:text]];
8613 }
8614 }
8615 }
8552 #ifdef DW_INCLUDE_DEPRECATED 8616 #ifdef DW_INCLUDE_DEPRECATED
8553 else if([object isKindOfClass:[UIControl class]]) 8617 else if([object isKindOfClass:[UIControl class]])
8554 { 8618 {
8555 UIControl *control = object; 8619 UIControl *control = object;
8556 [control setText:[NSString stringWithUTF8String:text]]; 8620 [control setText:[NSString stringWithUTF8String:text]];
8621 item = _dw_box_item(handle);
8557 } 8622 }
8558 #endif 8623 #endif
8559 else 8624 /* If we changed the text...
8560 return; 8625 * Check to see if any of the sizes need to be recalculated
8561 /* If we changed the text... */ 8626 */
8562 Item *item = _dw_box_item(handle);
8563
8564 /* Check to see if any of the sizes need to be recalculated */
8565 if(item && (item->origwidth == -1 || item->origheight == -1)) 8627 if(item && (item->origwidth == -1 || item->origheight == -1))
8566 { 8628 {
8567 int newwidth, newheight; 8629 int newwidth, newheight;
8568 8630
8569 _dw_control_size(handle, &newwidth, &newheight); 8631 _dw_control_size(handle, &newwidth, &newheight);