mirror of
https://github.com/mauiaaron/apple2.git
synced 2024-12-26 15:29:19 +00:00
747a469241
- TODO : various settings appear to be broken, but basic emulator functionality appears to be working ;-)
371 lines
13 KiB
Objective-C
371 lines
13 KiB
Objective-C
/*
|
|
* Apple // emulator for *ix
|
|
*
|
|
* This software package is subject to the GNU General Public License
|
|
* version 3 or later (your choice) as published by the Free Software
|
|
* Foundation.
|
|
*
|
|
* Copyright 2013-2015 Aaron Culliney
|
|
*
|
|
*/
|
|
|
|
#import "EmulatorPrefsController.h"
|
|
#import "EmulatorDiskController.h"
|
|
#import "EmulatorJoystickCalibrationView.h"
|
|
#import "EmulatorWindowController.h"
|
|
#import "common.h"
|
|
|
|
#define kApple2SavedPrefs @"kApple2SavedPrefs"
|
|
#define kApple2CPUSpeed @"kApple2CPUSpeed"
|
|
#define kApple2CPUSpeedIsMax @"kApple2CPUSpeedIsMax"
|
|
#define kApple2AltSpeed @"kApple2AltSpeed"
|
|
#define kApple2AltSpeedIsMax @"kApple2AltSpeedIsMax"
|
|
#define kApple2SoundcardConfig @"kApple2SoundcardConfig"
|
|
#define kApple2ColorConfig @"kApple2ColorConfig"
|
|
#define kApple2JoystickConfig @"kApple2JoystickConfig"
|
|
#define kApple2JoystickAutoRecenter @"kApple2JoystickAutoRecenter"
|
|
#define kApple2JoystickClipToRadius @"kApple2JoystickClipToRadius"
|
|
#define kApple2JoystickStep @"kApple2JoystickStep"
|
|
|
|
@interface EmulatorPrefsController ()
|
|
|
|
@property (assign) IBOutlet NSSlider *cpuSlider;
|
|
@property (assign) IBOutlet NSSlider *altSlider;
|
|
@property (assign) IBOutlet NSTextField *cpuSliderLabel;
|
|
@property (assign) IBOutlet NSTextField *altSliderLabel;
|
|
@property (assign) IBOutlet NSButton *cpuMaxChoice;
|
|
@property (assign) IBOutlet NSButton *altMaxChoice;
|
|
|
|
@property (assign) IBOutlet NSMatrix *soundCardChoice;
|
|
|
|
@property (assign) IBOutlet NSPopUpButton *colorChoice;
|
|
|
|
@property (assign) IBOutlet NSPopUpButton *joystickChoice;
|
|
@property (assign) IBOutlet NSButton *joystickRecenter;
|
|
@property (assign) IBOutlet NSButton *joystickClipToRadius;
|
|
@property (assign) IBOutlet NSTextField *joystickStepLabel;
|
|
@property (assign) IBOutlet NSStepper *joystickStepper;
|
|
@property (assign) IBOutlet NSTextField *joystickStepperLabel;
|
|
@property (assign) IBOutlet NSTextField *joystickKPadNotes;
|
|
@property (assign) IBOutlet NSTextField *joystickDeviceNotes;
|
|
|
|
@property (assign) IBOutlet NSTextField *button0Pressed;
|
|
@property (assign) IBOutlet NSTextField *button1Pressed;
|
|
@property (assign) IBOutlet EmulatorJoystickCalibrationView *joystickCalibrationView;
|
|
|
|
@end
|
|
|
|
@implementation EmulatorPrefsController
|
|
|
|
- (void)awakeFromNib
|
|
{
|
|
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
|
|
BOOL firstTime = ![defaults boolForKey:kApple2SavedPrefs];
|
|
if (firstTime)
|
|
{
|
|
[defaults setBool:YES forKey:kApple2SavedPrefs];
|
|
[defaults setDouble:1.0 forKey:kApple2CPUSpeed];
|
|
[defaults setDouble:CPU_SCALE_SLOWEST forKey:kApple2AltSpeed];
|
|
[defaults setBool:NO forKey:kApple2CPUSpeedIsMax];
|
|
[defaults setBool:NO forKey:kApple2AltSpeedIsMax];
|
|
[defaults setInteger:COLOR_INTERP forKey:kApple2ColorConfig];
|
|
[defaults setInteger:JOY_KPAD forKey:kApple2JoystickConfig];
|
|
[defaults setBool:YES forKey:kApple2JoystickAutoRecenter];
|
|
[defaults removeObjectForKey:kApple2PrefStartupDiskA];
|
|
[defaults removeObjectForKey:kApple2PrefStartupDiskB];
|
|
}
|
|
|
|
cpu_scale_factor = [defaults doubleForKey:kApple2CPUSpeed];
|
|
[self.cpuSlider setDoubleValue:cpu_scale_factor];
|
|
[self.cpuSliderLabel setStringValue:[NSString stringWithFormat:@"%.0f%%", cpu_scale_factor*100]];
|
|
if ([defaults boolForKey:kApple2CPUSpeedIsMax])
|
|
{
|
|
cpu_scale_factor = CPU_SCALE_FASTEST;
|
|
[self.cpuMaxChoice setState:NSOnState];
|
|
[self.cpuSlider setEnabled:NO];
|
|
}
|
|
else
|
|
{
|
|
[self.cpuMaxChoice setState:NSOffState];
|
|
[self.cpuSlider setEnabled:YES];
|
|
}
|
|
|
|
cpu_altscale_factor = [defaults doubleForKey:kApple2AltSpeed];
|
|
[self.altSlider setDoubleValue:cpu_altscale_factor];
|
|
[self.altSliderLabel setStringValue:[NSString stringWithFormat:@"%.0f%%", cpu_altscale_factor*100]];
|
|
if ([defaults boolForKey:kApple2AltSpeedIsMax])
|
|
{
|
|
cpu_altscale_factor = CPU_SCALE_FASTEST;
|
|
[self.altMaxChoice setState:NSOnState];
|
|
[self.altSlider setEnabled:NO];
|
|
}
|
|
else
|
|
{
|
|
[self.altMaxChoice setState:NSOffState];
|
|
[self.altSlider setEnabled:YES];
|
|
}
|
|
|
|
#warning TODO : actually implement sound card choices
|
|
[self.soundCardChoice deselectAllCells];
|
|
[self.soundCardChoice selectCellAtRow:1 column:0];
|
|
|
|
NSInteger mode = [defaults integerForKey:kApple2ColorConfig];
|
|
if (! ((mode >= COLOR_NONE) && (mode < NUM_COLOROPTS)) )
|
|
{
|
|
mode = COLOR_NONE;
|
|
}
|
|
[self.colorChoice selectItemAtIndex:mode];
|
|
prefs_setLongValue(PREF_DOMAIN_VIDEO, PREF_COLOR_MODE, (color_mode_t)mode);
|
|
prefs_sync(PREF_DOMAIN_VIDEO);
|
|
|
|
mode = [defaults integerForKey:kApple2JoystickConfig];
|
|
if (! ((mode >= JOY_PCJOY) && (mode < NUM_JOYOPTS)) )
|
|
{
|
|
mode = JOY_PCJOY;
|
|
}
|
|
joy_mode = (joystick_mode_t)mode;
|
|
[self.joystickChoice selectItemAtIndex:mode];
|
|
|
|
#ifdef KEYPAD_JOYSTICK
|
|
bool autoRecenter = [defaults integerForKey:kApple2JoystickAutoRecenter];
|
|
[self.joystickRecenter setState:autoRecenter ? NSOnState : NSOffState];
|
|
prefs_setBoolValue(PREF_DOMAIN_JOYSTICK, PREF_JOYSTICK_KPAD_AUTO_RECENTER, autoRecenter);
|
|
|
|
long joyStep = [defaults integerForKey:kApple2JoystickStep];
|
|
if (!joyStep)
|
|
{
|
|
joyStep = 1;
|
|
}
|
|
[self.joystickStepLabel setIntegerValue:joyStep];
|
|
[self.joystickStepper setIntegerValue:joyStep];
|
|
prefs_setLongValue(PREF_DOMAIN_JOYSTICK, PREF_JOYSTICK_KPAD_STEP, joyStep);
|
|
|
|
prefs_sync(PREF_DOMAIN_JOYSTICK);
|
|
#endif
|
|
|
|
joy_clip_to_radius = [defaults boolForKey:kApple2JoystickClipToRadius];
|
|
[self.joystickClipToRadius setState:joy_clip_to_radius ? NSOnState : NSOffState];
|
|
|
|
[self _setupJoystickUI];
|
|
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(drawJoystickCalibration:) name:(NSString *)kDrawTimerNotification object:nil];
|
|
}
|
|
|
|
- (void)dealloc
|
|
{
|
|
[[NSNotificationCenter defaultCenter] removeObserver:self];
|
|
[super dealloc];
|
|
}
|
|
|
|
- (void)_savePrefs
|
|
{
|
|
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
|
|
[defaults setBool:YES forKey:kApple2SavedPrefs];
|
|
[defaults setDouble:cpu_scale_factor forKey:kApple2CPUSpeed];
|
|
[defaults setDouble:cpu_altscale_factor forKey:kApple2AltSpeed];
|
|
[defaults setBool:([self.cpuMaxChoice state] == NSOnState) forKey:kApple2CPUSpeedIsMax];
|
|
[defaults setBool:([self.altMaxChoice state] == NSOnState) forKey:kApple2AltSpeedIsMax];
|
|
|
|
long lVal = 0;
|
|
color_mode_t mode = prefs_parseLongValue(PREF_DOMAIN_VIDEO, PREF_COLOR_MODE, &lVal, /*base:*/10) ? (color_mode_t)lVal : COLOR_INTERP;
|
|
[defaults setInteger:mode forKey:kApple2ColorConfig];
|
|
[defaults setInteger:joy_mode forKey:kApple2JoystickConfig];
|
|
|
|
long joyStep = prefs_parseLongValue(PREF_DOMAIN_JOYSTICK, PREF_JOYSTICK_KPAD_STEP, &lVal, /*base:*/10) ? lVal : 1;
|
|
[defaults setInteger:joyStep forKey:kApple2JoystickStep];
|
|
|
|
bool bVal = false;
|
|
bool autoRecenter = prefs_parseBoolValue(PREF_DOMAIN_JOYSTICK, PREF_JOYSTICK_KPAD_AUTO_RECENTER, &bVal) ? bVal : true;
|
|
[defaults setBool:autoRecenter forKey:kApple2JoystickAutoRecenter];
|
|
[defaults setBool:joy_clip_to_radius forKey:kApple2JoystickClipToRadius];
|
|
|
|
prefs_sync(PREF_DOMAIN_JOYSTICK);
|
|
}
|
|
|
|
- (IBAction)sliderDidMove:(id)sender
|
|
{
|
|
NSSlider *slider = (NSSlider *)sender;
|
|
double value = [slider doubleValue];
|
|
if (slider == self.cpuSlider)
|
|
{
|
|
cpu_scale_factor = value;
|
|
[self.cpuSliderLabel setStringValue:[NSString stringWithFormat:@"%.0f%%", value*100]];
|
|
}
|
|
else
|
|
{
|
|
cpu_altscale_factor = value;
|
|
[self.altSliderLabel setStringValue:[NSString stringWithFormat:@"%.0f%%", value*100]];
|
|
}
|
|
|
|
timing_initialize();
|
|
|
|
[self _savePrefs];
|
|
}
|
|
|
|
- (IBAction)peggedChoiceChanged:(id)sender
|
|
{
|
|
NSButton *maxButton = (NSButton *)sender;
|
|
if (maxButton == self.cpuMaxChoice)
|
|
{
|
|
[self.cpuSlider setEnabled:([maxButton state] != NSOnState)];
|
|
cpu_scale_factor = ([maxButton state] == NSOnState) ? CPU_SCALE_FASTEST : [self.cpuSlider doubleValue];
|
|
}
|
|
else
|
|
{
|
|
[self.altSlider setEnabled:([maxButton state] != NSOnState)];
|
|
cpu_altscale_factor = ([maxButton state] == NSOnState) ? CPU_SCALE_FASTEST : [self.altSlider doubleValue];
|
|
}
|
|
|
|
timing_initialize();
|
|
|
|
[self _savePrefs];
|
|
}
|
|
|
|
- (IBAction)colorChoiceChanged:(id)sender
|
|
{
|
|
NSInteger mode = [self.colorChoice indexOfSelectedItem];
|
|
if (! ((mode >= COLOR_NONE) && (mode < NUM_COLOROPTS)) )
|
|
{
|
|
mode = COLOR_NONE;
|
|
}
|
|
prefs_setLongValue(PREF_DOMAIN_VIDEO, PREF_COLOR_MODE, mode);
|
|
prefs_sync(PREF_DOMAIN_VIDEO);
|
|
[self _savePrefs];
|
|
|
|
#warning HACK TODO FIXME need to refactor video resetting procedure
|
|
video_reset();
|
|
}
|
|
|
|
- (IBAction)soundCardChoiceChanged:(id)sender
|
|
{
|
|
#warning TODO : make soundcard configurable at runtime
|
|
}
|
|
|
|
#pragma mark -
|
|
#pragma mark Joystick preferences
|
|
|
|
- (void)_setupJoystickUI
|
|
{
|
|
[self.joystickRecenter setHidden:(joy_mode == JOY_PCJOY)];
|
|
[self.joystickClipToRadius setHidden:(joy_mode != JOY_PCJOY)];
|
|
[self.joystickStepLabel setHidden:(joy_mode == JOY_PCJOY)];
|
|
[self.joystickStepper setHidden:(joy_mode == JOY_PCJOY)];
|
|
[self.joystickStepperLabel setHidden:(joy_mode == JOY_PCJOY)];
|
|
[self.joystickKPadNotes setHidden:(joy_mode == JOY_PCJOY)];
|
|
[self.joystickDeviceNotes setHidden:(joy_mode != JOY_PCJOY)];
|
|
}
|
|
|
|
- (IBAction)joystickChoiceChanged:(id)sender
|
|
{
|
|
NSInteger mode = [self.joystickChoice indexOfSelectedItem];
|
|
if (! ((mode >= JOY_PCJOY) && (mode < NUM_JOYOPTS)) )
|
|
{
|
|
mode = JOY_PCJOY;
|
|
}
|
|
joy_mode = (joystick_mode_t)mode;
|
|
[self _setupJoystickUI];
|
|
[self _savePrefs];
|
|
}
|
|
|
|
- (IBAction)autoRecenterChoiceChanged:(id)sender
|
|
{
|
|
bool autoRecenter = ([self.joystickRecenter state] == NSOnState);
|
|
prefs_setBoolValue(PREF_DOMAIN_JOYSTICK, PREF_JOYSTICK_KPAD_AUTO_RECENTER, autoRecenter);
|
|
[self _savePrefs];
|
|
}
|
|
|
|
- (IBAction)clipToRadiusChoiceChanged:(id)sender
|
|
{
|
|
joy_clip_to_radius = ([self.joystickClipToRadius state] == NSOnState);
|
|
[self _savePrefs];
|
|
}
|
|
|
|
- (IBAction)stepValueChanged:(id)sender
|
|
{
|
|
long joyStep = [self.joystickStepper intValue];
|
|
[self.joystickStepLabel setIntegerValue:joyStep];
|
|
prefs_setLongValue(PREF_DOMAIN_JOYSTICK, PREF_JOYSTICK_KPAD_AUTO_RECENTER, joyStep);
|
|
[self _savePrefs];
|
|
}
|
|
|
|
#pragma mark -
|
|
#pragma Joystick calibration
|
|
|
|
- (void)drawJoystickCalibration:(NSNotification *)notification
|
|
{
|
|
if (![self.joystickCalibrationView isHidden])
|
|
{
|
|
[self.joystickCalibrationView setNeedsDisplay:YES];
|
|
[self.button0Pressed setHidden:!(joy_button0)];
|
|
[self.button1Pressed setHidden:!(joy_button1)];
|
|
}
|
|
}
|
|
|
|
- (void)flagsChanged:(NSEvent*)event
|
|
{
|
|
// NOTE : yay, awesome! checking for ([event modifierFlags] & NSAlternateKeyMask) does not work properly if both were pressed and then one ALT key is unpressed ... kudoes to Apple for an excellent key-handling API /sarc
|
|
static BOOL leftAltEngaged = NO;
|
|
static BOOL rightAltEngaged = NO;
|
|
switch ([event keyCode])
|
|
{
|
|
case ALT_LT:
|
|
leftAltEngaged = !leftAltEngaged;
|
|
c_keys_handle_input(SCODE_L_ALT, /*pressed:*/leftAltEngaged, /*cooked:*/0);
|
|
break;
|
|
case ALT_RT:
|
|
rightAltEngaged = !rightAltEngaged;
|
|
c_keys_handle_input(SCODE_R_ALT, /*pressed:*/rightAltEngaged, /*cooked:*/0);
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
if (!([event modifierFlags] & NSAlternateKeyMask))
|
|
{
|
|
// But we can trust the system state if no alt modifier exists ... this resets b0rken edge cases
|
|
leftAltEngaged = NO;
|
|
rightAltEngaged = NO;
|
|
}
|
|
[self.button0Pressed setHidden:!(joy_button0)];
|
|
[self.button1Pressed setHidden:!(joy_button1)];
|
|
}
|
|
|
|
- (void)_handleKeyEvent:(NSEvent *)event pressed:(BOOL)pressed
|
|
{
|
|
unichar c = [[event charactersIgnoringModifiers] characterAtIndex:0];
|
|
int scode = (int)c;
|
|
switch (scode)
|
|
{
|
|
case NSUpArrowFunctionKey:
|
|
c_keys_handle_input(SCODE_U, pressed, /*cooked:*/0);
|
|
break;
|
|
case NSDownArrowFunctionKey:
|
|
c_keys_handle_input(SCODE_D, pressed, /*cooked:*/0);
|
|
break;
|
|
case NSLeftArrowFunctionKey:
|
|
c_keys_handle_input(SCODE_L, pressed, /*cooked:*/0);
|
|
break;
|
|
case NSRightArrowFunctionKey:
|
|
c_keys_handle_input(SCODE_R, pressed, /*cooked:*/0);
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
|
|
- (void)keyUp:(NSEvent *)event
|
|
{
|
|
[self _handleKeyEvent:event pressed:NO];
|
|
|
|
// Allow other character to be handled (or not and beep)
|
|
//[super keyDown:event];
|
|
}
|
|
|
|
- (void)keyDown:(NSEvent *)event
|
|
{
|
|
[self _handleKeyEvent:event pressed:YES];
|
|
|
|
// Allow other character to be handled (or not and beep)
|
|
//[super keyDown:event];
|
|
}
|
|
|
|
@end
|