added option to load most recent file when the program launches. preferences panel code updated to size to fit to the current preference panel.

This commit is contained in:
gecko_reverse 2008-05-13 06:57:32 +00:00
parent 70edd3aa9b
commit b250d8f84b
8 changed files with 267 additions and 155 deletions

View File

@ -10,6 +10,7 @@
- Fixed: Load state from file button works again. [Jeff]
- Save State panel now pauses emulation while the file selection box is open. [Jeff]
- Fixed: Frozen video output (and/or messed 3d emulation) after loading a state. [Jeff]
- Added option to load the most recent file upon launching the program. [Jeff]
Windows port:
- Removed the bug report link with a define, to avoid reports from betas/external builds [shash]
- Added the version on window bar to recognize versions from screenshots [shash]

Binary file not shown.

Binary file not shown.

View File

@ -20,18 +20,21 @@
#import <Cocoa/Cocoa.h>
/* The main window class instanciates an input object,
and places it after the window in the responder chain, so
any events not handled by a the window get sent here.
*/
and places it after the window in the responder chain, so
any events not handled by a the window get sent here.
*/
@class VideoOutputWindow;
@interface InputHandler : NSResponder
{
@private
@private
VideoOutputWindow *my_ds;
}
//
//preferences
+ (NSView*)createPreferencesView:(NSRect)size;
//creation/deletion
- (id)initWithWindow:(VideoOutputWindow*)nds;
- (void)dealloc;

View File

@ -1,20 +1,20 @@
/* Copyright (C) 2007 Jeff Bland
This file is part of DeSmuME
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 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.
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
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 "input.h"
@ -23,14 +23,26 @@
@implementation InputHandler
+ (NSView*)createPreferencesView:(NSRect)size
{
return nil; //to be implemented someday
}
//
- (id)init
{
//make sure we go through through the designated init function
[self doesNotRecognizeSelector:_cmd];
return nil;
}
- (id)initWithWindow:(VideoOutputWindow*)nds
{
self = [super init];
my_ds = nds;
[my_ds retain];
return self;
}
@ -46,8 +58,8 @@
NSUserDefaults *settings = [NSUserDefaults standardUserDefaults];
NSString *chars = [event characters];
if([chars rangeOfString:[settings stringForKey:PREF_KEY_A ]].location!=NSNotFound)[my_ds pressA];
if([chars rangeOfString:[settings stringForKey:PREF_KEY_A ]].location!=NSNotFound)[my_ds pressA];
else if([chars rangeOfString:[settings stringForKey:PREF_KEY_B ]].location!=NSNotFound)[my_ds pressB];
else if([chars rangeOfString:[settings stringForKey:PREF_KEY_SELECT]].location!=NSNotFound)[my_ds pressSelect];
else if([chars rangeOfString:[settings stringForKey:PREF_KEY_START ]].location!=NSNotFound)[my_ds pressStart];
@ -65,8 +77,8 @@
{
NSUserDefaults *settings = [NSUserDefaults standardUserDefaults];
NSString *chars = [event characters];
if([chars rangeOfString:[settings stringForKey:PREF_KEY_A ]].location!=NSNotFound)[my_ds liftA];
if([chars rangeOfString:[settings stringForKey:PREF_KEY_A ]].location!=NSNotFound)[my_ds liftA];
else if([chars rangeOfString:[settings stringForKey:PREF_KEY_B ]].location!=NSNotFound)[my_ds liftB];
else if([chars rangeOfString:[settings stringForKey:PREF_KEY_SELECT]].location!=NSNotFound)[my_ds liftSelect];
else if([chars rangeOfString:[settings stringForKey:PREF_KEY_START ]].location!=NSNotFound)[my_ds liftStart];

View File

@ -522,6 +522,23 @@ fail:
//create the video output window (the only window that opens with the app)
main_window = [[VideoOutputWindow alloc] init];
//check if it should load something by default
if([[[NSUserDefaults standardUserDefaults] stringForKey:PREF_AFTER_LAUNCHED] compare:PREF_AFTER_LAUNCHED_OPTION_LAST_ROM]==NSOrderedSame)
{
NSArray *recent_documents = [[NSDocumentController sharedDocumentController] recentDocumentURLs];
if([recent_documents count] > 0)
{
//we have to convert from a URL to file path. in the future, URL's ought to be used since they are more capable/robust...
NSString *file = [[recent_documents objectAtIndex:0] absoluteString]; //gets it in url form
file = [file stringByReplacingPercentEscapesUsingEncoding:NSUTF8StringEncoding]; //convert escaped characters in url
file = [file substringFromIndex:16]; //gets rid of "File://localhost" url component (there should be a much better way to do this....)
[main_window loadROM:file];
}
}
}
- (NSApplicationTerminateReply)applicationShouldTerminate:(NSApplication*)sender

View File

@ -18,7 +18,13 @@
*/
#define PREF_EXECUTE_UPON_LOAD @"Execute Upon Load"
#define PREF_AFTER_LAUNCHED @"When Launching, Load"
#define PREF_AFTER_LAUNCHED_OPTION_NOTHING @"Load Nothing"
#define PREF_AFTER_LAUNCHED_OPTION_LAST_ROM @"Load Last ROM"
#define PREF_FLASH_FILE @"FlashFile"
#define PREF_KEY_A @"KeyA"
#define PREF_KEY_B @"KeyB"
#define PREF_KEY_X @"KeyX"

View File

@ -1,39 +1,42 @@
/* Copyright (C) 2007 Jeff Bland
This file is part of DeSmuME
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 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.
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
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 "preferences.h"
#include "globals.h"
#import "globals.h"
#import "input.h"
/* Preference settings are stored using NSUserDefaults
which should put them in a property list in /Users/username/Library/Preferences
For the keys we use the same strings you see in the preference menu
such as "Execute Upon Load" 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.
*/
which should put them in a property list in /Users/username/Library/Preferences
For the keys we use the same strings you see in the preference menu
such as "Execute Upon Load" 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.
*/
#define INTERFACE_INTERNAL_NAME @"Interface"
#define CONTROLS_INTERNAL_NAME @"Controls"
#define FIRMWARE_INTERNAL_NAME @"Firmware"
const CGFloat PREFERENCES_WIDTH = 365;
///////////////////////////////
NSFont *preferences_font;
@ -52,16 +55,18 @@ unsigned char utf8_left[3] = { 0xEF, 0x9C, 0x82 };
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,
//Flash file default
@"", PREF_FLASH_FILE,
PREF_AFTER_LAUNCHED_OPTION_NOTHING, PREF_AFTER_LAUNCHED,
//Key defaults
@"v", PREF_KEY_A,
@ -77,9 +82,9 @@ void setAppDefaults()
[[[NSString alloc] initWithBytesNoCopy:utf8_right length:3 encoding:NSUTF8StringEncoding freeWhenDone:NO] autorelease], PREF_KEY_RIGHT,
[[[NSString alloc] initWithBytesNoCopy:&utf8_return length:1 encoding:NSUTF8StringEncoding freeWhenDone:NO] autorelease], PREF_KEY_START,
nil];
[desmume_defaults retain];
//window size defaults
NSRect temp;
temp.origin.x = 600;
@ -87,21 +92,20 @@ void setAppDefaults()
temp.size.width = 500;
temp.size.height = 600;
//[NSData dataWithBytes:&temp length:sizeof(NSRect)], @"DeSmuME Preferences Window", nil];
[[NSUserDefaults standardUserDefaults] registerDefaults:desmume_defaults];
}
///////////////////////////////
@interface PreferencesDelegate : NSObject {}
- (void)windowWillClose:(NSNotification*)aNotification;
@end
@implementation PreferencesDelegate
- (void)windowWillClose:(NSNotification*)aNotification
{
[NSApp stopModal];
[[NSUserDefaults standardUserDefaults] synchronize];
}
@ -109,27 +113,38 @@ void setAppDefaults()
{
//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)afterLaunch:(id)sender
{
if([sender indexOfSelectedItem] == 0)
[[NSUserDefaults standardUserDefaults] setObject:PREF_AFTER_LAUNCHED_OPTION_NOTHING forKey:PREF_AFTER_LAUNCHED];
else
[[NSUserDefaults standardUserDefaults] setObject:PREF_AFTER_LAUNCHED_OPTION_LAST_ROM forKey:PREF_AFTER_LAUNCHED];
}
@end
////////////////////////////////////////////////////
@interface ToolbarDelegate : NSObject
{
NSTabView *tab_view;
NSWindow *window;
NSToolbarItem *interface;
NSView *interface_view;
NSToolbarItem *controls;
NSView *controls_view;
NSToolbarItem *ds_firmware;
NSView *firmware_view;
}
- (id)initWithTabView:(NSTabView*)tabview;
- (id)initWithWindow:(NSWindow*)_window generalView:(NSView*)g controlsView:(NSView*)c firmwareView:(NSView*)f;
- (void)dealloc;
- (NSToolbarItem*)toolbar:(NSToolbar*)toolbar itemForItemIdentifier:(NSString*)itemIdentifier willBeInsertedIntoToolbar:(BOOL)flag;
- (NSArray*)toolbarAllowedItemIdentifiers:(NSToolbar*)toolbar;
@ -145,13 +160,22 @@ void setAppDefaults()
return nil;
}
- (id)initWithTabView:(NSTabView*)tabview
- (id)initWithWindow:(NSWindow*)_window generalView:(NSView*)g controlsView:(NSView*)c firmwareView:(NSView*)f;
{
self = [super init];
if(self == nil)return nil;
tab_view = tabview;
[tab_view retain];
window = _window;
[window retain];
interface_view = g;
[interface_view retain];
controls_view = c;
[controls_view retain];
firmware_view = f;
[firmware_view retain];
interface = controls = ds_firmware = nil;
@ -161,9 +185,12 @@ void setAppDefaults()
- (void)dealloc
{
[interface release];
[interface_view release];
[controls release];
[controls_view release];
[ds_firmware release];
[tab_view release];
[firmware_view release];
[window release];
[super dealloc];
}
@ -173,7 +200,7 @@ void setAppDefaults()
if([itemIdentifier compare:INTERFACE_INTERNAL_NAME] == NSOrderedSame)
{
if(interface == nil)
{
interface = [[NSToolbarItem alloc] initWithItemIdentifier:INTERFACE_INTERNAL_NAME];
@ -186,7 +213,7 @@ void setAppDefaults()
result = interface;
} else if([itemIdentifier compare:CONTROLS_INTERNAL_NAME] == NSOrderedSame)
{
if(controls == nil)
{
controls = [[NSToolbarItem alloc] initWithItemIdentifier:CONTROLS_INTERNAL_NAME];
@ -199,7 +226,7 @@ void setAppDefaults()
result = controls;
} else if([itemIdentifier compare:FIRMWARE_INTERNAL_NAME] == NSOrderedSame)
{
if(ds_firmware == nil)
{
ds_firmware = [[NSToolbarItem alloc] initWithItemIdentifier:FIRMWARE_INTERNAL_NAME];
@ -234,43 +261,89 @@ void setAppDefaults()
- (void)toolbarItemClicked:(id)sender
{
[tab_view selectTabViewItemWithIdentifier:[sender itemIdentifier]];
//Check what button was clicked
NSString *item_clicked = [sender itemIdentifier];
NSView *new_view;
if([item_clicked compare:INTERFACE_INTERNAL_NAME] == NSOrderedSame)
{
if([interface_view superview] == [window contentView])return;
new_view = interface_view;
} else if([item_clicked compare:CONTROLS_INTERNAL_NAME] == NSOrderedSame)
{
if([controls_view superview] == [window contentView])return;
new_view = controls_view;
} else if([item_clicked compare:FIRMWARE_INTERNAL_NAME] == NSOrderedSame)
{
if([firmware_view superview] == [window contentView])return;
new_view = firmware_view;
} else return;
//Add/remove views to show only the view we now want to see
NSView *content_view = [window contentView];
if(interface_view == new_view)[content_view addSubview:interface_view];
else [interface_view removeFromSuperview];
if(controls_view == new_view)[content_view addSubview:controls_view];
else [controls_view removeFromSuperview];
if(firmware_view == new_view)[content_view addSubview:firmware_view];
else [firmware_view removeFromSuperview];
//Resize window to fit the new information perfectly
//we must take into account the size of the titlebar and toolbar
//and we also have to recalc the window position to keep the top of the window in the same place,
//since coordinates are based from the bottom left
NSRect old_window_size = [window frame];
NSRect new_window_size = [window frameRectForContentRect:[new_view frame]];
new_window_size.size.width = PREFERENCES_WIDTH;
new_window_size.origin.x = old_window_size.origin.x;
new_window_size.origin.y = old_window_size.origin.y + old_window_size.size.height - new_window_size.size.height;
[window setFrame:new_window_size display:YES animate:YES];
}
@end
////////////////////////////////////////////////////
@implementation NSApplication(custom_extensions)
NSView *createPreferencesView(NSTabViewItem *tab, NSDictionary *options, id delegate)
NSView *createPreferencesView(NSString *helpinfo, NSDictionary *options, id delegate)
{
//create the view
NSView *view = [[NSView alloc] initWithFrame:[[tab tabView] contentRect]];
[tab setView:view];
NSView *view = [[NSView alloc] initWithFrame:NSMakeRect(0, 0, PREFERENCES_WIDTH, 10)];
//loop through each option in the options list
NSEnumerator *key_enumerator = [options keyEnumerator];
NSEnumerator *object_enumerator = [options objectEnumerator];
//this is done backwards since we build the view upwards
NSArray *keys = [options allKeys];
NSEnumerator *key_enumerator = [keys reverseObjectEnumerator];
id key, key_raw, object;
NSRect text_rect = NSMakeRect(0, [view frame].size.height, 255, 29);
NSRect button_rect = NSMakeRect(230, [view frame].size.height, 130, 26);
NSRect text_rect = NSMakeRect(5, 5, 220, 29);
NSRect button_rect = NSMakeRect(230, 5, PREFERENCES_WIDTH - 235, 26);
while ((key_raw = [key_enumerator nextObject]))
{
object = [object_enumerator nextObject];
object = [options objectForKey:key_raw];
key = NSLocalizedString(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
@ -278,34 +351,34 @@ NSView *createPreferencesView(NSTabViewItem *tab, NSDictionary *options, id dele
[[object objectAtIndex:1] getBytes:&action];
[button setAction:action];
[button setTarget:delegate];
[button addItemWithTitle:NSLocalizedString(@"Yes",nil)];
[button addItemWithTitle:NSLocalizedString(@"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:NSLocalizedString([object objectAtIndex:i],nil)];
//if this is the currently selected or default item
if([current_setting compare:[object objectAtIndex:i]] == NSOrderedSame)
{
@ -313,30 +386,30 @@ NSView *createPreferencesView(NSTabViewItem *tab, NSDictionary *options, id dele
[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(NSLocalizedString(@"Error",nil), [NSString stringWithFormat:NSLocalizedString(@"%@ setting corrupt, resetting to default (%@)",nil),key, NSLocalizedString(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;
@ -351,9 +424,9 @@ NSView *createPreferencesView(NSTabViewItem *tab, NSDictionary *options, id dele
[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.;
@ -365,16 +438,34 @@ NSView *createPreferencesView(NSTabViewItem *tab, NSDictionary *options, id dele
[text setSelectable:NO];
[text setVerticallyResizable:NO];
[view addSubview:text];
//Increase the y
button_rect.origin.y += 29;
}
//set the view
[tab setView:view];
[view release];
//add the info text at the top
NSText *help_text = [[NSText alloc] initWithFrame:NSMakeRect(5, button_rect.origin.y, PREFERENCES_WIDTH-10, 25)];
[help_text setDrawsBackground:NO];
[help_text setVerticallyResizable:YES];
[help_text setHorizontallyResizable:NO];
[help_text insertText:helpinfo];
[help_text setSelectable:NO];
[help_text setEditable:NO];
[view addSubview:help_text];
//resize the view to fit the stuff vertically
NSRect temprect = [view frame];
temprect.size.height = button_rect.origin.y + [help_text frame].size.height + 3;
[view setFrame:temprect];
[help_text release];
[view autorelease];
return view;
}
//this is a hack - in the nib we connect preferences to this function name,
//since it's there, and then here we override whatever it's actually supposed to do
//and replace it with the preference panel.
@ -382,83 +473,65 @@ NSView *createPreferencesView(NSTabViewItem *tab, NSDictionary *options, id dele
- (void)orderFrontDataLinkPanel:(id)sender //<- Preferences Display Function
{
//----------------------------------------------------------------------------------------------
//get the applications main bundle
//NSBundle* app_bundle = [NSBundle mainBundle];
//get a font for displaying text
preferences_font = [NSFont systemFontOfSize:[NSFont systemFontSizeForControlSize:NSRegularControlSize]];
preferences_font_attribs = [NSDictionary dictionaryWithObjectsAndKeys:preferences_font, NSFontAttributeName, nil];
//create our delegate
PreferencesDelegate *delegate = [[PreferencesDelegate alloc] init];
//Create the window ------------------------------------------------------------------------------
//create a preferences window
NSRect rect;
rect.size.width = 365;
rect.size.height = 300;
rect.origin.x = 200;
rect.origin.y = 200;
NSWindow *preferences_window = [[NSWindow alloc] initWithContentRect:rect styleMask:
NSTitledWindowMask|NSClosableWindowMask backing:NSBackingStoreBuffered defer:NO screen:nil];
[preferences_window setTitle:NSLocalizedString(@"DeSmuME Preferences", nil)];
[preferences_window setDelegate:delegate];
[preferences_window setFrameAutosaveName:@"DeSmuME Preferences Window"];
//create a tab view
NSTabView *tab_view = [[NSTabView alloc] initWithFrame:NSMakeRect(0,0,1,1)];
[tab_view setTabViewType:NSNoTabsNoBorder];
[preferences_window setContentView:tab_view];
//Create the "Interface" pane
NSTabViewItem *interface_tab = [[NSTabViewItem alloc] initWithIdentifier:INTERFACE_INTERNAL_NAME];
[tab_view addTabViewItem:interface_tab];
//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];
createPreferencesView(interface_tab, interface_options, delegate);
[interface_tab release];
//Create the "Controls" pane
NSTabViewItem *controls_tab = [[NSTabViewItem alloc] initWithIdentifier:CONTROLS_INTERNAL_NAME];
[tab_view addTabViewItem:controls_tab];
[controls_tab release];
[NSArray arrayWithObjects:@"Bool", [NSData dataWithBytes:&@selector(executeUponLoad:) length:sizeof(SEL)], @"Yes", @"No",nil], PREF_EXECUTE_UPON_LOAD,
[NSArray arrayWithObjects:@"Array", [NSData dataWithBytes:&@selector(afterLaunch:) length:sizeof(SEL)], PREF_AFTER_LAUNCHED_OPTION_NOTHING, PREF_AFTER_LAUNCHED_OPTION_LAST_ROM, nil], PREF_AFTER_LAUNCHED,
nil];
//Create the "DS Firmware" pane
NSTabViewItem *ds_firmware_tab = [[NSTabViewItem alloc] initWithIdentifier:FIRMWARE_INTERNAL_NAME];
[tab_view addTabViewItem:ds_firmware_tab];
[ds_firmware_tab release];
NSView *interface_view = createPreferencesView(@"Use the popup buttons on the right to change settings", interface_options, delegate);
//Create the controls view (to be implemented in the future)
NSView *controls_view = nil;
//create the preferences window
NSWindow *preferences_window = [[NSWindow alloc] initWithContentRect:[interface_view frame] styleMask:
NSTitledWindowMask|NSClosableWindowMask backing:NSBackingStoreBuffered defer:NO screen:nil];
[preferences_window setTitle:NSLocalizedString(@"DeSmuME Preferences", nil)];
[preferences_window setDelegate:delegate];
[preferences_window setFrameAutosaveName:@"DeSmuME Preferences Window"];
[[preferences_window contentView] addSubview:interface_view];
//create the toolbar delegate
ToolbarDelegate *toolbar_delegate = [[ToolbarDelegate alloc]
initWithWindow:preferences_window
generalView:interface_view
controlsView:controls_view
firmwareView:nil];
//create the toolbar
NSToolbar *toolbar =[[NSToolbar alloc] initWithIdentifier:@"DeSmuMe Preferences"];
ToolbarDelegate *toolbar_delegate = [[ToolbarDelegate alloc] initWithTabView:tab_view];
[toolbar setDelegate:toolbar_delegate];
[toolbar setSelectedItemIdentifier:INTERFACE_INTERNAL_NAME];
[toolbar setSelectedItemIdentifier:INTERFACE_INTERNAL_NAME]; //start with the general tab selected
[preferences_window setToolbar:toolbar];
[toolbar release];
[tab_view release];
//show the window
NSWindowController *wc = [[NSWindowController alloc] initWithWindow:preferences_window];
[wc setShouldCascadeWindows:NO];
[wc showWindow:nil];
[wc release];
//run the preferences
[NSApp runModalForWindow:preferences_window];
//
[toolbar_delegate release];
[preferences_window release];