Allow drag&drop of state files

This commit is contained in:
Lior Halphon 2021-04-14 15:20:01 +03:00
parent c1509b6339
commit 8a84a5897e
9 changed files with 103 additions and 14 deletions

View File

@ -44,5 +44,6 @@
-(void) writeMemory:(uint16_t) addr value:(uint8_t)value;
-(void) performAtomicBlock: (void (^)())block;
-(void) connectLinkCable:(NSMenuItem *)sender;
- (bool)loadStateFile:(const char *)path;
@end

View File

@ -1172,12 +1172,12 @@ static unsigned *multiplication_table_for_frequency(unsigned frequency)
}
}
- (IBAction)loadState:(id)sender
- (bool)loadStateFile:(const char *)path
{
bool __block success = false;
NSString *error =
[self captureOutputForBlock:^{
success = GB_load_state(&gb, [[self.fileURL URLByDeletingPathExtension] URLByAppendingPathExtension:[NSString stringWithFormat:@"s%ld", (long)[sender tag] ]].path.UTF8String) == 0;
success = GB_load_state(&gb, path) == 0;
}];
if (!success) {
@ -1186,6 +1186,12 @@ static unsigned *multiplication_table_for_frequency(unsigned frequency)
if (error) {
[GBWarningPopover popoverWithContents:error onWindow:self.mainWindow];
}
return success;
}
- (IBAction)loadState:(id)sender
{
[self loadStateFile:[[self.fileURL URLByDeletingPathExtension] URLByAppendingPathExtension:[NSString stringWithFormat:@"s%ld", (long)[sender tag] ]].path.UTF8String];
}
- (IBAction)clearConsole:(id)sender

View File

@ -142,6 +142,8 @@ static const uint8_t workboy_vk_to_key[] = {
- (void) _init
{
[self registerForDraggedTypes:[NSArray arrayWithObjects: NSPasteboardTypeFileURL, nil]];
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(ratioKeepingChanged) name:@"GBAspectChanged" object:nil];
tracking_area = [ [NSTrackingArea alloc] initWithRect:(NSRect){}
options:NSTrackingMouseEnteredAndExited | NSTrackingActiveAlways | NSTrackingInVisibleRect
@ -626,4 +628,29 @@ static const uint8_t workboy_vk_to_key[] = {
return image_buffers[(current_buffer + 2) % self.numberOfBuffers];
}
-(NSDragOperation)draggingEntered:(id<NSDraggingInfo>)sender
{
NSPasteboard *pboard = [sender draggingPasteboard];
if ( [[pboard types] containsObject:NSURLPboardType] ) {
NSURL *fileURL = [NSURL URLFromPasteboard:pboard];
if (GB_is_stave_state(fileURL.fileSystemRepresentation)) {
return NSDragOperationGeneric;
}
}
return NSDragOperationNone;
}
-(BOOL)performDragOperation:(id<NSDraggingInfo>)sender
{
NSPasteboard *pboard = [sender draggingPasteboard];
if ( [[pboard types] containsObject:NSURLPboardType] ) {
NSURL *fileURL = [NSURL URLFromPasteboard:pboard];
return [_document loadStateFile:fileURL.fileSystemRepresentation];
}
return false;
}
@end

View File

@ -19,12 +19,6 @@
#endif
static inline uint32_t state_magic(void)
{
if (sizeof(bool) == 1) return 'SAME';
return 'S4ME';
}
void GB_attributed_logv(GB_gameboy_t *gb, GB_log_attributes attributes, const char *fmt, va_list args)
{
char *string = NULL;

View File

@ -1170,3 +1170,36 @@ int GB_load_state_from_buffer(GB_gameboy_t *gb, const uint8_t *buffer, size_t le
return load_state_internal(gb, &file);
}
bool GB_is_stave_state(const char *path)
{
bool ret = false;
FILE *f = fopen(path, "rb");
if (!f) return false;
uint32_t magic = 0;
fread(&magic, sizeof(magic), 1, f);
if (magic == state_magic()) {
ret = true;
goto exit;
}
// Legacy corrupted Windows save state
if (magic == 0) {
fread(&magic, sizeof(magic), 1, f);
if (magic == state_magic()) {
ret = true;
goto exit;
}
}
fseek(f, -sizeof(magic), SEEK_END);
fread(&magic, sizeof(magic), 1, f);
if (magic == BE32('BESS')) {
ret = true;
}
exit:
fclose(f);
return ret;
}

View File

@ -27,8 +27,14 @@ void GB_save_state_to_buffer(GB_gameboy_t *gb, uint8_t *buffer);
int GB_load_state(GB_gameboy_t *gb, const char *path);
int GB_load_state_from_buffer(GB_gameboy_t *gb, const uint8_t *buffer, size_t length);
bool GB_is_stave_state(const char *path);
#ifdef GB_INTERNAL
static inline uint32_t state_magic(void)
{
if (sizeof(bool) == 1) return 'SAME';
return 'S4ME';
}
/* For internal in-memory save states (rewind, debugger) that do not need BESS */
size_t GB_get_save_state_size_no_bess(GB_gameboy_t *gb);
void GB_save_state_to_buffer_no_bess(GB_gameboy_t *gb, uint8_t *buffer);

View File

@ -18,6 +18,7 @@ SDL_Texture *texture = NULL;
SDL_PixelFormat *pixel_format = NULL;
enum pending_command pending_command;
unsigned command_parameter;
char *dropped_state_file = NULL;
#ifdef __APPLE__
#define MODIFIER_NAME " " CMD_STRING
@ -1300,9 +1301,15 @@ void run_gui(bool is_running)
break;
}
case SDL_DROPFILE: {
set_filename(event.drop.file, SDL_free);
pending_command = GB_SDL_NEW_FILE_COMMAND;
return;
if (GB_is_stave_state(event.drop.file)) {
dropped_state_file = event.drop.file;
pending_command = GB_SDL_LOAD_STATE_FROM_FILE_COMMAND;
}
else {
set_filename(event.drop.file, SDL_free);
pending_command = GB_SDL_NEW_FILE_COMMAND;
return;
}
}
case SDL_JOYBUTTONDOWN:
{

View File

@ -39,12 +39,14 @@ enum pending_command {
GB_SDL_RESET_COMMAND,
GB_SDL_NEW_FILE_COMMAND,
GB_SDL_QUIT_COMMAND,
GB_SDL_LOAD_STATE_FROM_FILE_COMMAND,
};
#define GB_SDL_DEFAULT_SCALE_MAX 8
extern enum pending_command pending_command;
extern unsigned command_parameter;
extern char *dropped_state_file;
typedef enum {
JOYPAD_BUTTON_LEFT,

View File

@ -142,8 +142,14 @@ static void handle_events(GB_gameboy_t *gb)
break;
case SDL_DROPFILE: {
set_filename(event.drop.file, SDL_free);
pending_command = GB_SDL_NEW_FILE_COMMAND;
if (GB_is_stave_state(event.drop.file)) {
dropped_state_file = event.drop.file;
pending_command = GB_SDL_LOAD_STATE_FROM_FILE_COMMAND;
}
else {
set_filename(event.drop.file, SDL_free);
pending_command = GB_SDL_NEW_FILE_COMMAND;
}
break;
}
@ -434,6 +440,13 @@ static bool handle_pending_command(void)
return false;
}
case GB_SDL_LOAD_STATE_FROM_FILE_COMMAND:
start_capturing_logs();
GB_load_state(&gb, dropped_state_file);
end_capturing_logs(true, false);
SDL_free(dropped_state_file);
return false;
case GB_SDL_NO_COMMAND:
return false;