mirror of https://github.com/LIJI32/SameBoy.git
636 lines
22 KiB
Objective-C
636 lines
22 KiB
Objective-C
#import "GBBackgroundView.h"
|
|
#import "GBViewMetal.h"
|
|
#import "GBHapticManager.h"
|
|
#import "GBMenuViewController.h"
|
|
#import "GBViewController.h"
|
|
#import "GBROMManager.h"
|
|
|
|
static double CGPointSquaredDistance(CGPoint a, CGPoint b)
|
|
{
|
|
double deltaX = a.x - b.x;
|
|
double deltaY = a.y - b.y;
|
|
return deltaX * deltaX + deltaY * deltaY;
|
|
}
|
|
|
|
static double CGPointAngle(CGPoint a, CGPoint b)
|
|
{
|
|
double deltaX = a.x - b.x;
|
|
double deltaY = a.y - b.y;
|
|
return atan2(deltaY, deltaX);
|
|
}
|
|
|
|
static void positionView(UIImageView *view, CGPoint position)
|
|
{
|
|
double center = view.image.size.width / 2 * [UIScreen mainScreen].scale;
|
|
view.frame = (CGRect){
|
|
{
|
|
round(position.x - center) / [UIScreen mainScreen].scale,
|
|
round(position.y - center) / [UIScreen mainScreen].scale
|
|
},
|
|
view.image.size
|
|
};
|
|
}
|
|
|
|
static GB_key_mask_t angleToKeyMask(double angle)
|
|
{
|
|
signed quantizedAngle = round(angle / M_PI * 16);
|
|
if (quantizedAngle < 0) {
|
|
quantizedAngle += 32;
|
|
}
|
|
switch (quantizedAngle) {
|
|
case 32:
|
|
case 0: return GB_KEY_RIGHT_MASK;
|
|
case 1: return GB_KEY_RIGHT_MASK;
|
|
case 2: return GB_KEY_RIGHT_MASK;
|
|
case 3: return GB_KEY_RIGHT_MASK | GB_KEY_DOWN_MASK;
|
|
case 4: return GB_KEY_RIGHT_MASK | GB_KEY_DOWN_MASK;
|
|
case 5: return GB_KEY_DOWN_MASK;
|
|
case 6: return GB_KEY_DOWN_MASK;
|
|
case 7: return GB_KEY_DOWN_MASK;
|
|
|
|
case 8: return GB_KEY_DOWN_MASK;
|
|
case 9: return GB_KEY_DOWN_MASK;
|
|
case 10: return GB_KEY_DOWN_MASK;
|
|
case 11: return GB_KEY_LEFT_MASK | GB_KEY_DOWN_MASK;
|
|
case 12: return GB_KEY_LEFT_MASK | GB_KEY_DOWN_MASK;
|
|
case 13: return GB_KEY_LEFT_MASK;
|
|
case 14: return GB_KEY_LEFT_MASK;
|
|
case 15: return GB_KEY_LEFT_MASK;
|
|
|
|
case 16: return GB_KEY_LEFT_MASK;
|
|
case 17: return GB_KEY_LEFT_MASK;
|
|
case 18: return GB_KEY_LEFT_MASK;
|
|
case 19: return GB_KEY_LEFT_MASK | GB_KEY_UP_MASK;
|
|
case 20: return GB_KEY_LEFT_MASK | GB_KEY_UP_MASK;
|
|
case 21: return GB_KEY_UP_MASK;
|
|
case 22: return GB_KEY_UP_MASK;
|
|
case 23: return GB_KEY_UP_MASK;
|
|
|
|
case 24: return GB_KEY_UP_MASK;
|
|
case 25: return GB_KEY_UP_MASK;
|
|
case 26: return GB_KEY_UP_MASK;
|
|
case 27: return GB_KEY_RIGHT_MASK | GB_KEY_UP_MASK;
|
|
case 28: return GB_KEY_RIGHT_MASK | GB_KEY_UP_MASK;
|
|
case 29: return GB_KEY_RIGHT_MASK;
|
|
case 30: return GB_KEY_RIGHT_MASK;
|
|
case 31: return GB_KEY_RIGHT_MASK;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
@implementation GBBackgroundView
|
|
{
|
|
NSMutableSet<UITouch *> *_touches;
|
|
UITouch *_padTouch;
|
|
CGPoint _padSwipeOrigin;
|
|
UITouch *_screenTouch;
|
|
UITouch *_logoTouch;
|
|
CGPoint _screenSwipeOrigin;
|
|
bool _screenSwiped;
|
|
bool _inDynamicSpeedMode;
|
|
bool _previewMode;
|
|
|
|
UIView *_fadeView;
|
|
UIImageView *_dpadView;
|
|
UIImageView *_dpadShadowView;
|
|
UIImageView *_aButtonView;
|
|
UIImageView *_bButtonView;
|
|
UIImageView *_startButtonView;
|
|
UIImageView *_selectButtonView;
|
|
UILabel *_screenLabel;
|
|
|
|
UIVisualEffectView *_overlayView;
|
|
UIView *_overlayViewContents;
|
|
NSTimer *_fadeTimer;
|
|
|
|
GB_key_mask_t _lastMask;
|
|
bool _fullScreenMode;
|
|
}
|
|
|
|
- (void)reloadThemeImages
|
|
{
|
|
_aButtonView.image = [_layout.theme imageNamed:@"buttonA"];
|
|
_bButtonView.image = [_layout.theme imageNamed:@"buttonB"];
|
|
_startButtonView.image = [_layout.theme imageNamed:@"button2"];
|
|
_selectButtonView.image = [_layout.theme imageNamed:@"button2"];
|
|
self.usesSwipePad = self.usesSwipePad;
|
|
}
|
|
|
|
- (void)setDefaultScreenLabel
|
|
{
|
|
_screenLabel.text = @"Tap the Game Boy screen to open the menu and load a ROM from the library.";
|
|
}
|
|
|
|
|
|
- (instancetype)initWithLayout:(GBLayout *)layout;
|
|
{
|
|
self = [super initWithImage:nil];
|
|
if (!self) return nil;
|
|
|
|
_layout = layout;
|
|
_touches = [NSMutableSet set];
|
|
|
|
_screenLabel = [[UILabel alloc] initWithFrame:CGRectZero];
|
|
_screenLabel.font = [UIFont systemFontOfSize:20 weight:UIFontWeightMedium];
|
|
_screenLabel.textAlignment = NSTextAlignmentCenter;
|
|
_screenLabel.textColor = [UIColor whiteColor];
|
|
_screenLabel.lineBreakMode = NSLineBreakByWordWrapping;
|
|
_screenLabel.numberOfLines = 0;
|
|
[self setDefaultScreenLabel];
|
|
[self addSubview:_screenLabel];
|
|
|
|
_dpadView = [[UIImageView alloc] initWithImage:[_layout.theme imageNamed:@"dpad"]];
|
|
_aButtonView = [[UIImageView alloc] initWithImage:[_layout.theme imageNamed:@"buttonA"]];
|
|
_bButtonView = [[UIImageView alloc] initWithImage:[_layout.theme imageNamed:@"buttonB"]];
|
|
_startButtonView = [[UIImageView alloc] initWithImage:[_layout.theme imageNamed:@"button2"]];
|
|
_selectButtonView = [[UIImageView alloc] initWithImage:[_layout.theme imageNamed:@"button2"]];
|
|
|
|
_dpadShadowView = [[UIImageView alloc] initWithImage:[UIImage imageNamed:@"dpadShadow"]];
|
|
_dpadShadowView.hidden = true;
|
|
_gbView = [[GBViewMetal alloc] initWithFrame:CGRectZero];
|
|
|
|
_fadeView = [[UIView alloc] initWithFrame:self.frame];
|
|
_fadeView.backgroundColor = [UIColor colorWithWhite:0 alpha:0];
|
|
_fadeView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
|
|
_fadeView.multipleTouchEnabled = true;
|
|
|
|
[self addSubview:_dpadView];
|
|
[self addSubview:_aButtonView];
|
|
[self addSubview:_bButtonView];
|
|
[self addSubview:_startButtonView];
|
|
[self addSubview:_selectButtonView];
|
|
[self addSubview:_fadeView];
|
|
[self addSubview:_gbView];
|
|
|
|
[_dpadView addSubview:_dpadShadowView];
|
|
|
|
UIVisualEffect *effect = [UIBlurEffect effectWithStyle:(UIBlurEffectStyle)UIBlurEffectStyleDark];
|
|
_overlayView = [[UIVisualEffectView alloc] initWithEffect:effect];
|
|
_overlayView.frame = CGRectMake(8, 8, 32, 32);
|
|
_overlayView.layer.cornerRadius = 12;
|
|
_overlayView.layer.masksToBounds = true;
|
|
_overlayView.alpha = 0;
|
|
|
|
if (@available(iOS 13.0, *)) {
|
|
_overlayViewContents = [[UIImageView alloc] init];
|
|
_overlayViewContents.tintColor = [UIColor whiteColor];
|
|
_overlayViewContents.contentMode = UIViewContentModeCenter;
|
|
}
|
|
else {
|
|
_overlayViewContents = [[UILabel alloc] init];
|
|
((UILabel *)_overlayViewContents).font = [UIFont systemFontOfSize:UIFont.systemFontSize weight:UIFontWeightMedium];
|
|
((UILabel *)_overlayViewContents).textColor = [UIColor whiteColor];
|
|
}
|
|
_overlayViewContents.frame = CGRectMake(8, 8, 160, 20.5);
|
|
[_overlayView.contentView addSubview:_overlayViewContents];
|
|
[_gbView addSubview:_overlayView];
|
|
|
|
return self;
|
|
}
|
|
|
|
- (GBViewController *)viewController
|
|
{
|
|
return (GBViewController *)[UIApplication sharedApplication].delegate;
|
|
}
|
|
|
|
- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event
|
|
{
|
|
if (_previewMode) return;
|
|
if (_fullScreenMode) {
|
|
self.fullScreenMode = false;
|
|
return;
|
|
}
|
|
static const double dpadRadius = 75;
|
|
CGPoint dpadLocation = _layout.dpadLocation;
|
|
double factor = [UIScreen mainScreen].scale;
|
|
dpadLocation.x /= factor;
|
|
dpadLocation.y /= factor;
|
|
CGRect logoRect = _layout.logoRect;
|
|
|
|
logoRect.origin.x /= factor;
|
|
logoRect.origin.y /= factor;
|
|
logoRect.size.width /= factor;
|
|
logoRect.size.height /= factor;
|
|
|
|
for (UITouch *touch in touches) {
|
|
CGPoint point = [touch locationInView:self];
|
|
if (CGRectContainsPoint(self.gbView.frame, point) && !_screenTouch) {
|
|
if (self.viewController.runMode != GBRunModeNormal) {
|
|
self.viewController.runMode = GBRunModeNormal;
|
|
[self fadeOverlayOut];
|
|
}
|
|
else {
|
|
_screenTouch = touch;
|
|
_screenSwipeOrigin = point;
|
|
_screenSwiped = false;
|
|
_inDynamicSpeedMode = false;
|
|
_overlayView.alpha = 0;
|
|
[_fadeTimer invalidate];
|
|
_fadeTimer = nil;
|
|
if ([[NSUserDefaults standardUserDefaults] boolForKey:@"GBDynamicSpeed"]) {
|
|
self.viewController.runMode = GBRunModePaused;
|
|
[self displayOverlayWithImage:@"pause" orTitle:@"Paused"];
|
|
}
|
|
}
|
|
}
|
|
else if (CGRectContainsPoint(logoRect, point) && !_logoTouch) {
|
|
_logoTouch = touch;
|
|
}
|
|
else if (!_padTouch) {
|
|
if (fabs(point.x - dpadLocation.x) <= dpadRadius &&
|
|
fabs(point.y - dpadLocation.y) <= dpadRadius) {
|
|
_padTouch = touch;
|
|
_padSwipeOrigin = point;
|
|
}
|
|
}
|
|
}
|
|
[_touches unionSet:touches];
|
|
[self touchesChanged];
|
|
}
|
|
|
|
- (void)touchesEnded:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event
|
|
{
|
|
if (_padTouch && [touches containsObject:_padTouch]) {
|
|
_padTouch = nil;
|
|
}
|
|
|
|
if (_screenTouch && [touches containsObject:_screenTouch]) {
|
|
_screenTouch = nil;
|
|
if (self.viewController.runMode == GBRunModePaused) {
|
|
self.viewController.runMode = GBRunModeNormal;
|
|
[self fadeOverlayOut];
|
|
}
|
|
if (!_screenSwiped) {
|
|
self.window.backgroundColor = nil;
|
|
[self.window.rootViewController presentViewController:[GBMenuViewController menu] animated:true completion:nil];
|
|
}
|
|
if (![[NSUserDefaults standardUserDefaults] boolForKey:@"GBSwipeLock"]) {
|
|
if (self.viewController.runMode != GBRunModeNormal) {
|
|
self.viewController.runMode = GBRunModeNormal;
|
|
[self fadeOverlayOut];
|
|
}
|
|
}
|
|
}
|
|
|
|
if (_logoTouch && [touches containsObject:_logoTouch]) {
|
|
|
|
double factor = [UIScreen mainScreen].scale;
|
|
CGRect logoRect = _layout.logoRect;
|
|
|
|
logoRect.origin.x /= factor;
|
|
logoRect.origin.y /= factor;
|
|
logoRect.size.width /= factor;
|
|
logoRect.size.height /= factor;
|
|
|
|
CGPoint point = [_logoTouch locationInView:self];
|
|
if (CGRectContainsPoint(logoRect, point)) {
|
|
self.window.backgroundColor = nil;
|
|
[self.window.rootViewController presentViewController:[GBMenuViewController menu] animated:true completion:nil];
|
|
}
|
|
_logoTouch = nil;
|
|
}
|
|
|
|
[_touches minusSet:touches];
|
|
[self touchesChanged];
|
|
}
|
|
|
|
- (void)touchesCancelled:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event
|
|
{
|
|
[self touchesEnded:touches withEvent:event];
|
|
}
|
|
|
|
- (void)touchesMoved:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event
|
|
{
|
|
[self touchesChanged];
|
|
}
|
|
|
|
- (void)touchesChanged
|
|
{
|
|
if (_previewMode) return;
|
|
if (!GB_is_inited(_gbView.gb)) return;
|
|
GB_key_mask_t mask = 0;
|
|
double factor = [UIScreen mainScreen].scale;
|
|
double buttonRadiusSquared = 36 * 36 * factor * factor;
|
|
double dpadRadius = 75 * factor;
|
|
bool dpadHandled = false;
|
|
if (_usesSwipePad) {
|
|
dpadHandled = true;
|
|
if (_padTouch) {
|
|
CGPoint point = [_padTouch locationInView:self];
|
|
double squaredDistance = CGPointSquaredDistance(point, _padSwipeOrigin);
|
|
if (squaredDistance > 16 * 16) {
|
|
GB_set_use_faux_analog_inputs(_gbView.gb, 0, false);
|
|
double angle = CGPointAngle(point, _padSwipeOrigin);
|
|
mask |= angleToKeyMask(angle);
|
|
if (squaredDistance > 24 * 24) {
|
|
double deltaX = point.x - _padSwipeOrigin.x;
|
|
double deltaY = point.y - _padSwipeOrigin.y;
|
|
double distance = sqrt(squaredDistance);
|
|
_padSwipeOrigin.x = point.x - deltaX / distance * 24;
|
|
_padSwipeOrigin.y = point.y - deltaY / distance * 24;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
for (UITouch *touch in _touches) {
|
|
if (_usesSwipePad && touch == _padTouch) continue;
|
|
CGPoint point = [touch locationInView:self];
|
|
|
|
if (touch == _screenTouch) {
|
|
if (_inDynamicSpeedMode) {
|
|
double delta = point.x - _screenSwipeOrigin.x;
|
|
if (fabs(delta) < 32) {
|
|
self.viewController.runMode = GBRunModePaused;
|
|
[self displayOverlayWithImage:@"pause" orTitle:@"Paused"];
|
|
continue;
|
|
}
|
|
|
|
double speed = fabs(delta / _gbView.frame.size.width * 3);
|
|
if (delta > 0) {
|
|
if (speed > 1) {
|
|
[self displayOverlayWithImage:@"forward" orTitle:@"Fast-forwarding…"];
|
|
}
|
|
else {
|
|
[self displayOverlayWithImage:@"play" orTitle:@"Forward…"];
|
|
}
|
|
GB_set_clock_multiplier(_gbView.gb, speed);
|
|
self.viewController.runMode = GBRunModeTurbo;
|
|
}
|
|
else {
|
|
[self displayOverlayWithImage:@"backward" orTitle:@"Rewinding…"];
|
|
GB_set_clock_multiplier(_gbView.gb, speed);
|
|
self.viewController.runMode = GBRunModeRewind;
|
|
|
|
}
|
|
continue;
|
|
}
|
|
if (_screenSwiped) continue;
|
|
if (point.x - _screenSwipeOrigin.x > 32) {
|
|
[self turboSwipe];
|
|
}
|
|
else if (point.x - _screenSwipeOrigin.x < -32) {
|
|
[self rewindSwipe];
|
|
}
|
|
else if (point.y - _screenSwipeOrigin.y > 32) {
|
|
[self saveSwipe];
|
|
}
|
|
else if (point.y - _screenSwipeOrigin.y < -32) {
|
|
[self loadSwipe];
|
|
}
|
|
continue;
|
|
}
|
|
|
|
point.x *= factor;
|
|
point.y *= factor;
|
|
if (!dpadHandled &&
|
|
(touch == _padTouch ||
|
|
(fabs(point.x - _layout.dpadLocation.x) <= dpadRadius &&
|
|
fabs(point.y - _layout.dpadLocation.y) <= dpadRadius)
|
|
) && (fabs(point.x - _layout.dpadLocation.x) >= dpadRadius / 5 ||
|
|
fabs(point.y - _layout.dpadLocation.y) >= dpadRadius / 5)) {
|
|
GB_set_use_faux_analog_inputs(_gbView.gb, 0, false);
|
|
dpadHandled = true; // Don't handle the dpad twice
|
|
double angle = CGPointAngle(point, _layout.dpadLocation);
|
|
mask |= angleToKeyMask(angle);
|
|
}
|
|
else if (CGPointSquaredDistance(point, _layout.aLocation) <= buttonRadiusSquared) {
|
|
mask |= GB_KEY_A_MASK;
|
|
}
|
|
else if (CGPointSquaredDistance(point, _layout.bLocation) <= buttonRadiusSquared) {
|
|
mask |= GB_KEY_B_MASK;
|
|
}
|
|
else if (CGPointSquaredDistance(point, _layout.startLocation) <= buttonRadiusSquared) {
|
|
mask |= GB_KEY_START_MASK;
|
|
}
|
|
else if (CGPointSquaredDistance(point, _layout.selectLocation) <= buttonRadiusSquared) {
|
|
mask |= GB_KEY_SELECT_MASK;
|
|
}
|
|
else if ([[NSUserDefaults standardUserDefaults] boolForKey:@"GBEnableABCombo"] &&
|
|
CGPointSquaredDistance(point, _layout.abComboLocation) <= buttonRadiusSquared) {
|
|
mask |= GB_KEY_A_MASK | GB_KEY_B_MASK;
|
|
}
|
|
}
|
|
if (mask != _lastMask) {
|
|
_aButtonView.image = [_layout.theme imageNamed:(mask & GB_KEY_A_MASK)? @"buttonAPressed" : @"buttonA"];
|
|
_bButtonView.image = [_layout.theme imageNamed:(mask & GB_KEY_B_MASK)? @"buttonBPressed" : @"buttonB"];
|
|
_startButtonView.image = [_layout.theme imageNamed:(mask & GB_KEY_START_MASK) ? @"button2Pressed" : @"button2"];
|
|
_selectButtonView.image = [_layout.theme imageNamed:(mask & GB_KEY_SELECT_MASK)? @"button2Pressed" : @"button2"];
|
|
|
|
bool hidden = false;
|
|
bool diagonal = false;
|
|
double rotation = 0;
|
|
switch (mask & (GB_KEY_RIGHT_MASK | GB_KEY_DOWN_MASK | GB_KEY_LEFT_MASK | GB_KEY_UP_MASK)) {
|
|
case GB_KEY_RIGHT_MASK: break;
|
|
case GB_KEY_RIGHT_MASK | GB_KEY_DOWN_MASK: diagonal = true; break;
|
|
case GB_KEY_DOWN_MASK: rotation = M_PI_2; break;
|
|
case GB_KEY_LEFT_MASK | GB_KEY_DOWN_MASK: diagonal = true; rotation = M_PI_2; break;
|
|
case GB_KEY_LEFT_MASK: rotation = M_PI; break;
|
|
case GB_KEY_LEFT_MASK | GB_KEY_UP_MASK: diagonal = true; rotation = M_PI; break;
|
|
case GB_KEY_UP_MASK: rotation = -M_PI_2; break;
|
|
case GB_KEY_RIGHT_MASK | GB_KEY_UP_MASK: diagonal = true; rotation = -M_PI_2; break;
|
|
default:
|
|
hidden = true;
|
|
}
|
|
|
|
_dpadShadowView.hidden = hidden;
|
|
if (!hidden) {
|
|
if (_usesSwipePad) {
|
|
_dpadShadowView.image = [UIImage imageNamed:diagonal? @"swipepadShadowDiagonal" : @"swipepadShadow"];
|
|
|
|
}
|
|
else {
|
|
_dpadShadowView.image = [UIImage imageNamed:diagonal? @"dpadShadowDiagonal" : @"dpadShadow"];
|
|
}
|
|
_dpadShadowView.transform = CGAffineTransformMakeRotation(rotation);
|
|
}
|
|
|
|
GB_set_key_mask(_gbView.gb, mask);
|
|
if ((mask & ~_lastMask) && ([[NSUserDefaults standardUserDefaults] boolForKey:@"GBButtonHaptics"])) {
|
|
[[GBHapticManager sharedManager] doTapHaptic];
|
|
}
|
|
_lastMask = mask;
|
|
}
|
|
}
|
|
|
|
- (BOOL)isMultipleTouchEnabled
|
|
{
|
|
return true;
|
|
}
|
|
|
|
- (BOOL)isUserInteractionEnabled
|
|
{
|
|
return true;
|
|
}
|
|
|
|
- (void)setLayout:(GBLayout *)layout
|
|
{
|
|
_layout = layout;
|
|
self.image = layout.background;
|
|
|
|
positionView(_dpadView, layout.dpadLocation);
|
|
positionView(_aButtonView, layout.aLocation);
|
|
positionView(_bButtonView, layout.bLocation);
|
|
positionView(_startButtonView, layout.startLocation);
|
|
positionView(_selectButtonView, layout.selectLocation);
|
|
|
|
CGRect screenFrame = layout.screenRect;
|
|
screenFrame.origin.x /= [UIScreen mainScreen].scale;
|
|
screenFrame.origin.y /= [UIScreen mainScreen].scale;
|
|
screenFrame.size.width /= [UIScreen mainScreen].scale;
|
|
screenFrame.size.height /= [UIScreen mainScreen].scale;
|
|
|
|
if (_fullScreenMode) {
|
|
CGRect fullScreenFrame = layout.fullScreenRect;
|
|
fullScreenFrame.origin.x /= [UIScreen mainScreen].scale;
|
|
fullScreenFrame.origin.y /= [UIScreen mainScreen].scale;
|
|
fullScreenFrame.size.width /= [UIScreen mainScreen].scale;
|
|
fullScreenFrame.size.height /= [UIScreen mainScreen].scale;
|
|
_gbView.frame = fullScreenFrame;
|
|
}
|
|
else {
|
|
_gbView.frame = screenFrame;
|
|
}
|
|
|
|
screenFrame.origin.x += 8;
|
|
screenFrame.origin.y += 8;
|
|
screenFrame.size.width -= 16;
|
|
screenFrame.size.height -= 16;
|
|
|
|
if (@available(iOS 13.0, *)) {
|
|
self.overrideUserInterfaceStyle = layout.theme.isDark? UIUserInterfaceStyleDark : UIUserInterfaceStyleLight;
|
|
self.tintColor = layout.theme.buttonColor;
|
|
}
|
|
|
|
_screenLabel.frame = screenFrame;
|
|
}
|
|
|
|
- (void)setUsesSwipePad:(bool)usesSwipePad
|
|
{
|
|
_usesSwipePad = usesSwipePad;
|
|
_dpadView.image = nil; // Some bug in UIImage seems to trigger without this?
|
|
_dpadView.image = [_layout.theme imageNamed:usesSwipePad? @"swipepad" : @"dpad"];
|
|
}
|
|
|
|
- (void)displayOverlayWithImage:(NSString *)imageName orTitle:(NSString *)title
|
|
{
|
|
if (@available(iOS 13.0, *)) {
|
|
((UIImageView *)_overlayViewContents).image = [UIImage systemImageNamed:imageName
|
|
withConfiguration:[UIImageSymbolConfiguration configurationWithWeight:UIImageSymbolWeightMedium]];
|
|
}
|
|
else {
|
|
((UILabel *)_overlayViewContents).text = title;
|
|
}
|
|
[_overlayViewContents sizeToFit];
|
|
|
|
CGRect frame = _overlayViewContents.frame;
|
|
frame.size.width = MAX(frame.size.width, 25);
|
|
frame.size.height = MAX(frame.size.height, 22);
|
|
_overlayViewContents.frame = frame;
|
|
frame.origin = (CGPoint){8, 8};
|
|
frame.size.width += 16;
|
|
frame.size.height += 16;
|
|
_overlayView.frame = frame;
|
|
|
|
_overlayView.alpha = 1.0;
|
|
}
|
|
|
|
- (void)fadeOverlayOut
|
|
{
|
|
[UIView animateWithDuration:1 animations:^{
|
|
_overlayView.alpha = 0;
|
|
}];
|
|
[_fadeTimer invalidate];
|
|
_fadeTimer = nil;
|
|
}
|
|
|
|
- (void)turboSwipe
|
|
{
|
|
_screenSwiped = true;
|
|
if ([[NSUserDefaults standardUserDefaults] boolForKey:@"GBDynamicSpeed"]) {
|
|
_inDynamicSpeedMode = true;
|
|
}
|
|
[self displayOverlayWithImage:@"forward" orTitle:@"Fast-forwarding…"];
|
|
self.viewController.runMode = GBRunModeTurbo;
|
|
}
|
|
|
|
- (void)rewindSwipe
|
|
{
|
|
_screenSwiped = true;
|
|
if ([[NSUserDefaults standardUserDefaults] boolForKey:@"GBDynamicSpeed"]) {
|
|
_inDynamicSpeedMode = true;
|
|
}
|
|
[self displayOverlayWithImage:@"backward" orTitle:@"Rewinding…"];
|
|
self.viewController.runMode = GBRunModeRewind;
|
|
}
|
|
|
|
- (NSString *)swipeStateFile
|
|
{
|
|
return [[GBROMManager sharedManager] stateFile:1];
|
|
}
|
|
|
|
- (void)saveSwipe
|
|
{
|
|
_screenSwiped = true;
|
|
self.viewController.runMode = GBRunModeNormal;
|
|
if (![[NSUserDefaults standardUserDefaults] boolForKey:@"GBSwipeState"]) {
|
|
[self fadeOverlayOut];
|
|
return;
|
|
}
|
|
[self displayOverlayWithImage:@"square.and.arrow.down" orTitle:@"Saved state to Slot 1"];
|
|
_fadeTimer = [NSTimer scheduledTimerWithTimeInterval:1 repeats:false block:^(NSTimer *timer) {
|
|
[self fadeOverlayOut];
|
|
}];
|
|
[self.viewController stop];
|
|
[self.viewController saveStateToFile:self.swipeStateFile];
|
|
[self.viewController start];
|
|
}
|
|
|
|
- (void)loadSwipe
|
|
{
|
|
_screenSwiped = true;
|
|
self.viewController.runMode = GBRunModeNormal;
|
|
if (![[NSUserDefaults standardUserDefaults] boolForKey:@"GBSwipeState"]) {
|
|
[self fadeOverlayOut];
|
|
return;
|
|
}
|
|
[self displayOverlayWithImage:@"square.and.arrow.up" orTitle:@"Loaded state from Slot 1"];
|
|
_fadeTimer = [NSTimer scheduledTimerWithTimeInterval:1 repeats:false block:^(NSTimer *timer) {
|
|
[self fadeOverlayOut];
|
|
}];
|
|
[self.viewController stop];
|
|
[self.viewController loadStateFromFile:self.swipeStateFile];
|
|
[self.viewController start];
|
|
}
|
|
|
|
- (void)enterPreviewMode:(bool)showLabel
|
|
{
|
|
if (showLabel) {
|
|
_screenLabel.text = [NSString stringWithFormat:@"Previewing Theme “%@”", _layout.theme.name];
|
|
}
|
|
else {
|
|
[_screenLabel removeFromSuperview];
|
|
_screenLabel = nil;
|
|
}
|
|
_previewMode = true;
|
|
}
|
|
|
|
- (bool)fullScreenMode
|
|
{
|
|
return _fullScreenMode;
|
|
}
|
|
|
|
- (void)setFullScreenMode:(bool)fullScreenMode
|
|
{
|
|
if (fullScreenMode == _fullScreenMode) return;
|
|
_fullScreenMode = fullScreenMode;
|
|
[UIView animateWithDuration:1.0/3 animations:^{
|
|
// Animating alpha has some weird quirks for some reason
|
|
_fadeView.backgroundColor = [UIColor colorWithWhite:0 alpha:fullScreenMode];
|
|
[self setLayout:_layout];
|
|
}];
|
|
[self.window.rootViewController setNeedsStatusBarAppearanceUpdate];
|
|
}
|
|
|
|
@end
|