SameBoy | Accurate GB/GBC emulator |
| download: https://git.y1.nz/archives/sameboy.tar.gz | |
| README | Files | Log | Refs | LICENSE |
commit a838c31d029636a634fe84d228ddfca4e02fb5c1 parent 7f0ad795ec00298b3a5d1e37005e75efe8aea192 Author: Lior Halphon <LIJI32@gmail.com> Date: Sun, 15 Jan 2023 18:37:25 +0200 Add a menu Diffstat:
| M | iOS/GBBackgroundView.m | 6 | ++++++ |
| A | iOS/GBMenuButton.h | 5 | +++++ |
| A | iOS/GBMenuButton.m | 23 | +++++++++++++++++++++++ |
| A | iOS/GBMenuViewController.h | 5 | +++++ |
| A | iOS/GBMenuViewController.m | 100 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
| M | iOS/GBViewController.h | 4 | ++++ |
| M | iOS/GBViewController.m | 30 | +++++++++++++++++++++++++----- |
| A | iOS/ModelTemplate@2x.png | 0 | |
| A | iOS/ModelTemplate@3x.png | 0 |
9 files changed, 168 insertions(+), 5 deletions(-)
diff --git a/iOS/GBBackgroundView.m b/iOS/GBBackgroundView.m @@ -1,6 +1,7 @@ #import "GBBackgroundView.h" #import "GBViewMetal.h" #import "GBHapticManager.h" +#import "GBMenuViewController.h" double CGPointSquaredDistance(CGPoint a, CGPoint b) { @@ -67,6 +68,11 @@ static void positionView(UIImageView *view, CGPoint position) - (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event { + for (UITouch *touch in touches) { + if (CGRectContainsPoint(self.gbView.frame, [touch locationInView:self])) { + [self.window.rootViewController presentViewController:[GBMenuViewController menu] animated:true completion:nil]; + } + } [_touches unionSet:touches]; [self touchesChanged]; } diff --git a/iOS/GBMenuButton.h b/iOS/GBMenuButton.h @@ -0,0 +1,5 @@ +#import <UIKit/UIKit.h> + +@interface GBMenuButton : UIButton + +@end diff --git a/iOS/GBMenuButton.m b/iOS/GBMenuButton.m @@ -0,0 +1,23 @@ +#import "GBMenuButton.h" + +@implementation GBMenuButton + +- (void)setFrame:(CGRect)frame +{ + [super setFrame:frame]; + if (!self.imageView.image) return; + CGSize imageSize = self.imageView.frame.size; + CGSize titleSize = self.titleLabel.frame.size; + + self.imageEdgeInsets = UIEdgeInsetsMake(0, + 0, + 28, + -titleSize.width); + + self.titleEdgeInsets = UIEdgeInsetsMake(36, + -imageSize.width, + 0, + 0); +} + +@end diff --git a/iOS/GBMenuViewController.h b/iOS/GBMenuViewController.h @@ -0,0 +1,5 @@ +#import <UIKit/UIKit.h> + +@interface GBMenuViewController : UIAlertController ++ (instancetype)menu; +@end diff --git a/iOS/GBMenuViewController.m b/iOS/GBMenuViewController.m @@ -0,0 +1,100 @@ +#import <objc/runtime.h> +#import "GBMenuViewController.h" +#import "GBMenuButton.h" +#import "GBViewController.h" +#import "GBROMManager.h" + +@interface GBMenuViewController () + +@end + +@implementation GBMenuViewController + ++ (instancetype)menu +{ + UIAlertControllerStyle style = [UIDevice currentDevice].userInterfaceIdiom == UIUserInterfaceIdiomPad? + UIAlertControllerStyleAlert : UIAlertControllerStyleActionSheet; + GBMenuViewController *ret = [self alertControllerWithTitle:nil + message:nil + preferredStyle:style]; + [ret addAction:[UIAlertAction actionWithTitle:@"Close" + style:UIAlertActionStyleCancel + handler:^(UIAlertAction * _Nonnull action) { + [(GBViewController *)[UIApplication sharedApplication].delegate start]; + }]]; + return ret; +} + +// The redundant sizeof forces the compiler to validate the selector exists +#define SelectorString(x) (sizeof(@selector(x))? @#x : nil) + +- (void)viewWillAppear:(BOOL)animated +{ + [super viewWillAppear:true]; + static const struct { + NSString *label; + NSString *image; + NSString *selector; + } buttons[] = { + {@"Reset", @"arrow.2.circlepath", SelectorString(reset)}, + {@"Library", @"bookmark", SelectorString(openLibrary)}, + {@"Model", @"ModelTemplate", nil}, + {@"States", @"square.stack", nil}, + {@"Settings", @"gear", nil}, + {@"About", @"info.circle", nil}, + }; + + double width = self.view.frame.size.width / 3; + double height = 88; + for (unsigned i = 0; i < 6; i++) { + unsigned x = i % 3; + unsigned y = i / 3; + GBMenuButton *button = [GBMenuButton buttonWithType:UIButtonTypeSystem]; + [button setTitle:buttons[i].label forState:UIControlStateNormal]; + if (@available(iOS 13.0, *)) { + UIImage *image = [UIImage imageNamed:buttons[i].image] ?: [UIImage systemImageNamed:buttons[i].image]; + [button setImage:image forState:UIControlStateNormal]; + } + button.frame = CGRectMake(width * x, height * y, width, height); + button.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleLeftMargin | UIViewAutoresizingFlexibleRightMargin; + [self.view addSubview:button]; + + if (!buttons[i].selector) { + button.enabled = false; + continue; + } + SEL selector = NSSelectorFromString(buttons[i].selector); + if (selector == @selector(reset) && ![GBROMManager sharedManager].currentROM) { + button.enabled = false; + continue; + } + id block = ^(){ + [self.presentingViewController dismissViewControllerAnimated:true completion:^{ +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Warc-performSelector-leaks" + (void)[[UIApplication sharedApplication].delegate performSelector:selector]; +#pragma clang diagnostic pop + }]; + }; + objc_setAssociatedObject(button, "RetainedBlock", block, OBJC_ASSOCIATION_RETAIN); + [button addTarget:block action:@selector(invoke) forControlEvents:UIControlEventTouchUpInside]; + + + } +} + +- (void)viewDidLayoutSubviews +{ + if (self.view.bounds.size.height < 88 * 2) { + [self.view.heightAnchor constraintEqualToConstant:self.view.bounds.size.height + 88 * 2].active = true; + } + [super viewDidLayoutSubviews]; +} + +// This is a hack that forces the iPad controller to display the button separator +- (UIViewController *)contentViewController +{ + return [[UIViewController alloc] init]; +} + +@end diff --git a/iOS/GBViewController.h b/iOS/GBViewController.h @@ -2,4 +2,8 @@ @interface GBViewController : UIViewController <UIApplicationDelegate> @property (nullable, nonatomic, strong) UIWindow *window; +- (void)reset; +- (void)openLibrary; +- (void)start; +- (void)stop; @end diff --git a/iOS/GBViewController.m b/iOS/GBViewController.m @@ -7,6 +7,7 @@ #import "GBLoadROMTableViewController.h" #import "GBBackgroundView.h" #import "GBHapticManager.h" +#import "GBMenuViewController.h" #include <Core/gb.h> @implementation GBViewController @@ -126,11 +127,13 @@ static void rumbleCallback(GB_gameboy_t *gb, double amp) - (void)loadROM { + [self stop]; GBROMManager *romManager = [GBROMManager sharedManager]; if (romManager.romFile) { // Todo: display errors and warnings _romLoaded = GB_load_rom(&_gb, romManager.romFile.fileSystemRepresentation) == 0; if (_romLoaded) { + GB_reset(&_gb); GB_load_battery(&_gb, [GBROMManager sharedManager].batterySaveFile.fileSystemRepresentation); GB_load_state(&_gb, [GBROMManager sharedManager].autosaveStateFile.fileSystemRepresentation); } @@ -140,14 +143,31 @@ static void rumbleCallback(GB_gameboy_t *gb, double amp) - (void)applicationDidBecomeActive:(UIApplication *)application { if (self.presentedViewController) return; - if (!_romLoaded) { - [self presentViewController:[[GBLoadROMTableViewController alloc] init] - animated:true - completion:nil]; - } [self start]; } +-(void)presentViewController:(UIViewController *)viewControllerToPresent animated:(BOOL)flag completion:(void (^)(void))completion +{ + [self stop]; + [super presentViewController:viewControllerToPresent + animated:flag + completion:completion]; +} + +- (void)reset +{ + [self stop]; + GB_reset(&_gb); + [self start]; +} + +- (void)openLibrary +{ + [self presentViewController:[[GBLoadROMTableViewController alloc] init] + animated:true + completion:nil]; +} + - (void)applicationWillResignActive:(UIApplication *)application { [self stop]; diff --git a/iOS/ModelTemplate@2x.png b/iOS/ModelTemplate@2x.png Binary files differ. diff --git a/iOS/ModelTemplate@3x.png b/iOS/ModelTemplate@3x.png Binary files differ.
This webpage is intended to be an accessible preview of this repository. To get a fuller picture, clone it and use the git CLI.