various updates to cocoa port (see change log)

This commit is contained in:
gecko_reverse 2007-08-19 10:23:26 +00:00
parent 214321d03e
commit 7114abee25
10 changed files with 911 additions and 162 deletions

View File

@ -99,6 +99,11 @@
<Option compile="1" /> <Option compile="1" />
<Option link="1" /> <Option link="1" />
</Unit> </Unit>
<Unit filename="screenshot.h" />
<Unit filename="screenshot.m">
<Option compile="1" />
<Option link="1" />
</Unit>
<Unit filename="../config.h" /> <Unit filename="../config.h" />
<Unit filename="../cp15.c"> <Unit filename="../cp15.c">
<Option compilerVar="CC" /> <Option compilerVar="CC" />

View File

@ -37,6 +37,13 @@
#define DS_SCREEN_X_RATIO (256.0 / (192.0 * 2.0)) #define DS_SCREEN_X_RATIO (256.0 / (192.0 * 2.0))
#define DS_SCREEN_Y_RATIO ((192.0 * 2.0) / 256.0) #define DS_SCREEN_Y_RATIO ((192.0 * 2.0) / 256.0)
//Port Specific constants ---------------------------------------------------------------------
#define ROTATION_0 0
#define ROTATION_90 1
#define ROTATION_180 2
#define ROTATION_270 3
//Cocoa Util------------------------------------------------------------------------------------ //Cocoa Util------------------------------------------------------------------------------------
//These are just useful little functions to help with stuff //These are just useful little functions to help with stuff
//defined in cocoa_util.m //defined in cocoa_util.m
@ -135,6 +142,7 @@ extern NintendoDS *NDS;
@class VideoOutputWindow; @class VideoOutputWindow;
extern VideoOutputWindow *main_window; extern VideoOutputWindow *main_window;
void setAppDefaults(); //this is defined in preferences.m and should be called at app launch
//-------------------------------------------------------------------------------------------------- //--------------------------------------------------------------------------------------------------
extern volatile int /*desmume_BOOL*/ execute; extern volatile int /*desmume_BOOL*/ execute;

View File

@ -42,9 +42,7 @@ FIXME: Apple+Q during open dialog = badness
FIXME: Live resize needs to work without pausing emulator FIXME: Live resize needs to work without pausing emulator
FIXME: Hardware acceleration for openglrender.c ?? FIXME: Hardware acceleration for openglrender.c ??
FIXME: When cross-platform (core) components end emulation due to error - pause should be called (set the menu checkmark) FIXME: When cross-platform (core) components end emulation due to error - pause should be called (set the menu checkmark)
FIXME: Multi-threaded version needs to do some sleep()-ing when not running game
FIXME: Some bug where states get messed up and hitting execute does nothing...... FIXME: Some bug where states get messed up and hitting execute does nothing......
FIXME: single threaded version requires an additional event to quit (after you tell the program to exit you gotta click or press something)
FIXME: .nds.gba extensions don't work in open panels FIXME: .nds.gba extensions don't work in open panels
FIXME: Traveling windows when constantly resizing with hotkey FIXME: Traveling windows when constantly resizing with hotkey
*/ */
@ -74,10 +72,13 @@ NSMenu *menu;
@interface NSApplication(delegate) @interface NSApplication(delegate)
//delegate methods //delegate methods
- (BOOL)application:(NSApplication *)theApplication openFile:(NSString *)filename; - (BOOL)application:(NSApplication*)sender openFile:(NSString*)filename;
- (void)application:(NSApplication *)sender openFiles:(NSArray *)filenames; - (void)application:(NSApplication*)sender openFiles:(NSArray*)filenames;
- (void)applicationDidFinishLaunching:(NSNotification *)aNotification; - (void)applicationWillFinishLaunching:(NSNotification*)aNotification;
- (NSApplicationTerminateReply)applicationShouldTerminate:(NSApplication *)sender; - (void)applicationDidFinishLaunching:(NSNotification*)aNotification;
- (NSApplicationTerminateReply)applicationShouldTerminate:(NSApplication*)sender;
@end @end
@ -186,8 +187,8 @@ void CreateMenu()
[application_menu addItem: [NSMenuItem separatorItem]]; [application_menu addItem: [NSMenuItem separatorItem]];
//Add the preferences menu //Add the preferences menu
//temp = [application_menu addItemWithTitle:@"Preferences..." action:@selector(preferences) keyEquivalent:@","]; temp = [application_menu addItemWithTitle:@"Preferences..." action:@selector(preferences) keyEquivalent:@","];
//[temp setTarget:NSApp]; [temp setTarget:NSApp];
// //
[application_menu addItem: [NSMenuItem separatorItem]]; [application_menu addItem: [NSMenuItem separatorItem]];
@ -240,13 +241,29 @@ void CreateMenu()
[temp setTarget:NDS]; [temp setTarget:NDS];
//recent items menu //recent items menu
/* Thanks to Jeff Johnson and the Lap Cat Software Blog for their information on the Open Recent menu in Cocoa*/
/* http://lapcatsoftware.com/blog/ */
temp = [file addItemWithTitle:@"Open Recent" action:nil keyEquivalent:@""]; temp = [file addItemWithTitle:@"Open Recent" action:nil keyEquivalent:@""];
NSMenu *recent_menu = [[NSMenu alloc] initWithTitle:@""]; NSMenu *recent_menu = [[NSMenu alloc] initWithTitle:@"Open Recent"];
[recent_menu performSelector:@selector(_setMenuName:) withObject:@"NSRecentDocumentsMenu"];
[temp setSubmenu:recent_menu]; [temp setSubmenu:recent_menu];
[recent_menu addItemWithTitle:@"Blar" action:nil keyEquivalent:@""]; NSArray *recent_documents = [[NSDocumentController sharedDocumentController] recentDocumentURLs];
int i;
for(i = 0; i < [recent_documents count]; i++)
{
// [recent_menu addItemWithTitle:[[recent_documents objectAtIndex:i] absoluteString] action:nil keyEquivalent:@""];
}
/*
[recent_menu addItem:[NSMenuItem separatorItem]];
temp = [recent_menu addItemWithTitle:@"Clear" action:@selector(clearRecentDocuments:) keyEquivalent:@""];
if(i == 0)[temp setEnabled:NO];
else [temp setEnabled:YES];
[temp setTarget:[NSDocumentController sharedDocumentController]];
*/
[file addItem:[NSMenuItem separatorItem]]; [file addItem:[NSMenuItem separatorItem]];
rom_info_item = [file addItemWithTitle:@"ROM Info..." action:@selector(showRomInfo) keyEquivalent:@""]; rom_info_item = [file addItemWithTitle:@"ROM Info..." action:@selector(showRomInfo) keyEquivalent:@""];
@ -277,7 +294,6 @@ void CreateMenu()
[load_state_menu setAutoenablesItems:NO]; [load_state_menu setAutoenablesItems:NO];
[temp setSubmenu:load_state_menu]; [temp setSubmenu:load_state_menu];
int i;
for(i = 0; i < SAVE_SLOTS; i++) for(i = 0; i < SAVE_SLOTS; i++)
{ {
saveSlot_item[i] = [save_state_menu addItemWithTitle:@"Slot %d" withInt:i action:@selector(saveToSlot:) keyEquivalent:@""]; saveSlot_item[i] = [save_state_menu addItemWithTitle:@"Slot %d" withInt:i action:@selector(saveToSlot:) keyEquivalent:@""];
@ -379,12 +395,11 @@ a way to get the time of a save that's not a string / human formatted...
[frame_skip_item[0] setTarget:NDS]; [frame_skip_item[0] setTarget:NDS];
[frame_skip_item[0] setEnabled:YES]; [frame_skip_item[0] setEnabled:YES];
int i2; for(i = 1; i < MAX_FRAME_SKIP; i++)
for(i2 = 1; i2 < MAX_FRAME_SKIP; i2++)
{ {
frame_skip_item[i2] = [frame_skip_menu addItemWithTitle:@"%d" withInt:i2 action:@selector(setFrameSkip:) keyEquivalent:@""]; frame_skip_item[i] = [frame_skip_menu addItemWithTitle:@"%d" withInt:i action:@selector(setFrameSkip:) keyEquivalent:@""];
[frame_skip_item[i2] setTarget:NDS]; [frame_skip_item[i] setTarget:NDS];
[frame_skip_item[i2] setEnabled:YES]; [frame_skip_item[i] setEnabled:YES];
} }
//Create the screens menu //Create the screens menu
@ -418,7 +433,7 @@ a way to get the time of a save that's not a string / human formatted...
[constrain_item setState:NSOnState]; [constrain_item setState:NSOnState];
[constrain_item setTarget:main_window]; [constrain_item setTarget:main_window];
min_size_item = [view addItemWithTitle: @"No smaller than DS" action:@selector(toggleMinSize) keyEquivalent:@""]; min_size_item = [view addItemWithTitle: @"No Smaller Than DS" action:@selector(toggleMinSize) keyEquivalent:@""];
[min_size_item setState:NSOnState]; [min_size_item setState:NSOnState];
[min_size_item setTarget:main_window]; [min_size_item setTarget:main_window];
@ -429,19 +444,19 @@ a way to get the time of a save that's not a string / human formatted...
NSMenu *rotation_menu = [[NSMenu alloc] initWithTitle:@"Rotation"]; NSMenu *rotation_menu = [[NSMenu alloc] initWithTitle:@"Rotation"];
[temp setSubmenu: rotation_menu]; [temp setSubmenu: rotation_menu];
rotation0_item = [rotation_menu addItemWithTitle:@"0" action:@selector(setRotation0) keyEquivalent:@""]; rotation0_item = [rotation_menu addItemWithTitle:@"Rotation 0" action:@selector(setRotation0) keyEquivalent:@""];
[rotation0_item setState:NSOnState]; [rotation0_item setState:NSOnState];
[rotation0_item setTarget:main_window]; [rotation0_item setTarget:main_window];
rotation90_item = [rotation_menu addItemWithTitle:@"90" action:@selector(setRotation90) keyEquivalent:@""]; rotation90_item = [rotation_menu addItemWithTitle:@"Rotation 90" action:@selector(setRotation90) keyEquivalent:@""];
[rotation90_item setState:NSOffState]; [rotation90_item setState:NSOffState];
[rotation90_item setTarget:main_window]; [rotation90_item setTarget:main_window];
rotation180_item = [rotation_menu addItemWithTitle:@"180" action:@selector(setRotation180) keyEquivalent:@""]; rotation180_item = [rotation_menu addItemWithTitle:@"Rotation 180" action:@selector(setRotation180) keyEquivalent:@""];
[rotation180_item setState:NSOffState]; [rotation180_item setState:NSOffState];
[rotation180_item setTarget:main_window]; [rotation180_item setTarget:main_window];
rotation270_item = [rotation_menu addItemWithTitle:@"270" action:@selector(setRotation270) keyEquivalent:@""]; rotation270_item = [rotation_menu addItemWithTitle:@"Rotation 270" action:@selector(setRotation270) keyEquivalent:@""];
[rotation270_item setState:NSOffState]; [rotation270_item setState:NSOffState];
[rotation270_item setTarget:main_window]; [rotation270_item setTarget:main_window];
@ -485,6 +500,15 @@ a way to get the time of a save that's not a string / human formatted...
[subBG3_item setState:NSOnState]; [subBG3_item setState:NSOnState];
[subBG3_item setTarget:main_window]; [subBG3_item setTarget:main_window];
[view addItem:[NSMenuItem separatorItem]];
allows_resize_item = [view addItemWithTitle:@"Screenshot to File" action:@selector(screenShotToFile) keyEquivalent:@""];
[allows_resize_item setTarget:main_window];
allows_resize_item = [view addItemWithTitle:@"Screenshot to Window" action:@selector(screenShotToWindow) keyEquivalent:@""];
[allows_resize_item setTarget:main_window];
//Create the window menu //Create the window menu
/* /*
window = [[NSMenu alloc] initWithTitle:localizedString(@"Window", nil)]; window = [[NSMenu alloc] initWithTitle:localizedString(@"Window", nil)];
@ -506,13 +530,13 @@ a way to get the time of a save that's not a string / human formatted...
help = [[NSMenu alloc] initWithTitle:localizedString(@"Help", nil)]; help = [[NSMenu alloc] initWithTitle:localizedString(@"Help", nil)];
[menu setSubmenu:help forItem:help_item]; [menu setSubmenu:help forItem:help_item];
temp = [help addItemWithTitle:@"Website" action:@selector(launchWebsite) keyEquivalent: @""]; temp = [help addItemWithTitle:@"Go to Website" action:@selector(launchWebsite) keyEquivalent: @""];
[temp setTarget:NSApp]; [temp setTarget:NSApp];
temp = [help addItemWithTitle:@"Forums" action:@selector(launchForums) keyEquivalent: @""]; temp = [help addItemWithTitle:@"Go to Forums" action:@selector(launchForums) keyEquivalent: @""];
[temp setTarget:NSApp]; [temp setTarget:NSApp];
temp = [help addItemWithTitle:@"Submit A Bug Report" action:@selector(bugReport) keyEquivalent: @""]; temp = [help addItemWithTitle:@"Submit a Bug Report" action:@selector(bugReport) keyEquivalent: @""];
[temp setTarget:NSApp]; [temp setTarget:NSApp];
[NSApp setMainMenu: menu]; [NSApp setMainMenu: menu];
@ -545,37 +569,61 @@ int main(int argc, char *argv[])
//gdb stuff-------------------------------------------------------------------------------- //gdb stuff--------------------------------------------------------------------------------
//don't know and don't care //don't know and don't care
void * void *createThread_gdb(void (*thread_function)(void *data), void *thread_data)
createThread_gdb( void (*thread_function)( void *data), {
void *thread_data) { return NULL;
return NULL;
} }
void void joinThread_gdb(void *thread_handle)
joinThread_gdb( void *thread_handle) { {
} }
//Implementations------------------------------------------------------------------------- //Implementations-------------------------------------------------------------------------
@implementation NSApplication(delegate) @implementation NSApplication(delegate)
- (BOOL)application:(NSApplication *)theApplication openFile:(NSString *)filename - (BOOL)application:(NSApplication*)sender openFile:(NSString*)filename
{ {
//verify everything
if(sender != NSApp)return NO;
if(!filename)return NO;
if([filename length] == 0)return NO;
if([NDS loadROM:filename]) if([NDS loadROM:filename])
return YES; return YES;
return NO; return NO;
} }
- (void)application:(NSApplication *)sender openFiles:(NSArray *)filenames - (void)application:(NSApplication*)sender openFiles:(NSArray*)filenames
{ {
//messageDialog(@"Openfiles",@""); //verify everything
if(sender != NSApp)goto fail;
if(!filenames)goto fail;
if([filenames count] == 0)goto fail;
NSString *filename = [filenames lastObject];
if(!filename)goto fail;
if([filename length] == 0)goto fail;
if([NDS loadROM:filename])
{
[sender replyToOpenOrPrint:NSApplicationDelegateReplySuccess];
return;
}
fail:
[sender replyToOpenOrPrint:NSApplicationDelegateReplySuccess];
} }
- (void)applicationDidFinishLaunching:(NSNotification *)aNotification - (void)applicationWillFinishLaunching:(NSNotification *)aNotification
{ {
//Set default values for all preferences
//(this wont override saved preferences as
//they work in different preference domains)
setAppDefaults();
//More app Init ------------------------------------------------------------------------------ //App Init ------------------------------------------------------------------------------
//Bring the application to the front //Bring the application to the front
[NSApp activateIgnoringOtherApps:TRUE]; [NSApp activateIgnoringOtherApps:TRUE];
@ -586,21 +634,19 @@ joinThread_gdb( void *thread_handle) {
//create the video output window (the only window that opens with the app) //create the video output window (the only window that opens with the app)
main_window = [[VideoOutputWindow alloc] init]; main_window = [[VideoOutputWindow alloc] init];
//start with a blank screen
[main_window clearScreen];
//create the menus //create the menus
CreateMenu(); CreateMenu();
//init opengl 3d ness //init opengl 3d ness
NDS_3D_SetDriver (GPU3D_OPENGL); NDS_3D_SetDriver (GPU3D_OPENGL);
if(!gpu3D->NDS_3D_Init()) if(!gpu3D->NDS_3D_Init())
messageDialog(@"Error", @"Unable to initialize OpenGL components"); messageDialog(localizedString(@"Error", nil), @"Unable to initialize OpenGL components");
}
//[NDS LoadROM:@"/Users/gecko/nds/0004 - Feel the Magic - XY-XX (U) (Trashman).nds"]; - (void)applicationDidFinishLaunching:(NSNotification *)aNotification
//^ above line breaks everything!? {
//Main program loop ---------------------------------------------------------------------------- //Start the main program loop ----------------------------------------------------------------------------
#ifdef MULTITHREADED #ifdef MULTITHREADED
@ -627,4 +673,5 @@ joinThread_gdb( void *thread_handle) {
//AskForQuit takes care of quitting, dont need cocoa to do it for us //AskForQuit takes care of quitting, dont need cocoa to do it for us
return NSTerminateCancel; return NSTerminateCancel;
} }
@end @end

View File

@ -34,8 +34,9 @@
//this is the only method involving cocoa that should be called from the run() function //this is the only method involving cocoa that should be called from the run() function
- (void)updateScreen; - (void)updateScreen;
//makes the screen white //
- (void)clearScreen; - (void)clearScreenWhite; //for when a rom is loaded but stopped
- (void)clearScreenBlack; //for when the emulator is not loaded
//resets the min size internalls (when rotation changes), shouldn't be used from outside //resets the min size internalls (when rotation changes), shouldn't be used from outside
- (void)resetMinSize:(bool)resize; - (void)resetMinSize:(bool)resize;
@ -74,6 +75,11 @@
- (void)toggleSubBackground2; - (void)toggleSubBackground2;
- (void)toggleSubBackground3; - (void)toggleSubBackground3;
//screenshots
- (void)screenShotToFile;
- (void)screenShotToWindow;
- (const unsigned char *)getBuffer;//pause before calling
//keyboard input //keyboard input
- (void)keyDown:(NSEvent*)event; - (void)keyDown:(NSEvent*)event;
- (void)keyUp:(NSEvent*)event; - (void)keyUp:(NSEvent*)event;
@ -82,6 +88,7 @@
- (void)mouseDown:(NSEvent*)event; - (void)mouseDown:(NSEvent*)event;
- (void)mouseDragged:(NSEvent*)event; - (void)mouseDragged:(NSEvent*)event;
- (void)mouseUp:(NSEvent*)event; - (void)mouseUp:(NSEvent*)event;
@end @end
#endif //MAIN_WINDOW_H #endif //MAIN_WINDOW_H

View File

@ -24,6 +24,7 @@
#import "globals.h" #import "globals.h"
#import "main_window.h" #import "main_window.h"
#import "nds_control.h" #import "nds_control.h"
#import "screenshot.h"
//DeSmuME general includes //DeSmuME general includes
#define OBJ_C #define OBJ_C
@ -106,10 +107,6 @@ unsigned short save_slot_10 = 109; //F10
NSOpenGLContext *gpu_context; NSOpenGLContext *gpu_context;
//rotation //rotation
#define ROTATION_0 0
#define ROTATION_90 1
#define ROTATION_180 2
#define ROTATION_270 3
u8 rotation = ROTATION_0; u8 rotation = ROTATION_0;
//extern unsigned char GPU_screen3D[256*256*4]; //extern unsigned char GPU_screen3D[256*256*4];
@ -151,7 +148,7 @@ NSSize min_size;
if(self==nil) if(self==nil)
{ {
messageDialog(@"Error", @"Could not init frame for OpenGL display"); messageDialog(localizedString(@"Error", nil), @"Could not init frame for OpenGL display");
return nil; return nil;
} }
@ -172,14 +169,14 @@ NSSize min_size;
NSOpenGLPixelFormat* pixel_format = [[NSOpenGLPixelFormat alloc] initWithAttributes:attrs]; NSOpenGLPixelFormat* pixel_format = [[NSOpenGLPixelFormat alloc] initWithAttributes:attrs];
if(pixel_format == nil) if(pixel_format == nil)
{ {
messageDialog(@"Error", @"Couldn't create OpenGL pixel format for video output"); messageDialog(localizedString(@"Error", nil), @"Couldn't create OpenGL pixel format for video output");
return self; return self;
} }
context = [[NSOpenGLContext alloc] initWithFormat:pixel_format shareContext:nil]; context = [[NSOpenGLContext alloc] initWithFormat:pixel_format shareContext:nil];
if(context == nil) if(context == nil)
{ {
messageDialog(@"Error", @"Couldn't create OpenGL context for video output"); messageDialog(localizedString(@"Error", nil), @"Couldn't create OpenGL context for video output");
return self; return self;
} }
@ -202,14 +199,14 @@ NSSize min_size;
NSOpenGLPixelFormat* pixel_format2 = [[NSOpenGLPixelFormat alloc] initWithAttributes:attrs2]; NSOpenGLPixelFormat* pixel_format2 = [[NSOpenGLPixelFormat alloc] initWithAttributes:attrs2];
if(pixel_format2 == nil) if(pixel_format2 == nil)
{ {
messageDialog(@"Error", @"Couldn't create OpenGL pixel format for GPU"); messageDialog(localizedString(@"Error", nil), @"Couldn't create OpenGL pixel format for GPU");
return self; return self;
} }
gpu_context = [[NSOpenGLContext alloc] initWithFormat:pixel_format2 shareContext:nil]; gpu_context = [[NSOpenGLContext alloc] initWithFormat:pixel_format2 shareContext:nil];
if(gpu_context == nil) if(gpu_context == nil)
{ {
messageDialog(@"Error", @"Couldn't create OpenGL context for GPU"); messageDialog(localizedString(@"Error", nil), @"Couldn't create OpenGL context for GPU");
return self; return self;
} }
@ -346,7 +343,7 @@ NSSize min_size;
backing:NSBackingStoreBuffered defer:NO screen:nil]; backing:NSBackingStoreBuffered defer:NO screen:nil];
[self setTitle:@"DeSmuME Emulator"]; [self setTitle:localizedString(@"DeSmuME Emulator", nil)];
//set minimum window size (to the starting size, pixel-for-pixel to DS) //set minimum window size (to the starting size, pixel-for-pixel to DS)
//this re-gets the window rect to include the title bar size //this re-gets the window rect to include the title bar size
@ -373,7 +370,7 @@ NSSize min_size;
rect.size.width = DS_SCREEN_WIDTH; rect.size.width = DS_SCREEN_WIDTH;
rect.size.height = DS_SCREEN_HEIGHT_COMBINED; rect.size.height = DS_SCREEN_HEIGHT_COMBINED;
if((video_output_view = [[VideoOutputView alloc] initWithFrame:rect]) == nil) if((video_output_view = [[VideoOutputView alloc] initWithFrame:rect]) == nil)
messageDialog(@"Error", @"Couldn't create OpenGL view to display screens"); messageDialog(localizedString(@"Error", nil), @"Couldn't create OpenGL view to display screens");
else else
{ {
[[self contentView] addSubview:video_output_view]; [[self contentView] addSubview:video_output_view];
@ -383,6 +380,9 @@ NSSize min_size;
//Show the window //Show the window
[[[NSWindowController alloc] initWithWindow:self] showWindow:nil]; [[[NSWindowController alloc] initWithWindow:self] showWindow:nil];
//start with a blank screen
[self clearScreenBlack];
return self; return self;
} }
@ -410,7 +410,7 @@ NSSize min_size;
[video_output_view draw]; [video_output_view draw];
} }
- (void)clearScreen - (void)clearScreenWhite
{ {
//fill our buffer with pure white //fill our buffer with pure white
memset(&correction_buffer, 255, DS_SCREEN_WIDTH * DS_SCREEN_HEIGHT_COMBINED * 2); memset(&correction_buffer, 255, DS_SCREEN_WIDTH * DS_SCREEN_HEIGHT_COMBINED * 2);
@ -418,6 +418,14 @@ NSSize min_size;
[video_output_view draw]; [video_output_view draw];
} }
- (void)clearScreenBlack
{
//fill our buffer with pure white
memset(&correction_buffer, 0, DS_SCREEN_WIDTH * DS_SCREEN_HEIGHT_COMBINED * 2);
[video_output_view draw];
}
- (void)resetMinSize:(bool)resize - (void)resetMinSize:(bool)resize
{ {
if(rotation == ROTATION_0 || rotation == ROTATION_180) if(rotation == ROTATION_0 || rotation == ROTATION_180)
@ -450,8 +458,6 @@ NSSize min_size;
- (void)toggleMinSize - (void)toggleMinSize
{ {
static bool state = false;
if([min_size_item state] == NSOnState) if([min_size_item state] == NSOnState)
{ {
[min_size_item setState:NSOffState]; [min_size_item setState:NSOffState];
@ -881,6 +887,31 @@ NSSize min_size;
} }
} }
- (void)screenShotToFile
{
BOOL was_paused = paused;
[NDS pause];
[[Screenshot alloc] initWithBuffer:correction_buffer rotation:rotation saveOnly:YES];
if(!was_paused)[NDS execute];
}
- (void)screenShotToWindow
{
BOOL was_paused = paused;
[NDS pause];
[[Screenshot alloc] initWithBuffer:correction_buffer rotation:rotation saveOnly:NO];
if(!was_paused)[NDS execute];
}
- (const u8*)getBuffer
{
return (const u8*)correction_buffer;
}
- (void)keyDown:(NSEvent*)event - (void)keyDown:(NSEvent*)event
{ {
if([event isARepeat])return; if([event isARepeat])return;

View File

@ -29,6 +29,9 @@
//creation //creation
- (id)init; - (id)init;
//Firmware control
- (void)setPlayerName:(NSString*)player_name;
//ROM control //ROM control
- (void)pickROM; - (void)pickROM;
- (BOOL)loadROM:(NSString*)filename; - (BOOL)loadROM:(NSString*)filename;

View File

@ -21,6 +21,7 @@
#import "globals.h" #import "globals.h"
#import "nds_control.h" #import "nds_control.h"
#import "main_window.h" #import "main_window.h"
#import "preferences.h"
//DeSmuME general includes //DeSmuME general includes
#define OBJ_C #define OBJ_C
@ -79,6 +80,8 @@ volatile u8 frame_skip = 0; //this is one more than the acutal frame skip, a val
static int backupmemorytype=MC_TYPE_AUTODETECT; static int backupmemorytype=MC_TYPE_AUTODETECT;
static u32 backupmemorysize=1; static u32 backupmemorysize=1;
struct NDS_fw_config_data firmware;
NSString *current_file; NSString *current_file;
@implementation NintendoDS @implementation NintendoDS
@ -93,32 +96,28 @@ NSString *current_file;
NDS_Init( arm9_memio, &arm9_ctrl_iface, NDS_Init( arm9_memio, &arm9_ctrl_iface,
arm7_memio, &arm7_ctrl_iface); arm7_memio, &arm7_ctrl_iface);
typedef struct {
enum nds_fw_ds_type ds_type;
u8 fav_colour;
u8 birth_month;
u8 birth_day;
u16 nickname[MAX_FW_NICKNAME_LENGTH];
u8 nickname_len;
u16 message[MAX_FW_MESSAGE_LENGTH];
u8 message_len;
u8 language;
/* touchscreen calibration */
struct NDS_fw_touchscreen_cal touch_cal[2];
} NDS_fw_config_data;
NDS_fw_config_data firmware;
NDS_FillDefaultFirmwareConfigData(&firmware); NDS_FillDefaultFirmwareConfigData(&firmware);
[self setPlayerName:@"Joe"];
NDS_CreateDummyFirmware(&firmware); NDS_CreateDummyFirmware(&firmware);
return self; return self;
} }
- (void)setPlayerName:(NSString*)player_name
{
//first we convert to UTF-16 which the DS uses to store the nickname
NSData *string_chars = [player_name dataUsingEncoding:NSUnicodeStringEncoding];
//copy the bytes
firmware.nickname_len = MIN([string_chars length],MAX_FW_NICKNAME_LENGTH);
[string_chars getBytes:firmware.nickname length:firmware.nickname_len];
firmware.nickname[firmware.nickname_len / 2] = 0;
//set the firmware
//NDS_CreateDummyFirmware(&firmware);
}
- (void)pickROM - (void)pickROM
{ {
BOOL was_paused = paused; BOOL was_paused = paused;
@ -145,7 +144,7 @@ typedef struct {
if(!NDS_LoadROM([filename cStringUsingEncoding:NSASCIIStringEncoding], backupmemorytype, backupmemorysize, "/Users/gecko/AAAA.sav") > 0) if(!NDS_LoadROM([filename cStringUsingEncoding:NSASCIIStringEncoding], backupmemorytype, backupmemorysize, "/Users/gecko/AAAA.sav") > 0)
{ {
//if it didn't work give an error and dont unpause //if it didn't work give an error and dont unpause
messageDialog(@"Error", @"Could not open file"); messageDialog(localizedString(@"Error", nil), @"Could not open file");
//continue playing if load didn't work //continue playing if load didn't work
if(!was_paused)[self execute]; if(!was_paused)[self execute];
@ -153,6 +152,9 @@ typedef struct {
return FALSE; return FALSE;
} }
//add the rom to the recent documents list
[[NSDocumentController sharedDocumentController] noteNewRecentDocumentURL:[NSURL fileURLWithPath:filename]];
//set current file var //set current file var
current_file = filename; current_file = filename;
@ -191,8 +193,11 @@ typedef struct {
//layers apparently get reset on rom load? //layers apparently get reset on rom load?
//[set topBG2_item fixme //[set topBG2_item fixme
//if it worked, unpause (start) //if it worked, check the execute upon load option
[self execute]; if([[NSUserDefaults standardUserDefaults] boolForKey:PREF_EXECUTE_UPON_LOAD])
[self execute];
else
[main_window clearScreenWhite];
return true; return true;
} }
@ -233,7 +238,7 @@ typedef struct {
{ {
[self closeROM]; [self closeROM];
[main_window clearScreen]; [main_window clearScreenBlack];
} }
else if(!was_paused)[NDS execute]; else if(!was_paused)[NDS execute];
} }
@ -395,8 +400,26 @@ typedef struct {
} }
- (void)saveStateAs - (void)saveStateAs
{ {//dst
messageDialog(@"LOAD",@"DDSA"); BOOL was_paused = paused;
[NDS pause];
NSSavePanel *panel = [NSSavePanel savePanel];
[panel setTitle:localizedString(@"Save State to File...", nil)];
[panel setAllowedFileTypes:[NSArray arrayWithObjects:@"dst",nil]];
if([panel runModal] == NSOKButton)
{
NSString *filename = [panel filename];
if(filename)
savestate_save([filename cStringUsingEncoding:NSASCIIStringEncoding]);
}
if(!was_paused)[NDS execute];
} }
- (void)loadStateFrom - (void)loadStateFrom

View File

@ -1,9 +1,39 @@
/* Copyright (C) 2007 Jeff Bland
This file is part of DeSmuME
DeSmuME is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
DeSmuME is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with DeSmuME; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#import "globals.h" #import "globals.h"
#import "preferences.h"
#import "nds_control.h" #import "nds_control.h"
/* Preference settings are stored using NSUserDefaults
which should put them in a propert list in /Users/username/Library/Preferences
For the keys we use the same strings you see in the preference menu
such as "Language" to keep things simple, of course the unlocalized version
of the strings are used so that when you change language it will still
finds the settings from before. Also theres no guarantee that localized
strings will be unique.
*/
/////////////////////////////// ///////////////////////////////
NSWindow *preferences_window; NSWindow *preferences_window = NULL;
NSFont *preferences_font; NSFont *preferences_font;
NSDictionary *preferences_font_attribs; NSDictionary *preferences_font_attribs;
@ -15,18 +45,54 @@ NSTabViewItem *plugins_pane_tab;
NSText *language_selection_text; NSText *language_selection_text;
NSPopUpButton *language_selection; NSPopUpButton *language_selection;
NSDictionary *desmume_defaults;
/////////////////////////////// ///////////////////////////////
@interface PreferencesDelegate : NSObject {} @interface PreferencesDelegate : NSObject {}
- (void)windowWillClose:(NSNotification *)aNotification; - (void)windowWillClose:(NSNotification*)aNotification;
@end @end
@implementation PreferencesDelegate @implementation PreferencesDelegate
- (void)windowWillClose:(NSNotification *)aNotification - (void)windowWillClose:(NSNotification*)aNotification
{ {
//[preferences_window saveFrameUsingName:@"DeSmuME Preferences Window"];
[preferences_window setFrameAutosaveName:@"DeSmuME Preferences Window"];
[NSApp stopModal]; [NSApp stopModal];
[[NSUserDefaults standardUserDefaults] synchronize];
} }
- (void)textDidChange:(NSNotification*)notification
{
NSText *text_field = [notification object];
NSString *text = [text_field string];
}
- (void)executeUponLoad:(id)sender
{
BOOL value = ([sender indexOfSelectedItem] == 0) ? YES : NO;
[[NSUserDefaults standardUserDefaults] setBool:value forKey:PREF_EXECUTE_UPON_LOAD];
}
/*
- (void)numRecentItems:(id)sender
{
NSString *value = @"invalid";
if([sender indexOfSelectedItem] == 0)
value = @"5";
if([sender indexOfSelectedItem] == 1)
value = @"10";
if([sender indexOfSelectedItem] == 2)
value = @"15";
[[NSUserDefaults standardUserDefaults] setObject:value forKey:PREF_NUM_RECENT_ITEMS];
}*/
- (void)languageChange:(id)sender - (void)languageChange:(id)sender
{ {
@ -82,104 +148,267 @@ See the GNU General Public License details in COPYING.", nil/*OK*/, nil, nil);
/////////////////////////////////////////////////// ///////////////////////////////////////////////////
NSView *createPreferencesView(NSTabViewItem *tab, NSDictionary *options, id delegate)
{
//create the view
NSView *view = [[NSView alloc] initWithFrame:NSMakeRect(0,0,400-10,300-10)];
[tab setView:view];
//loop through each option in the options list
NSEnumerator *key_enumerator = [options keyEnumerator];
NSEnumerator *object_enumerator = [options objectEnumerator];
id key, key_raw, object;
NSRect text_rect = NSMakeRect(0, 230, 255, 29);
NSRect button_rect = NSMakeRect(230, 230, 130, 26);
while ((key_raw = [key_enumerator nextObject]))
{
object = [object_enumerator nextObject];
key = localizedString(key_raw, nil);
NSString *current_setting = [[NSUserDefaults standardUserDefaults] objectForKey:key_raw];
button_rect.origin.y -= 29;
if([[object objectAtIndex:0] compare:@"Bool"] == NSOrderedSame)
{
//Create the button for this option
NSPopUpButton *button = [[NSPopUpButton alloc] initWithFrame:button_rect pullsDown:NO];
//Setup the button callback
//the items array should have a selector encoded in an NSData
//since we can't stick a selector directly in an NSArray
SEL action;
[[object objectAtIndex:1] getBytes:&action];
[button setAction:action];
[button setTarget:delegate];
[button addItemWithTitle:localizedString(@"Yes",nil)];
[button addItemWithTitle:localizedString(@"No",nil)];
[button selectItemAtIndex:([[NSUserDefaults standardUserDefaults] boolForKey:PREF_EXECUTE_UPON_LOAD] == YES) ? 0 : 1];
[view addSubview:button];
}
else if([[object objectAtIndex:0] compare:@"Array"] == NSOrderedSame)
{
//Create the button for this option
NSPopUpButton *button = [[NSPopUpButton alloc] initWithFrame:button_rect pullsDown:NO];
//button callback
SEL action;
[[object objectAtIndex:1] getBytes:&action];
[button setAction:action];
[button setTarget:delegate];
int i;
bool found = false;
for(i = 2; i < [object count]; i++)
{
//add the item to the popup buttons list
[button addItemWithTitle:localizedString([object objectAtIndex:i],nil)];
//if this is the currently selected or default item
if([current_setting compare:[object objectAtIndex:i]] == NSOrderedSame)
{
found = true;
[button selectItemAtIndex:i - 2];
}
}
if(!found)
{ //the user setting for this option was not found
//get the default value
current_setting = [desmume_defaults objectForKey:key_raw];
//show an error
messageDialog(localizedString(@"Error",nil), [NSString stringWithFormat:localizedString(@"%@ setting corrupt, resetting to default (%@)",nil),key, localizedString(current_setting, nil)]);
//set the setting to default
[[NSUserDefaults standardUserDefaults] setObject:current_setting forKey:key_raw];
//show the default setting in the button
for(i = 2; i < [object count]; i++)
if([current_setting compare:[object objectAtIndex:i]] == NSOrderedSame)
;//[button selectItemAtIndex:i - 2];
}
[view addSubview:button];
} else if ([[object objectAtIndex:0] caseInsensitiveCompare:@"Text"] == NSOrderedSame)
{
//if this preference is a text field
//we will create a text field and add it to the view
NSRect temp = button_rect;
temp.size.height = [current_setting sizeWithAttributes:preferences_font_attribs].height + 2;
temp.origin.y += (26. - temp.size.height) / 2.;
NSText *text = [[NSText alloc] initWithFrame:temp];
[text setMinSize:temp.size];
[text setMaxSize:temp.size];
[text setFont:preferences_font];
[text setString:current_setting];
[text setEditable:YES];
[text setDrawsBackground:YES];
[text setDelegate:delegate];
[view addSubview:text];
}
//Create text for this option
text_rect.size.height = [key sizeWithAttributes:preferences_font_attribs].height;
text_rect.origin.y = button_rect.origin.y + (26. - [key sizeWithAttributes:preferences_font_attribs].height) / 2.;
NSText *text = [[NSText alloc] initWithFrame:text_rect];
[text setFont:preferences_font];
[text setString:key];
[text setEditable:NO];
[text setDrawsBackground:NO];
[text setSelectable:NO];
[text setVerticallyResizable:NO];
[view addSubview:text];
}
//set the view
[tab setView:view];
return view;
}
void setAppDefaults()
{
desmume_defaults = [NSDictionary dictionaryWithObjectsAndKeys:
//Interface defaults
@"Yes", PREF_EXECUTE_UPON_LOAD,
//Firmware defaults
@"DeSmuME User", PREF_FIRMWARE_PLAYER_NAME,
@"English", PREF_FIRMWARE_LANGUAGE,
//Plugin defaults
@"OpenGL 3D", PREF_3D_PLUGIN,
@"None", PREF_SOUND_PLUGIN,
nil];
[desmume_defaults retain];
//window size defaults
NSRect temp;
temp.origin.x = 600;
temp.origin.y = 600;
temp.size.width = 500;
temp.size.height = 600;
//[NSData dataWithBytes:&temp length:sizeof(NSRect)], @"DeSmuME Preferences Window", nil];
[[NSUserDefaults standardUserDefaults] registerDefaults:desmume_defaults];
}
- (void)preferences - (void)preferences
{ {
bool was_paused = paused; bool was_paused = paused;
[NDS pause]; [NDS pause];
//---------------------------------------------------------------------------------------------- if(!preferences_window)
{
//get the applications main bundle //----------------------------------------------------------------------------------------------
NSBundle* app_bundle = [NSBundle mainBundle];
//grab the list of languages //get the applications main bundle
NSArray *languages = [app_bundle localizations]; NSBundle* app_bundle = [NSBundle mainBundle];
//get a font for displaying text //grab the list of languages
preferences_font = [NSFont systemFontOfSize:[NSFont systemFontSizeForControlSize:NSRegularControlSize]]; NSArray *languages = [app_bundle localizations];
preferences_font_attribs = [NSDictionary dictionaryWithObjectsAndKeys:preferences_font, NSFontAttributeName, nil]; //get a font for displaying text
preferences_font = [NSFont systemFontOfSize:[NSFont systemFontSizeForControlSize:NSRegularControlSize]];
//create our delegate preferences_font_attribs = [NSDictionary dictionaryWithObjectsAndKeys:preferences_font, NSFontAttributeName, nil];
PreferencesDelegate *delegate = [[PreferencesDelegate alloc] init];
//
int i; //general iterator
//Create the window ------------------------------------------------------------------------------ //create our delegate
PreferencesDelegate *delegate = [[PreferencesDelegate alloc] init];
//create a preferences window //Create the window ------------------------------------------------------------------------------
NSRect rect;
rect.size.width = 400;
rect.size.height = 300;
rect.origin.x = 200;
rect.origin.y = 200;
preferences_window = [[NSWindow alloc] initWithContentRect:rect styleMask:
NSTitledWindowMask|NSClosableWindowMask backing:NSBackingStoreBuffered defer:NO screen:nil];
//set the window title //create a preferences window
[preferences_window setTitle:localizedString(@"DeSmuME Preferences", nil)]; NSRect rect;
rect.size.width = 400;
rect.size.height = 300;
rect.origin.x = 200;
rect.origin.y = 200;
preferences_window = [[NSWindow alloc] initWithContentRect:rect styleMask:
NSTitledWindowMask|NSClosableWindowMask backing:NSBackingStoreBuffered defer:NO screen:nil];
//set the window delegate //set the window title
[preferences_window setDelegate:delegate]; [preferences_window setTitle:localizedString(@"DeSmuME Preferences", nil)];
//create a tab view //set the window delegate
rect.size.width = 400 - 10; [preferences_window setDelegate:delegate];
rect.size.height = 300 - 10;
rect.origin.x = 5;
rect.origin.y = 5;
NSTabView *tab_view = [[NSTabView alloc] initWithFrame:rect];
[[preferences_window contentView] addSubview:tab_view];
//Create the "Interface" pane //create a tab view
interface_pane_tab = [[NSTabViewItem alloc] initWithIdentifier:nil]; rect.size.width = 400 - 10;
[interface_pane_tab setLabel:localizedString(@"Interface", nil)]; rect.size.height = 300 - 10;
[tab_view addTabViewItem:interface_pane_tab]; rect.origin.x = 5;
rect.origin.y = 5;
NSTabView *tab_view = [[NSTabView alloc] initWithFrame:rect];
[[preferences_window contentView] addSubview:tab_view];
//Create interface view //Create the "Interface" pane
rect.size.width = 400 - 10; interface_pane_tab = [[NSTabViewItem alloc] initWithIdentifier:nil];
rect.size.height = 300 - 10; [interface_pane_tab setLabel:localizedString(@"Interface", nil)];
rect.origin.x = 0; [tab_view addTabViewItem:interface_pane_tab];
rect.origin.y = 0;
NSView *interface_view = [[NSView alloc] initWithFrame:rect];
[interface_pane_tab setView:interface_view];
//Create language selection text //Create interface view
rect.size.width = 225; NSDictionary *interface_options = [NSDictionary dictionaryWithObjectsAndKeys:
rect.size.height = 29 - [localizedString(@"Language",nil) sizeWithAttributes:preferences_font_attribs].height / 2; [NSArray arrayWithObjects:@"Bool", [NSData dataWithBytes:&@selector(executeUponLoad:) length:sizeof(SEL)], @"Yes",@"No",nil], PREF_EXECUTE_UPON_LOAD,
rect.origin.x = 0; nil];
rect.origin.y = 200;// + [localizedString(@"Language",nil) sizeWithAttributes:preferences_font_attribs].height / 2;
language_selection_text = [[NSText alloc] initWithFrame:rect];
[language_selection_text setFont: preferences_font];
[language_selection_text setString:localizedString(@"Language",nil)];
[language_selection_text setEditable:NO];
[language_selection_text setDrawsBackground:NO];
[interface_view addSubview:language_selection_text];
//Create language selection button NSView *interface_view = createPreferencesView(interface_pane_tab, interface_options, delegate);
rect.size.width = 130;
rect.size.height = 26;
rect.origin.x = 230;
rect.origin.y = 200;
language_selection = [[NSPopUpButton alloc] initWithFrame:rect pullsDown:NO];
[language_selection addItemWithTitle:@"Default"];
for(i = 0; i < [languages count]; i++)
[language_selection addItemWithTitle:[languages objectAtIndex:i]];
[language_selection setAction:@selector(languageChange:)];
[language_selection setTarget:delegate];
[interface_view addSubview:language_selection];
//Create the "DS Firmware" pane //Create the firmware pane
firmware_pane_tab = [[NSTabViewItem alloc] initWithIdentifier:nil]; firmware_pane_tab = [[NSTabViewItem alloc] initWithIdentifier:nil];
[firmware_pane_tab setLabel:localizedString(@"DS Firmware", nil)]; [firmware_pane_tab setLabel:localizedString(@"DS Firmware", nil)];
[tab_view addTabViewItem:firmware_pane_tab]; [tab_view addTabViewItem:firmware_pane_tab];
//Create the "Plugins" pane NSDictionary *firmware_options = [NSDictionary dictionaryWithObjectsAndKeys:
plugins_pane_tab = [[NSTabViewItem alloc] initWithIdentifier:nil]; [NSArray arrayWithObjects:@"Text", [NSData dataWithBytes:&@selector(playerName:) length:sizeof(SEL)], nil], PREF_FIRMWARE_PLAYER_NAME,
[plugins_pane_tab setLabel:localizedString(@"Plugins", nil)]; [NSArray arrayWithObjects:@"Array", [NSData dataWithBytes:&@selector(nonexisant:) length:sizeof(SEL)], @"Danish",@"English",@"French",nil], PREF_FIRMWARE_LANGUAGE,
[tab_view addTabViewItem:plugins_pane_tab]; nil];
NSView *firmware_view = createPreferencesView(firmware_pane_tab, firmware_options, delegate);
//Create the "Plugins" pane
plugins_pane_tab = [[NSTabViewItem alloc] initWithIdentifier:nil];
[plugins_pane_tab setLabel:localizedString(@"Plugins", nil)];
[tab_view addTabViewItem:plugins_pane_tab];
NSDictionary *plugin_options = [NSDictionary dictionaryWithObjectsAndKeys:
[NSArray arrayWithObjects:@"Array", [NSData dataWithBytes:&@selector(nonexisant:) length:sizeof(SEL)], @"OpenGL 3D",nil], PREF_3D_PLUGIN,
[NSArray arrayWithObjects:@"Array", [NSData dataWithBytes:&@selector(nonexisant:) length:sizeof(SEL)], @"None",nil], PREF_SOUND_PLUGIN,
nil];
NSView *plugins_view = createPreferencesView(plugins_pane_tab, plugin_options, delegate);
}
//make the window controller
NSWindowController *wc = [[NSWindowController alloc] initWithWindow:preferences_window];
[wc setShouldCascadeWindows:NO];
//tell it to store/retrieve window frame from/to previous/later sessions
[preferences_window setFrameUsingName:@"DeSmuME Preferences Window" force:YES];
//[preferences_window setFrameAutosaveName:@"DeSmuME Preferences Window"];
//messageDialog([preferences_window frameAutosaveName],@"");
//show the window //show the window
[[[NSWindowController alloc] initWithWindow:preferences_window] showWindow:nil]; [wc showWindow:nil];
[NSApp runModalForWindow:preferences_window]; [NSApp runModalForWindow:preferences_window];

View File

@ -0,0 +1,44 @@
/* Copyright (C) 2007 Jeff Bland
This file is part of DeSmuME
DeSmuME is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
DeSmuME is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with DeSmuME; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#ifndef SCREENSHOT_H
#define SCREENSHOT_H
#import <Cocoa/Cocoa.h>
#define OBJ_C
#include "../types.h"
#undef BOOL
@interface Screenshot : NSObject
{
NSWindow *window;
NSImage *image;
NSImageView *image_view;
NSButton *save_button;
NSButton *update_button;
NSBitmapImageRep *image_rep;
NSView *format_selection;
NSPopUpButton *format_button;
}
- (id)initWithBuffer:(u8*)buffer rotation:(u8)rotation saveOnly:(BOOL)save_only;
@end
#endif

View File

@ -0,0 +1,352 @@
/* Copyright (C) 2007 Jeff Bland
This file is part of DeSmuME
DeSmuME is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
DeSmuME is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with DeSmuME; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#import <Cocoa/Cocoa.h>
//DeSmuME Cocoa includes
#import "globals.h"
#import "screenshot.h"
#import "main_window.h"
#import "nds_control.h"
//DeSmuME general includes
#define OBJ_C
#include "../MMU.h"
#include "../GPU.h"
#undef BOOL
#define BUTTON_HEIGHT 26.
#define RESIZE_CONTROL_WIDTH 12.
#define NUM_BUTTONS 2.
@interface Screenshot (delegate)
- (void)windowDidResize:(NSNotification*)aNotification;
- (void)saveButtonPressed;
- (void)updateButtonPressed;
- (BOOL)panel:(id)sender isValidFilename:(NSString*)filename;
- (BOOL)panel:(id)sender shouldShowFilename:(NSString *)filename;
@end
@implementation Screenshot (delegate)
- (void)windowDidResize:(NSNotification*)aNotification
{
NSRect content_frame = [[window contentView] frame];
[image_view setFrame:NSMakeRect(0, BUTTON_HEIGHT, content_frame.size.width, content_frame.size.height - BUTTON_HEIGHT)];
float button_width = (content_frame.size.width - RESIZE_CONTROL_WIDTH) / NUM_BUTTONS;
[save_button setFrame:NSMakeRect(0, 0, button_width, BUTTON_HEIGHT)];
[update_button setFrame:NSMakeRect(button_width, 0, button_width, BUTTON_HEIGHT)];
}
- (void)saveButtonPressed
{//localize
NSSavePanel *panel = [NSSavePanel savePanel];
//Create format selection list
NSRect rect;
rect.size.width = 130;
rect.size.height = 26;
rect.origin.x = 230;
rect.origin.y = 200;
[panel setTitle:localizedString(@"Save Screenshot to File", nil)];
//[panel setAllowedFileTypes:[NSArray arrayWithObjects:@"bmp",@"gif",nil]];
if(!format_selection)
{
NSFont *font = [NSFont systemFontOfSize:[NSFont systemFontSizeForControlSize:NSRegularControlSize]];
NSTextView *format_text = [[NSTextView alloc] initWithFrame:NSMakeRect(0,0,500,500)];
[format_text setFont:font];
[format_text setEditable:NO];
[format_text setDrawsBackground:NO];
[format_text setMaxSize:NSMakeSize(500,26)];
[format_text setMinSize:NSMakeSize(1,1)];
[format_text setHorizontallyResizable:YES];
[format_text setVerticallyResizable:YES];
[format_text setString:localizedString(@"Select Image Format: ", nil)];
[format_text sizeToFit];
//center vertically
NSRect temp = [format_text frame];
temp.origin.y = 26.0 / 2.0 - (float)[format_text frame].size.height / 2.0;
[format_text setFrame:temp];
format_button = [[NSPopUpButton alloc] initWithFrame:NSMakeRect([format_text frame].size.width,0,200,26) pullsDown:NO];
[format_button addItemWithTitle:localizedString(@"Pick by Extension", nil)];
[format_button addItemWithTitle:localizedString(@"BMP", nil)];
[format_button addItemWithTitle:localizedString(@"GIF", nil)];
[format_button addItemWithTitle:localizedString(@"JPG", nil)];
[format_button addItemWithTitle:localizedString(@"PNG", nil)];
[format_button addItemWithTitle:localizedString(@"TIFF", nil)];
//[format_button setAction:@selector(??)];
//[format_button setTarget:self];
format_selection = [[NSView alloc] initWithFrame:NSMakeRect(0,0,[format_text frame].size.width + [format_button frame].size.width,26)];
[format_selection addSubview:format_button];
[format_selection addSubview:format_text];
}
[panel setAccessoryView:format_selection];
[panel setDelegate:self];
if(window)
[panel beginSheetForDirectory:@"" file:@"Screenshot.bmp" modalForWindow:window modalDelegate:self
didEndSelector:nil contextInfo:nil];
else
[panel runModal];
}
- (void)updateButtonPressed
{
BOOL was_paused = paused;
[NDS pause];
u8 *bitmap_data = [image_rep bitmapData];
const u16 *buffer_16 = (const u16*)[main_window getBuffer];
int i;
for(i = 0; i < [image_rep size].width * [image_rep size].height; i++)
{ //this loop we go through pixel by pixel and convert from 16bit to 24bit for the NSImage
*(bitmap_data++) = (*buffer_16 & 0x001F) << 3;
*(bitmap_data++) = (*buffer_16 & 0x03E0) >> 5 << 3;
*(bitmap_data++) = (*buffer_16 & 0x7C00) >> 10 << 3;
buffer_16++;
}
//there seems to be issues updating the image when
//it is scaled, probably due to some internal caching of the scaled version.
//resetting the image here to ensure that it updates properly.
[image_view setImage:nil];
[image_view setImage:image];
//tell the image to redraw [soon]
[image_view setNeedsDisplay:YES];
if(!was_paused)[NDS execute];
}
- (BOOL)panel:(id)sender isValidFilename:(NSString*)filename
{
NSBitmapImageFileType type = NSBMPFileType;
if([format_button indexOfSelectedItem] == 0)
{
NSString *ext = [filename pathExtension];
if([ext caseInsensitiveCompare:@"gif"] == NSOrderedSame)
type = NSGIFFileType;
else if([ext caseInsensitiveCompare:@"jpg"] == NSOrderedSame)
type = NSJPEGFileType;
else if([ext caseInsensitiveCompare:@"jpeg"] == NSOrderedSame)
type = NSJPEGFileType;
else if([ext caseInsensitiveCompare:@"png"] == NSOrderedSame)
type = NSPNGFileType;
else if([ext caseInsensitiveCompare:@"tiff"] == NSOrderedSame)
type = NSTIFFFileType;
}
if([format_button indexOfSelectedItem] == 2)
type = NSGIFFileType;
if([format_button indexOfSelectedItem] == 3)
type = NSJPEGFileType;
if([format_button indexOfSelectedItem] == 4)
type = NSPNGFileType;
if([format_button indexOfSelectedItem] == 5)
type = NSTIFFFileType;
[[image_rep representationUsingType:type properties:[NSDictionary dictionary]]
writeToFile:filename atomically:NO];
return YES;
}
- (BOOL)panel:(id)sender shouldShowFilename:(NSString *)filename
{
NSString *ext = [filename pathExtension];
int index = [format_button indexOfSelectedItem];
if((index == 1) || (index == 0))
if([ext caseInsensitiveCompare:@"bmp"] == NSOrderedSame)
return YES;
if((index == 2) || (index == 0))
if([ext caseInsensitiveCompare:@"gif"] == NSOrderedSame)
return YES;
if((index == 3) || (index == 0))
if(([ext caseInsensitiveCompare:@"jpg"] == NSOrderedSame) || ([ext caseInsensitiveCompare:@"jpeg"] == NSOrderedSame))
return YES;
if((index == 4) || (index == 0))
if([ext caseInsensitiveCompare:@"png"] == NSOrderedSame)
return YES;
if((index == 5) || (index == 0))
if([ext caseInsensitiveCompare:@"tiff"] == NSOrderedSame)
return YES;
return NO;
}
@end
@implementation Screenshot
- (id)initWithBuffer:(u8*)buffer rotation:(u8)rotation saveOnly:(BOOL)save_only
{
self = [super init];
//this gets set upon the first save panel
format_selection = nil;
window = nil;
NSRect rect;
if(rotation == ROTATION_0 || rotation == ROTATION_180)
{
rect.size.width = DS_SCREEN_WIDTH;
rect.size.height = DS_SCREEN_HEIGHT_COMBINED;
} else
{
rect.size.width = DS_SCREEN_HEIGHT_COMBINED;
rect.size.height = DS_SCREEN_WIDTH;
}
rect.origin.x = 200;
rect.origin.y = 200;
//create the image
image_rep = [[NSBitmapImageRep alloc] initWithBitmapDataPlanes:NULL
pixelsWide:rect.size.width
pixelsHigh:rect.size.height
bitsPerSample:8
samplesPerPixel:3
hasAlpha:NO
isPlanar:NO
colorSpaceName:NSCalibratedRGBColorSpace
bytesPerRow:rect.size.width * 3
bitsPerPixel:24];
if(!image_rep)
{
messageDialog(localizedString(@"Error", nil), @"Could not create NSBitmapImageRep for screenshot");
return nil;
}
u8 *bitmap_data = [image_rep bitmapData];
u16 *buffer_16 = (u16*)buffer;
int i;
for(i = 0; i < rect.size.width * rect.size.height; i++)
{ //this loop we go through pixel by pixel and convert from 16bit to 24bit for the NSImage
*(bitmap_data++) = (*buffer_16 & 0x001F) << 3;
*(bitmap_data++) = (*buffer_16 & 0x03E0) >> 5 << 3;
*(bitmap_data++) = (*buffer_16 & 0x7C00) >> 10 << 3;
buffer_16++;
}
if(save_only)
{
[self saveButtonPressed];
} else
{
//create the image
image = [[NSImage alloc] initWithSize:NSMakeSize(rect.size.width, rect.size.height)];
if(!image)
{
messageDialog(localizedString(@"Error", nil), @"Could not create NSImage for screenshot window");
return nil;
}
[image setBackgroundColor:[NSColor whiteColor]];
[image addRepresentation:image_rep];
//create the image view
image_view = [[NSImageView alloc] initWithFrame:rect];
if(!image_view)
{
messageDialog(localizedString(@"Error", nil), @"Could not create NSImageView for screenshot window");
return nil;
}
[image_view setImage:image];
[image_view setImageScaling:NSScaleToFit];
//create the save button
save_button = [[NSButton alloc] initWithFrame:rect];
if(!save_button)
{
messageDialog(localizedString(@"Error", nil), @"Could not create save button for screenshot window");
return nil;
}
[save_button setBezelStyle:NSRoundedBezelStyle];
[save_button setTitle:localizedString(@"Save Screenshot", nil)];
[save_button setAction:@selector(saveButtonPressed)];
[save_button setTarget:self];
//update
update_button = [[NSButton alloc] initWithFrame:rect];
if(!update_button)
{
messageDialog(localizedString(@"Error", nil), @"Could not create update button for screenshot window");
return nil;
}
[update_button setBezelStyle:NSRoundedBezelStyle];
[update_button setTitle:localizedString(@"Update Screenshot", nil)];
[update_button setAction:@selector(updateButtonPressed)];
[update_button setTarget:self];
//create a window
rect.size.height += BUTTON_HEIGHT;
window = [[NSWindow alloc] initWithContentRect:rect styleMask:
NSTitledWindowMask|NSClosableWindowMask|NSResizableWindowMask backing:NSBackingStoreBuffered defer:NO screen:nil];
//set the window title
[window setTitle:localizedString(@"DeSmuME Screenshot", nil)];
//set the window delegate
[window setDelegate:self];
//add the items to the window
[[window contentView] addSubview:image_view];
[[window contentView] addSubview:save_button];
[[window contentView] addSubview:update_button];
//size the stuff (by invoking our resize callback)
[self windowDidResize:nil];
//show the window
[[[NSWindowController alloc] initWithWindow:window] showWindow:nil];
}
return self;
}
@end