SameBoy/Cocoa/GBCheatWindowController.m

241 lines
7.6 KiB
Objective-C

#import "GBCheatWindowController.h"
#import "GBWarningPopover.h"
#import "GBCheatTextFieldCell.h"
@implementation GBCheatWindowController
+ (NSString *)addressStringFromCheat:(const GB_cheat_t *)cheat
{
if (cheat->bank != GB_CHEAT_ANY_BANK) {
return [NSString stringWithFormat:@"$%x:$%04x", cheat->bank, cheat->address];
}
return [NSString stringWithFormat:@"$%04x", cheat->address];
}
+ (NSString *)actionDescriptionForCheat:(const GB_cheat_t *)cheat
{
if (cheat->use_old_value) {
return [NSString stringWithFormat:@"[%@]($%02x) = $%02x", [self addressStringFromCheat:cheat], cheat->old_value, cheat->value];
}
return [NSString stringWithFormat:@"[%@] = $%02x", [self addressStringFromCheat:cheat], cheat->value];
}
- (NSInteger)numberOfRowsInTableView:(NSTableView *)tableView
{
GB_gameboy_t *gb = self.document.gameboy;
if (!gb) return 0;
size_t cheatCount;
GB_get_cheats(gb, &cheatCount);
return cheatCount + 1;
}
- (NSCell *)tableView:(NSTableView *)tableView dataCellForTableColumn:(NSTableColumn *)tableColumn row:(NSInteger)row
{
GB_gameboy_t *gb = self.document.gameboy;
if (!gb) return nil;
size_t cheatCount;
GB_get_cheats(gb, &cheatCount);
NSUInteger columnIndex = [[tableView tableColumns] indexOfObject:tableColumn];
if (row >= cheatCount && columnIndex == 0) {
return [[NSCell alloc] init];
}
return nil;
}
- (nullable id)tableView:(NSTableView *)tableView objectValueForTableColumn:(nullable NSTableColumn *)tableColumn row:(NSInteger)row
{
size_t cheatCount;
GB_gameboy_t *gb = self.document.gameboy;
if (!gb) return nil;
const GB_cheat_t *const *cheats = GB_get_cheats(gb, &cheatCount);
NSUInteger columnIndex = [[tableView tableColumns] indexOfObject:tableColumn];
if (row >= cheatCount) {
switch (columnIndex) {
case 0:
return @YES;
case 1:
return @NO;
case 2:
return @"Add Cheat...";
case 3:
return @"";
}
}
switch (columnIndex) {
case 0:
return @NO;
case 1:
return @(cheats[row]->enabled);
case 2:
return @(cheats[row]->description);
case 3:
return [GBCheatWindowController actionDescriptionForCheat:cheats[row]];
}
return nil;
}
- (IBAction)importCheat:(id)sender
{
GB_gameboy_t *gb = self.document.gameboy;
if (!gb) return;
[self.document performAtomicBlock:^{
if (GB_import_cheat(gb,
self.importCodeField.stringValue.UTF8String,
self.importDescriptionField.stringValue.UTF8String,
true)) {
self.importCodeField.stringValue = @"";
self.importDescriptionField.stringValue = @"";
[self.cheatsTable reloadData];
[self tableViewSelectionDidChange:nil];
}
else {
NSBeep();
[GBWarningPopover popoverWithContents:@"This code is not a valid GameShark or GameGenie code" onView:self.importCodeField];
}
}];
}
- (void)tableView:(NSTableView *)tableView setObjectValue:(id)object forTableColumn:(NSTableColumn *)tableColumn row:(NSInteger)row
{
GB_gameboy_t *gb = self.document.gameboy;
if (!gb) return;
size_t cheatCount;
const GB_cheat_t *const *cheats = GB_get_cheats(gb, &cheatCount);
NSUInteger columnIndex = [[tableView tableColumns] indexOfObject:tableColumn];
[self.document performAtomicBlock:^{
if (columnIndex == 1) {
if (row >= cheatCount) {
GB_add_cheat(gb, "New Cheat", 0, 0, 0, 0, false, true);
}
else {
GB_update_cheat(gb, cheats[row], cheats[row]->description, cheats[row]->address, cheats[row]->bank, cheats[row]->value, cheats[row]->old_value, cheats[row]->use_old_value, !cheats[row]->enabled);
}
}
else if (row < cheatCount) {
GB_remove_cheat(gb, cheats[row]);
}
}];
[self.cheatsTable reloadData];
[self tableViewSelectionDidChange:nil];
}
- (void)tableViewSelectionDidChange:(NSNotification *)notification
{
GB_gameboy_t *gb = self.document.gameboy;
if (!gb) return;
size_t cheatCount;
const GB_cheat_t *const *cheats = GB_get_cheats(gb, &cheatCount);
unsigned row = self.cheatsTable.selectedRow;
const GB_cheat_t *cheat = NULL;
if (row >= cheatCount) {
static const GB_cheat_t template = {
.address = 0,
.bank = 0,
.value = 0,
.old_value = 0,
.use_old_value = false,
.enabled = false,
.description = "New Cheat",
};
cheat = &template;
}
else {
cheat = cheats[row];
}
self.addressField.stringValue = [GBCheatWindowController addressStringFromCheat:cheat];
self.valueField.stringValue = [NSString stringWithFormat:@"$%02x", cheat->value];
self.oldValueField.stringValue = [NSString stringWithFormat:@"$%02x", cheat->old_value];
self.oldValueCheckbox.state = cheat->use_old_value;
self.descriptionField.stringValue = @(cheat->description);
}
- (void)awakeFromNib
{
[self tableViewSelectionDidChange:nil];
((GBCheatTextFieldCell *)self.addressField.cell).usesAddressFormat = true;
}
- (void)controlTextDidChange:(NSNotification *)obj
{
[self updateCheat:nil];
}
- (IBAction)updateCheat:(id)sender
{
GB_gameboy_t *gb = self.document.gameboy;
if (!gb) return;
uint16_t address = 0;
uint16_t bank = GB_CHEAT_ANY_BANK;
if ([self.addressField.stringValue rangeOfString:@":"].location != NSNotFound) {
sscanf(self.addressField.stringValue.UTF8String, "$%hx:$%hx", &bank, &address);
}
else {
sscanf(self.addressField.stringValue.UTF8String, "$%hx", &address);
}
uint8_t value = 0;
if ([self.valueField.stringValue characterAtIndex:0] == '$') {
sscanf(self.valueField.stringValue.UTF8String, "$%02hhx", &value);
}
else {
sscanf(self.valueField.stringValue.UTF8String, "%hhd", &value);
}
uint8_t oldValue = 0;
if ([self.oldValueField.stringValue characterAtIndex:0] == '$') {
sscanf(self.oldValueField.stringValue.UTF8String, "$%02hhx", &oldValue);
}
else {
sscanf(self.oldValueField.stringValue.UTF8String, "%hhd", &oldValue);
}
size_t cheatCount;
const GB_cheat_t *const *cheats = GB_get_cheats(gb, &cheatCount);
unsigned row = self.cheatsTable.selectedRow;
[self.document performAtomicBlock:^{
if (row >= cheatCount) {
GB_add_cheat(gb,
self.descriptionField.stringValue.UTF8String,
address,
bank,
value,
oldValue,
self.oldValueCheckbox.state,
false);
}
else {
GB_update_cheat(gb,
cheats[row],
self.descriptionField.stringValue.UTF8String,
address,
bank,
value,
oldValue,
self.oldValueCheckbox.state,
cheats[row]->enabled);
}
}];
[self.cheatsTable reloadData];
}
- (void)cheatsUpdated
{
[self.cheatsTable reloadData];
[self tableViewSelectionDidChange:nil];
}
@end