diff --git a/desmume/src/cocoa/DeSmuME.cbp b/desmume/src/cocoa/DeSmuME.cbp
index 76b22267b..627eb7ac0 100644
--- a/desmume/src/cocoa/DeSmuME.cbp
+++ b/desmume/src/cocoa/DeSmuME.cbp
@@ -99,6 +99,11 @@
+
+
+
+
+
diff --git a/desmume/src/cocoa/globals.h b/desmume/src/cocoa/globals.h
index 2e3730266..831098f61 100644
--- a/desmume/src/cocoa/globals.h
+++ b/desmume/src/cocoa/globals.h
@@ -37,6 +37,13 @@
#define DS_SCREEN_X_RATIO (256.0 / (192.0 * 2.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------------------------------------------------------------------------------------
//These are just useful little functions to help with stuff
//defined in cocoa_util.m
@@ -135,6 +142,7 @@ extern NintendoDS *NDS;
@class VideoOutputWindow;
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;
diff --git a/desmume/src/cocoa/main.m b/desmume/src/cocoa/main.m
index 992731734..dba51f14e 100644
--- a/desmume/src/cocoa/main.m
+++ b/desmume/src/cocoa/main.m
@@ -42,9 +42,7 @@ FIXME: Apple+Q during open dialog = badness
FIXME: Live resize needs to work without pausing emulator
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: 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: 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: Traveling windows when constantly resizing with hotkey
*/
@@ -74,10 +72,13 @@ NSMenu *menu;
@interface NSApplication(delegate)
//delegate methods
-- (BOOL)application:(NSApplication *)theApplication openFile:(NSString *)filename;
-- (void)application:(NSApplication *)sender openFiles:(NSArray *)filenames;
-- (void)applicationDidFinishLaunching:(NSNotification *)aNotification;
-- (NSApplicationTerminateReply)applicationShouldTerminate:(NSApplication *)sender;
+- (BOOL)application:(NSApplication*)sender openFile:(NSString*)filename;
+- (void)application:(NSApplication*)sender openFiles:(NSArray*)filenames;
+- (void)applicationWillFinishLaunching:(NSNotification*)aNotification;
+- (void)applicationDidFinishLaunching:(NSNotification*)aNotification;
+- (NSApplicationTerminateReply)applicationShouldTerminate:(NSApplication*)sender;
+
+
@end
@@ -186,8 +187,8 @@ void CreateMenu()
[application_menu addItem: [NSMenuItem separatorItem]];
//Add the preferences menu
- //temp = [application_menu addItemWithTitle:@"Preferences..." action:@selector(preferences) keyEquivalent:@","];
- //[temp setTarget:NSApp];
+ temp = [application_menu addItemWithTitle:@"Preferences..." action:@selector(preferences) keyEquivalent:@","];
+ [temp setTarget:NSApp];
//
[application_menu addItem: [NSMenuItem separatorItem]];
@@ -240,13 +241,29 @@ void CreateMenu()
[temp setTarget:NDS];
//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:@""];
- 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];
- [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]];
rom_info_item = [file addItemWithTitle:@"ROM Info..." action:@selector(showRomInfo) keyEquivalent:@""];
@@ -277,7 +294,6 @@ void CreateMenu()
[load_state_menu setAutoenablesItems:NO];
[temp setSubmenu:load_state_menu];
- int i;
for(i = 0; i < SAVE_SLOTS; i++)
{
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] setEnabled:YES];
- int i2;
- for(i2 = 1; i2 < MAX_FRAME_SKIP; i2++)
+ for(i = 1; i < MAX_FRAME_SKIP; i++)
{
- frame_skip_item[i2] = [frame_skip_menu addItemWithTitle:@"%d" withInt:i2 action:@selector(setFrameSkip:) keyEquivalent:@""];
- [frame_skip_item[i2] setTarget:NDS];
- [frame_skip_item[i2] setEnabled:YES];
+ frame_skip_item[i] = [frame_skip_menu addItemWithTitle:@"%d" withInt:i action:@selector(setFrameSkip:) keyEquivalent:@""];
+ [frame_skip_item[i] setTarget:NDS];
+ [frame_skip_item[i] setEnabled:YES];
}
//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 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 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"];
[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 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 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 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 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 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
/*
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)];
[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 = [help addItemWithTitle:@"Forums" action:@selector(launchForums) keyEquivalent: @""];
+ temp = [help addItemWithTitle:@"Go to Forums" action:@selector(launchForums) keyEquivalent: @""];
[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];
[NSApp setMainMenu: menu];
@@ -545,37 +569,61 @@ int main(int argc, char *argv[])
//gdb stuff--------------------------------------------------------------------------------
//don't know and don't care
-void *
-createThread_gdb( void (*thread_function)( void *data),
- void *thread_data) {
-return NULL;
+void *createThread_gdb(void (*thread_function)(void *data), void *thread_data)
+{
+ return NULL;
}
-void
-joinThread_gdb( void *thread_handle) {
+void joinThread_gdb(void *thread_handle)
+{
}
//Implementations-------------------------------------------------------------------------
@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])
return YES;
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
[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)
main_window = [[VideoOutputWindow alloc] init];
- //start with a blank screen
- [main_window clearScreen];
-
//create the menus
CreateMenu();
//init opengl 3d ness
NDS_3D_SetDriver (GPU3D_OPENGL);
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"];
- //^ above line breaks everything!?
+- (void)applicationDidFinishLaunching:(NSNotification *)aNotification
+{
- //Main program loop ----------------------------------------------------------------------------
+ //Start the main program loop ----------------------------------------------------------------------------
#ifdef MULTITHREADED
@@ -627,4 +673,5 @@ joinThread_gdb( void *thread_handle) {
//AskForQuit takes care of quitting, dont need cocoa to do it for us
return NSTerminateCancel;
}
+
@end
diff --git a/desmume/src/cocoa/main_window.h b/desmume/src/cocoa/main_window.h
index b2ed2cf6e..ec97cba5a 100644
--- a/desmume/src/cocoa/main_window.h
+++ b/desmume/src/cocoa/main_window.h
@@ -34,8 +34,9 @@
//this is the only method involving cocoa that should be called from the run() function
- (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
- (void)resetMinSize:(bool)resize;
@@ -74,6 +75,11 @@
- (void)toggleSubBackground2;
- (void)toggleSubBackground3;
+//screenshots
+- (void)screenShotToFile;
+- (void)screenShotToWindow;
+- (const unsigned char *)getBuffer;//pause before calling
+
//keyboard input
- (void)keyDown:(NSEvent*)event;
- (void)keyUp:(NSEvent*)event;
@@ -82,6 +88,7 @@
- (void)mouseDown:(NSEvent*)event;
- (void)mouseDragged:(NSEvent*)event;
- (void)mouseUp:(NSEvent*)event;
+
@end
#endif //MAIN_WINDOW_H
diff --git a/desmume/src/cocoa/main_window.m b/desmume/src/cocoa/main_window.m
index c4280925f..15d058c27 100644
--- a/desmume/src/cocoa/main_window.m
+++ b/desmume/src/cocoa/main_window.m
@@ -24,6 +24,7 @@
#import "globals.h"
#import "main_window.h"
#import "nds_control.h"
+#import "screenshot.h"
//DeSmuME general includes
#define OBJ_C
@@ -106,10 +107,6 @@ unsigned short save_slot_10 = 109; //F10
NSOpenGLContext *gpu_context;
//rotation
-#define ROTATION_0 0
-#define ROTATION_90 1
-#define ROTATION_180 2
-#define ROTATION_270 3
u8 rotation = ROTATION_0;
//extern unsigned char GPU_screen3D[256*256*4];
@@ -151,7 +148,7 @@ NSSize min_size;
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;
}
@@ -172,14 +169,14 @@ NSSize min_size;
NSOpenGLPixelFormat* pixel_format = [[NSOpenGLPixelFormat alloc] initWithAttributes:attrs];
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;
}
context = [[NSOpenGLContext alloc] initWithFormat:pixel_format shareContext: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;
}
@@ -202,14 +199,14 @@ NSSize min_size;
NSOpenGLPixelFormat* pixel_format2 = [[NSOpenGLPixelFormat alloc] initWithAttributes:attrs2];
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;
}
gpu_context = [[NSOpenGLContext alloc] initWithFormat:pixel_format2 shareContext: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;
}
@@ -346,7 +343,7 @@ NSSize min_size;
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)
//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.height = DS_SCREEN_HEIGHT_COMBINED;
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
{
[[self contentView] addSubview:video_output_view];
@@ -383,6 +380,9 @@ NSSize min_size;
//Show the window
[[[NSWindowController alloc] initWithWindow:self] showWindow:nil];
+ //start with a blank screen
+ [self clearScreenBlack];
+
return self;
}
@@ -410,7 +410,7 @@ NSSize min_size;
[video_output_view draw];
}
-- (void)clearScreen
+- (void)clearScreenWhite
{
//fill our buffer with pure white
memset(&correction_buffer, 255, DS_SCREEN_WIDTH * DS_SCREEN_HEIGHT_COMBINED * 2);
@@ -418,6 +418,14 @@ NSSize min_size;
[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
{
if(rotation == ROTATION_0 || rotation == ROTATION_180)
@@ -450,8 +458,6 @@ NSSize min_size;
- (void)toggleMinSize
{
- static bool state = false;
-
if([min_size_item state] == NSOnState)
{
[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
{
if([event isARepeat])return;
diff --git a/desmume/src/cocoa/nds_control.h b/desmume/src/cocoa/nds_control.h
index f186e7178..1d16c7485 100644
--- a/desmume/src/cocoa/nds_control.h
+++ b/desmume/src/cocoa/nds_control.h
@@ -29,6 +29,9 @@
//creation
- (id)init;
+//Firmware control
+- (void)setPlayerName:(NSString*)player_name;
+
//ROM control
- (void)pickROM;
- (BOOL)loadROM:(NSString*)filename;
diff --git a/desmume/src/cocoa/nds_control.m b/desmume/src/cocoa/nds_control.m
index 4c592139b..24e892e1d 100644
--- a/desmume/src/cocoa/nds_control.m
+++ b/desmume/src/cocoa/nds_control.m
@@ -21,6 +21,7 @@
#import "globals.h"
#import "nds_control.h"
#import "main_window.h"
+#import "preferences.h"
//DeSmuME general includes
#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 u32 backupmemorysize=1;
+struct NDS_fw_config_data firmware;
+
NSString *current_file;
@implementation NintendoDS
@@ -93,32 +96,28 @@ NSString *current_file;
NDS_Init( arm9_memio, &arm9_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);
+[self setPlayerName:@"Joe"];
NDS_CreateDummyFirmware(&firmware);
+
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
{
BOOL was_paused = paused;
@@ -145,7 +144,7 @@ typedef struct {
if(!NDS_LoadROM([filename cStringUsingEncoding:NSASCIIStringEncoding], backupmemorytype, backupmemorysize, "/Users/gecko/AAAA.sav") > 0)
{
//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
if(!was_paused)[self execute];
@@ -153,6 +152,9 @@ typedef struct {
return FALSE;
}
+ //add the rom to the recent documents list
+ [[NSDocumentController sharedDocumentController] noteNewRecentDocumentURL:[NSURL fileURLWithPath:filename]];
+
//set current file var
current_file = filename;
@@ -191,8 +193,11 @@ typedef struct {
//layers apparently get reset on rom load?
//[set topBG2_item fixme
- //if it worked, unpause (start)
- [self execute];
+ //if it worked, check the execute upon load option
+ if([[NSUserDefaults standardUserDefaults] boolForKey:PREF_EXECUTE_UPON_LOAD])
+ [self execute];
+ else
+ [main_window clearScreenWhite];
return true;
}
@@ -233,7 +238,7 @@ typedef struct {
{
[self closeROM];
- [main_window clearScreen];
+ [main_window clearScreenBlack];
}
else if(!was_paused)[NDS execute];
}
@@ -395,8 +400,26 @@ typedef struct {
}
- (void)saveStateAs
-{
- messageDialog(@"LOAD",@"DDSA");
+{//dst
+ 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
diff --git a/desmume/src/cocoa/preferences.m b/desmume/src/cocoa/preferences.m
index f1051f158..20bd8d36b 100644
--- a/desmume/src/cocoa/preferences.m
+++ b/desmume/src/cocoa/preferences.m
@@ -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 "preferences.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;
NSDictionary *preferences_font_attribs;
@@ -15,18 +45,54 @@ NSTabViewItem *plugins_pane_tab;
NSText *language_selection_text;
NSPopUpButton *language_selection;
+NSDictionary *desmume_defaults;
+
///////////////////////////////
@interface PreferencesDelegate : NSObject {}
-- (void)windowWillClose:(NSNotification *)aNotification;
+- (void)windowWillClose:(NSNotification*)aNotification;
@end
@implementation PreferencesDelegate
-- (void)windowWillClose:(NSNotification *)aNotification
+- (void)windowWillClose:(NSNotification*)aNotification
{
+ //[preferences_window saveFrameUsingName:@"DeSmuME Preferences Window"];
+ [preferences_window setFrameAutosaveName:@"DeSmuME Preferences Window"];
+
[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
{
@@ -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
{
+
bool was_paused = paused;
[NDS pause];
- //----------------------------------------------------------------------------------------------
+ if(!preferences_window)
+ {
- //get the applications main bundle
- NSBundle* app_bundle = [NSBundle mainBundle];
+ //----------------------------------------------------------------------------------------------
- //grab the list of languages
- NSArray *languages = [app_bundle localizations];
+ //get the applications main bundle
+ NSBundle* app_bundle = [NSBundle mainBundle];
- //get a font for displaying text
- preferences_font = [NSFont systemFontOfSize:[NSFont systemFontSizeForControlSize:NSRegularControlSize]];
+ //grab the list of languages
+ 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
- PreferencesDelegate *delegate = [[PreferencesDelegate alloc] init];
- //
- int i; //general iterator
+ preferences_font_attribs = [NSDictionary dictionaryWithObjectsAndKeys:preferences_font, NSFontAttributeName, nil];
- //Create the window ------------------------------------------------------------------------------
+ //create our delegate
+ PreferencesDelegate *delegate = [[PreferencesDelegate alloc] init];
- //create a preferences 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];
+ //Create the window ------------------------------------------------------------------------------
- //set the window title
- [preferences_window setTitle:localizedString(@"DeSmuME Preferences", nil)];
+ //create a preferences 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 delegate
- [preferences_window setDelegate:delegate];
+ //set the window title
+ [preferences_window setTitle:localizedString(@"DeSmuME Preferences", nil)];
- //create a tab view
- rect.size.width = 400 - 10;
- 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];
+ //set the window delegate
+ [preferences_window setDelegate:delegate];
- //Create the "Interface" pane
- interface_pane_tab = [[NSTabViewItem alloc] initWithIdentifier:nil];
- [interface_pane_tab setLabel:localizedString(@"Interface", nil)];
- [tab_view addTabViewItem:interface_pane_tab];
+ //create a tab view
+ rect.size.width = 400 - 10;
+ 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 interface view
- rect.size.width = 400 - 10;
- rect.size.height = 300 - 10;
- rect.origin.x = 0;
- rect.origin.y = 0;
- NSView *interface_view = [[NSView alloc] initWithFrame:rect];
- [interface_pane_tab setView:interface_view];
+ //Create the "Interface" pane
+ interface_pane_tab = [[NSTabViewItem alloc] initWithIdentifier:nil];
+ [interface_pane_tab setLabel:localizedString(@"Interface", nil)];
+ [tab_view addTabViewItem:interface_pane_tab];
- //Create language selection text
- rect.size.width = 225;
- rect.size.height = 29 - [localizedString(@"Language",nil) sizeWithAttributes:preferences_font_attribs].height / 2;
- rect.origin.x = 0;
- 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 interface view
+ NSDictionary *interface_options = [NSDictionary dictionaryWithObjectsAndKeys:
+ [NSArray arrayWithObjects:@"Bool", [NSData dataWithBytes:&@selector(executeUponLoad:) length:sizeof(SEL)], @"Yes",@"No",nil], PREF_EXECUTE_UPON_LOAD,
+ nil];
- //Create language selection button
- 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];
+ NSView *interface_view = createPreferencesView(interface_pane_tab, interface_options, delegate);
- //Create the "DS Firmware" pane
- firmware_pane_tab = [[NSTabViewItem alloc] initWithIdentifier:nil];
- [firmware_pane_tab setLabel:localizedString(@"DS Firmware", nil)];
- [tab_view addTabViewItem:firmware_pane_tab];
+ //Create the firmware pane
+ firmware_pane_tab = [[NSTabViewItem alloc] initWithIdentifier:nil];
+ [firmware_pane_tab setLabel:localizedString(@"DS Firmware", nil)];
+ [tab_view addTabViewItem:firmware_pane_tab];
- //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 *firmware_options = [NSDictionary dictionaryWithObjectsAndKeys:
+ [NSArray arrayWithObjects:@"Text", [NSData dataWithBytes:&@selector(playerName:) length:sizeof(SEL)], nil], PREF_FIRMWARE_PLAYER_NAME,
+ [NSArray arrayWithObjects:@"Array", [NSData dataWithBytes:&@selector(nonexisant:) length:sizeof(SEL)], @"Danish",@"English",@"French",nil], PREF_FIRMWARE_LANGUAGE,
+ 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
- [[[NSWindowController alloc] initWithWindow:preferences_window] showWindow:nil];
+ [wc showWindow:nil];
+
[NSApp runModalForWindow:preferences_window];
diff --git a/desmume/src/cocoa/screenshot.h b/desmume/src/cocoa/screenshot.h
new file mode 100644
index 000000000..7569c76ac
--- /dev/null
+++ b/desmume/src/cocoa/screenshot.h
@@ -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
+
+#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
diff --git a/desmume/src/cocoa/screenshot.m b/desmume/src/cocoa/screenshot.m
new file mode 100644
index 000000000..13e943abd
--- /dev/null
+++ b/desmume/src/cocoa/screenshot.m
@@ -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
+
+//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