pcsxr/macosx/Source/CheatController.m

325 lines
8.8 KiB
Objective-C

//
// CheatController.m
// Pcsxr
//
#import <Cocoa/Cocoa.h>
#import "CheatController.h"
#import "PcsxrCheatHandler.h"
#import "PcsxrHexadecimalFormatter.h"
#define kTempCheatCodesName @"tempCheatCodes"
#define kCheatsName @"cheats"
@implementation PcsxrCheatTempObject
@synthesize cheatAddress, cheatValue;
- (instancetype)init
{
return [self initWithAddress:0x10000000 value:0];
}
- (instancetype)initWithAddress:(uint32_t)add value:(uint16_t)val
{
if (self = [super init]) {
self.cheatAddress = add;
self.cheatValue = val;
}
return self;
}
- (instancetype)initWithCheatCode:(CheatCode *)theCheat
{
return [self initWithAddress:theCheat->Addr value:theCheat->Val];
}
- (NSString*)description
{
return [NSString stringWithFormat:@"%08x %04x", cheatAddress, cheatValue];
}
- (BOOL)isEqual:(id)object
{
if ([object isKindOfClass:[PcsxrCheatTempObject class]]) {
if (cheatAddress != [object cheatAddress]) {
return NO;
} else if (cheatValue != [object cheatValue]) {
return NO;
} else
return YES;
} else
return NO;
}
- (NSUInteger)hash
{
return cheatAddress ^ cheatValue;
}
- (id)copyWithZone:(NSZone *)zone
{
return [[[self class] allocWithZone:zone] initWithAddress:cheatAddress value:cheatValue];
}
@end
@implementation PcsxrCheatTemp
@synthesize cheatName;
@synthesize cheatValues;
@synthesize enabled;
- (instancetype)initWithCheat:(Cheat *)theCheat
{
if (self = [super init]) {
self.cheatName = @(theCheat->Descr);
self.enabled = theCheat->Enabled ? YES : NO;
self.cheatValues = [NSMutableArray arrayWithCapacity:theCheat->n];
for (int i = 0; i < theCheat->n; i++) {
[cheatValues addObject:[[PcsxrCheatTempObject alloc] initWithCheatCode:&CheatCodes[i+theCheat->First]]];
}
}
return self;
}
- (NSUInteger)hash
{
return [cheatName hash] ^ [cheatValues hash];
}
- (NSString *)description
{
return [NSString stringWithFormat:@"[%@%@]\n%@", enabled ? @"*" : @"", cheatName, [cheatValues componentsJoinedByString:@"\n"]];
}
@end
@implementation CheatController
@synthesize addressFormatter;
@synthesize cheatView;
@synthesize editCheatView;
@synthesize editCheatWindow;
@synthesize valueFormatter;
- (NSString *)windowNibName
{
return @"CheatWindow";
}
- (instancetype)init
{
return self = [self initWithWindowNibName:@"CheatWindow"];
}
- (instancetype)initWithCoder:(NSCoder *)aDecoder
{
if (self = [super initWithCoder:aDecoder]) {
self.tempCheatCodes = [NSMutableArray array];
}
return self;
}
- (instancetype)initWithWindow:(NSWindow *)window
{
if (self = [super initWithWindow:window]) {
self.tempCheatCodes = [NSMutableArray array];
}
return self;
}
- (void)refreshNSCheatArray
{
NSMutableArray *tmpArray = [[NSMutableArray alloc] initWithCapacity:NumCheats];
for (int i = 0; i < NumCheats; i++) {
PcsxrCheatTemp *tmpObj = [[PcsxrCheatTemp alloc] initWithCheat:&Cheats[i]];
[tmpArray addObject:tmpObj];
}
self.cheats = tmpArray;
[self setDocumentEdited:NO];
}
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context
{
if ([keyPath isEqualToString:kCheatsName]) {
[self setDocumentEdited:YES];
}
}
- (void)refresh
{
[cheatView reloadData];
[self refreshNSCheatArray];
}
- (void)awakeFromNib
{
[valueFormatter setHexPadding:4];
[addressFormatter setHexPadding:8];
[self refreshNSCheatArray];
[self addObserver:self forKeyPath:kCheatsName options:NSKeyValueObservingOptionNew | NSKeyValueObservingOptionOld context:NULL];
}
- (IBAction)loadCheats:(id)sender
{
NSOpenPanel *openDlg = [NSOpenPanel openPanel];
[openDlg setAllowsMultipleSelection:NO];
[openDlg setAllowedFileTypes:[PcsxrCheatHandler supportedUTIs]];
if ([openDlg runModal] == NSFileHandlingPanelOKButton) {
NSURL *file = [openDlg URL];
LoadCheats([[file path] fileSystemRepresentation]);
[self refresh];
}
}
- (IBAction)saveCheats:(id)sender
{
NSSavePanel *saveDlg = [NSSavePanel savePanel];
[saveDlg setAllowedFileTypes:[PcsxrCheatHandler supportedUTIs]];
[saveDlg setCanSelectHiddenExtension:YES];
[saveDlg setCanCreateDirectories:YES];
[saveDlg setPrompt:NSLocalizedString(@"Save Cheats", nil)];
if ([saveDlg runModal] == NSFileHandlingPanelOKButton) {
NSURL *url = [saveDlg URL];
NSString *saveString = [self.cheats componentsJoinedByString:@"\n"];
[saveString writeToURL:url atomically:YES encoding:NSUTF8StringEncoding error:NULL];
}
}
- (IBAction)clear:(id)sender
{
self.cheats = [[NSMutableArray alloc] init];
}
- (IBAction)closeCheatEdit:(id)sender
{
[[self window] endSheet:editCheatWindow returnCode:[sender tag] == 1 ? NSCancelButton : NSOKButton];
}
- (IBAction)changeCheat:(id)sender
{
[self setDocumentEdited:YES];
}
- (IBAction)removeCheatValue:(id)sender
{
if ([editCheatView selectedRow] < 0) {
NSBeep();
return;
}
NSIndexSet *toRemoveIndex = [editCheatView selectedRowIndexes];
[self willChange:NSKeyValueChangeRemoval valuesAtIndexes:toRemoveIndex forKey:kTempCheatCodesName];
[self.tempCheatCodes removeObjectsAtIndexes:toRemoveIndex];
[self didChange:NSKeyValueChangeRemoval valuesAtIndexes:toRemoveIndex forKey:kTempCheatCodesName];
}
- (IBAction)addCheatValue:(id)sender
{
NSIndexSet *newSet = [NSIndexSet indexSetWithIndex:[self.tempCheatCodes count]];
[self willChange:NSKeyValueChangeInsertion valuesAtIndexes:newSet forKey:kTempCheatCodesName];
[self.tempCheatCodes addObject:[[PcsxrCheatTempObject alloc] init]];
[self didChange:NSKeyValueChangeInsertion valuesAtIndexes:newSet forKey:kTempCheatCodesName];
}
- (void)reloadCheats
{
NSFileManager *manager = [NSFileManager defaultManager];
NSURL *tmpURL = [[manager URLForDirectory:NSItemReplacementDirectory inDomain:NSUserDomainMask appropriateForURL:[[NSBundle mainBundle] bundleURL] create:YES error:nil] URLByAppendingPathComponent:@"temp.cht" isDirectory:NO];
NSString *tmpStr = [self.cheats componentsJoinedByString:@"\n"];
[tmpStr writeToURL:tmpURL atomically:NO encoding:NSUTF8StringEncoding error:NULL];
LoadCheats([[tmpURL path] fileSystemRepresentation]);
[manager removeItemAtURL:tmpURL error:NULL];
}
- (IBAction)editCheat:(id)sender
{
if ([cheatView selectedRow] < 0) {
NSBeep();
return;
}
NSMutableArray *tmpArray = [(self.cheats)[[cheatView selectedRow]] cheatValues];
NSMutableArray *newCheats = [[NSMutableArray alloc] initWithArray:tmpArray copyItems:YES];
self.tempCheatCodes = newCheats;
[[self window] beginSheet:editCheatWindow completionHandler:^(NSModalResponse returnCode) {
if (returnCode == NSOKButton) {
PcsxrCheatTemp *tmpCheat = (self.cheats)[[cheatView selectedRow]];
if (![tmpCheat.cheatValues isEqualToArray:self.tempCheatCodes]) {
tmpCheat.cheatValues = self.tempCheatCodes;
[self setDocumentEdited:YES];
}
}
[editCheatWindow orderOut:nil];
}];
}
- (IBAction)addCheat:(id)sender
{
NSIndexSet *newSet = [NSIndexSet indexSetWithIndex:[self.cheats count]];
[self willChange:NSKeyValueChangeInsertion valuesAtIndexes:newSet forKey:kCheatsName];
PcsxrCheatTemp *tmpCheat = [[PcsxrCheatTemp alloc] init];
tmpCheat.cheatName = NSLocalizedString(@"New Cheat", @"New Cheat Name" );
PcsxrCheatTempObject *tmpObj = [[PcsxrCheatTempObject alloc] initWithAddress:0x10000000 value:0];
NSMutableArray *tmpArray = [NSMutableArray arrayWithObject:tmpObj];
tmpCheat.cheatValues = tmpArray;
[self.cheats addObject:tmpCheat];
[self didChange:NSKeyValueChangeInsertion valuesAtIndexes:newSet forKey:kCheatsName];
[self setDocumentEdited:YES];
}
- (IBAction)applyCheats:(id)sender
{
[self reloadCheats];
[self setDocumentEdited:NO];
}
- (void)sheetDidDismiss:(NSWindow *)sheet returnCode:(int)returnCode contextInfo:(void *)contextInfo
{
switch (returnCode) {
case NSAlertDefaultReturn:
[self reloadCheats];
[self close];
break;
default:
[self refreshNSCheatArray];
[self close];
break;
case NSAlertOtherReturn:
break;
}
}
- (BOOL)windowShouldClose:(id)sender
{
if (![sender isDocumentEdited] || ![[self window] isEqual:sender]) {
return YES;
} else {
NSBeginAlertSheet(NSLocalizedString(@"Unsaved Changes", @"Unsaved changes"),
NSLocalizedString(@"Save", @"Save"),
NSLocalizedString(@"Don't Save",@"Don't Save"),
NSLocalizedString(@"Cancel", @"Cancel"), [self window], self,
NULL, @selector(sheetDidDismiss:returnCode:contextInfo:), NULL,
NSLocalizedString(@"The cheat codes have not been applied. Unapplied cheats will not run nor be saved. Do you wish to save?", nil));
return NO;
}
}
- (IBAction)removeCheats:(id)sender
{
if ([cheatView selectedRow] < 0) {
NSBeep();
return;
}
NSIndexSet *toRemoveIndex = [cheatView selectedRowIndexes];
[self willChange:NSKeyValueChangeRemoval valuesAtIndexes:toRemoveIndex forKey:kCheatsName];
[self.cheats removeObjectsAtIndexes:toRemoveIndex];
[self didChange:NSKeyValueChangeRemoval valuesAtIndexes:toRemoveIndex forKey:kCheatsName];
[self setDocumentEdited:YES];
}
@end