apple2ix/Apple2Mac/Classes/OSX/EmulatorPrefsController.m
2019-03-10 12:17:06 -07:00

334 lines
11 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"
@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 *monochromeColorChoice;
@property (assign) IBOutlet NSButton *scanlinesChoice;
@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;
- (void)loadPrefsForDomain:(const char *)domain;
@end
static EmulatorPrefsController *prefsInstance = nil;
static void prefsChangeCallback(const char *domain)
{
assert(prefsInstance);
[prefsInstance loadPrefsForDomain:domain];
}
@implementation EmulatorPrefsController
- (void)awakeFromNib
{
assert(!prefsInstance);
prefsInstance = self;
prefs_registerListener(PREF_DOMAIN_AUDIO, prefsChangeCallback);
prefs_registerListener(PREF_DOMAIN_INTERFACE, prefsChangeCallback);
prefs_registerListener(PREF_DOMAIN_JOYSTICK, prefsChangeCallback);
prefs_registerListener(PREF_DOMAIN_KEYBOARD, prefsChangeCallback);
//prefs_registerListener(PREF_DOMAIN_TOUCHSCREEN, prefsChangeCallback);
prefs_registerListener(PREF_DOMAIN_VIDEO, prefsChangeCallback);
prefs_registerListener(PREF_DOMAIN_VM, prefsChangeCallback);
[self _setupJoystickUI];
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(drawJoystickCalibration:) name:(NSString *)kDrawTimerNotification object:nil];
}
- (void)loadPrefsForDomain:(const char *)domain
{
domain = NULL; (void)domain;
float fVal, fValDisplay;
fVal = prefs_parseFloatValue(PREF_DOMAIN_VM, PREF_CPU_SCALE, &fVal) ? fVal/100 : 1.0;
fValDisplay = fVal;
if (fVal >= CPU_SCALE_FASTEST)
{
fVal = CPU_SCALE_FASTEST;
fValDisplay = CPU_SCALE_FASTEST_PIVOT;
[self.cpuMaxChoice setState:NSOnState];
[self.cpuSlider setEnabled:NO];
}
else
{
[self.cpuMaxChoice setState:NSOffState];
[self.cpuSlider setEnabled:YES];
}
[self.cpuSlider setFloatValue:fVal];
[self.cpuSliderLabel setStringValue:[NSString stringWithFormat:@"%.0f%%", fValDisplay*100]];
fVal = prefs_parseFloatValue(PREF_DOMAIN_VM, PREF_CPU_SCALE_ALT, &fVal) ? fVal/100 : 1.0;
fValDisplay = fVal;
if (fVal >= CPU_SCALE_FASTEST)
{
fVal = CPU_SCALE_FASTEST;
fValDisplay = CPU_SCALE_FASTEST_PIVOT;
[self.altMaxChoice setState:NSOnState];
[self.altSlider setEnabled:NO];
}
else
{
[self.altMaxChoice setState:NSOffState];
[self.altSlider setEnabled:YES];
}
[self.altSlider setFloatValue:fVal];
[self.altSliderLabel setStringValue:[NSString stringWithFormat:@"%.0f%%", fValDisplay*100]];
#warning TODO : actually implement sound card choices
[self.soundCardChoice deselectAllCells];
[self.soundCardChoice selectCellAtRow:1 column:0];
long lVal = 0;
NSInteger mode;
mode = prefs_parseLongValue(PREF_DOMAIN_VIDEO, PREF_COLOR_MODE, &lVal, /*base:*/10) ? getColorMode(lVal) : COLOR_MODE_DEFAULT;
[self.colorChoice selectItemAtIndex:mode];
mode = prefs_parseLongValue(PREF_DOMAIN_VIDEO, PREF_MONO_MODE, &lVal, /*base:*/10) ? getMonoMode(lVal) : MONO_MODE_DEFAULT;
[self.monochromeColorChoice selectItemAtIndex:mode];
bool bVal = prefs_parseBoolValue(PREF_DOMAIN_VIDEO, PREF_SHOW_HALF_SCANLINES, &bVal) ? bVal : true;
[self.scanlinesChoice setState:bVal ? NSOnState : NSOffState];
[self.joystickChoice selectItemAtIndex:(NSInteger)joy_mode];
#ifdef KEYPAD_JOYSTICK
[self.joystickRecenter setState:joy_auto_recenter ? NSOnState : NSOffState];
[self.joystickStepLabel setIntegerValue:joy_step];
[self.joystickStepper setIntegerValue:joy_step];
#endif
[self.joystickClipToRadius setState:joy_clip_to_radius ? NSOnState : NSOffState];
}
- (void)dealloc
{
[[NSNotificationCenter defaultCenter] removeObserver:self];
[super dealloc];
}
- (IBAction)sliderDidMove:(id)sender
{
NSSlider *slider = (NSSlider *)sender;
double value = [slider doubleValue];
prefs_setFloatValue(PREF_DOMAIN_VM, (slider == self.cpuSlider) ? PREF_CPU_SCALE : PREF_CPU_SCALE_ALT, value*100);
prefs_sync(PREF_DOMAIN_VM);
prefs_save();
}
- (IBAction)peggedChoiceChanged:(id)sender
{
NSButton *maxButton = (NSButton *)sender;
if (maxButton == self.cpuMaxChoice)
{
double value = ([maxButton state] == NSOnState) ? CPU_SCALE_FASTEST : [self.cpuSlider doubleValue];
prefs_setFloatValue(PREF_DOMAIN_VM, PREF_CPU_SCALE, value*100);
}
else
{
double value = ([maxButton state] == NSOnState) ? CPU_SCALE_FASTEST : [self.altSlider doubleValue];
prefs_setFloatValue(PREF_DOMAIN_VM, PREF_CPU_SCALE_ALT, value*100);
}
prefs_sync(PREF_DOMAIN_VM);
prefs_save();
}
- (IBAction)colorChoiceChanged:(id)sender
{
NSInteger mode = [self.colorChoice indexOfSelectedItem];
mode = getColorMode(mode);
prefs_setLongValue(PREF_DOMAIN_VIDEO, PREF_COLOR_MODE, mode);
prefs_sync(PREF_DOMAIN_VIDEO);
prefs_save();
}
- (IBAction)monochromeColorChoiceChanged:(id)sender {
NSInteger mode = [self.monochromeColorChoice indexOfSelectedItem];
mode = getMonoMode(mode);
prefs_setLongValue(PREF_DOMAIN_VIDEO, PREF_MONO_MODE, mode);
prefs_sync(PREF_DOMAIN_VIDEO);
prefs_save();
}
- (IBAction)scanlinesChoiceChanged:(id)sender
{
NSControlStateValue state = [self.scanlinesChoice state];
prefs_setBoolValue(PREF_DOMAIN_VIDEO, PREF_SHOW_HALF_SCANLINES, state == NSControlStateValueOn);
prefs_sync(PREF_DOMAIN_VIDEO);
prefs_save();
}
- (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];
mode = getJoyMode(mode);
prefs_setLongValue(PREF_DOMAIN_JOYSTICK, PREF_JOYSTICK_MODE, mode);
prefs_sync(PREF_DOMAIN_JOYSTICK);
prefs_save();
}
- (IBAction)autoRecenterChoiceChanged:(id)sender
{
bool autoRecenter = ([self.joystickRecenter state] == NSOnState);
prefs_setBoolValue(PREF_DOMAIN_JOYSTICK, PREF_JOYSTICK_KPAD_AUTO_RECENTER, autoRecenter);
prefs_sync(PREF_DOMAIN_JOYSTICK);
prefs_save();
}
- (IBAction)clipToRadiusChoiceChanged:(id)sender
{
bool clipToRadius = ([self.joystickClipToRadius state] == NSOnState);
prefs_setBoolValue(PREF_DOMAIN_JOYSTICK, PREF_JOYSTICK_CLIP_TO_RADIUS, clipToRadius);
prefs_sync(PREF_DOMAIN_JOYSTICK);
prefs_save();
}
- (IBAction)stepValueChanged:(id)sender
{
long joyStep = [self.joystickStepper intValue];
[self.joystickStepLabel setIntegerValue:joyStep];
prefs_setLongValue(PREF_DOMAIN_JOYSTICK, PREF_JOYSTICK_KPAD_STEP, joyStep);
prefs_sync(PREF_DOMAIN_JOYSTICK);
prefs_save();
}
#pragma mark -
#pragma Joystick calibration
- (void)drawJoystickCalibration:(NSNotification *)notification
{
if (![self.joystickCalibrationView isHidden])
{
[self.joystickCalibrationView setNeedsDisplay:YES];
[self.button0Pressed setHidden:!(run_args.joy_button0)];
[self.button1Pressed setHidden:!(run_args.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;
keys_handleInput(SCODE_L_ALT, /*is_pressed:*/leftAltEngaged, /*is_ascii:*/false);
break;
case ALT_RT:
rightAltEngaged = !rightAltEngaged;
keys_handleInput(SCODE_R_ALT, /*is_pressed:*/rightAltEngaged, /*is_ascii:*/false);
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:!(run_args.joy_button0)];
[self.button1Pressed setHidden:!(run_args.joy_button1)];
}
- (void)_handleKeyEvent:(NSEvent *)event pressed:(BOOL)pressed
{
unichar c = [[event charactersIgnoringModifiers] characterAtIndex:0];
int scode = (int)c;
switch (scode)
{
case NSUpArrowFunctionKey:
keys_handleInput(SCODE_U, pressed, /*is_ascii:*/false);
break;
case NSDownArrowFunctionKey:
keys_handleInput(SCODE_D, pressed, /*is_ascii:*/false);
break;
case NSLeftArrowFunctionKey:
keys_handleInput(SCODE_L, pressed, /*is_ascii:*/false);
break;
case NSRightArrowFunctionKey:
keys_handleInput(SCODE_R, pressed, /*is_ascii:*/false);
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