1
0
mirror of https://github.com/TomHarte/CLK.git synced 2025-03-25 21:34:05 +00:00

Makes a first, ugly attempt at a 'new machine' dialogue for the Mac.

Which has implied getting much more specific about MSX disk drive attachment, and has prompted an excuse to offer the ZX80 with the ZX81 ROM.
This commit is contained in:
Thomas Harte 2018-04-02 22:42:41 -04:00
parent 80c84ddd75
commit 69f520428d
20 changed files with 775 additions and 63 deletions
Analyser/Static
Machines
OSBindings/Mac
Clock Signal.xcodeproj
Clock Signal

@ -6,8 +6,8 @@
// Copyright © 2018 Thomas Harte. All rights reserved.
//
#ifndef Target_h
#define Target_h
#ifndef Analyser_Static_Acorn_Target_h
#define Analyser_Static_Acorn_Target_h
#include "../StaticAnalyser.hpp"
@ -25,4 +25,4 @@ struct Target: public ::Analyser::Static::Target {
}
}
#endif /* Target_h */
#endif /* Analyser_Static_Acorn_Target_h */

@ -6,8 +6,8 @@
// Copyright © 2018 Thomas Harte. All rights reserved.
//
#ifndef Target_h
#define Target_h
#ifndef Analyser_Static_AmstradCPC_Target_h
#define Analyser_Static_AmstradCPC_Target_h
#include "../StaticAnalyser.hpp"
@ -30,4 +30,4 @@ struct Target: public ::Analyser::Static::Target {
}
#endif /* Target_h */
#endif /* Analyser_Static_AmstradCPC_Target_h */

@ -6,8 +6,8 @@
// Copyright © 2018 Thomas Harte. All rights reserved.
//
#ifndef Target_h
#define Target_h
#ifndef Analyser_Static_Atari_Target_h
#define Analyser_Static_Atari_Target_h
#include "../StaticAnalyser.hpp"
@ -40,4 +40,4 @@ struct Target: public ::Analyser::Static::Target {
}
}
#endif /* Target_h */
#endif /* Analyser_Static_Atari_Target_h */

@ -6,8 +6,8 @@
// Copyright © 2018 Thomas Harte. All rights reserved.
//
#ifndef Target_h
#define Target_h
#ifndef Analyser_Static_Commodore_Target_h
#define Analyser_Static_Commodore_Target_h
#include "../StaticAnalyser.hpp"
@ -39,4 +39,4 @@ struct Target: public ::Analyser::Static::Target {
}
}
#endif /* Target_h */
#endif /* Analyser_Static_Commodore_Target_h */

@ -10,6 +10,8 @@
#include "Cartridge.hpp"
#include "Tape.hpp"
#include "Target.hpp"
#include "../Disassembler/Z80.hpp"
#include "../Disassembler/AddressMapper.hpp"
@ -32,7 +34,7 @@ static std::unique_ptr<Analyser::Static::Target> CartridgeTarget(
output_segments.emplace_back(start_address, segment.data);
}
std::unique_ptr<Analyser::Static::Target> target(new Analyser::Static::Target);
std::unique_ptr<Analyser::Static::MSX::Target> target(new Analyser::Static::MSX::Target);
target->machine = Analyser::Machine::MSX;
target->confidence = confidence;
@ -259,9 +261,9 @@ static std::vector<std::unique_ptr<Analyser::Static::Target>> CartridgeTargetsFr
return targets;
}
void Analyser::Static::MSX::AddTargets(const Media &media, std::vector<std::unique_ptr<Target>> &destination) {
void Analyser::Static::MSX::AddTargets(const Media &media, std::vector<std::unique_ptr<::Analyser::Static::Target>> &destination) {
// Append targets for any cartridges that look correct.
std::vector<std::unique_ptr<Target>> cartridge_targets = CartridgeTargetsFrom(media.cartridges);
auto cartridge_targets = CartridgeTargetsFrom(media.cartridges);
std::move(cartridge_targets.begin(), cartridge_targets.end(), std::back_inserter(destination));
// Consider building a target for disks and/or tapes.
@ -283,6 +285,7 @@ void Analyser::Static::MSX::AddTargets(const Media &media, std::vector<std::uniq
// Blindly accept disks for now.
target->media.disks = media.disks;
target->has_disk_drive = !media.disks.empty();
if(!target->media.empty()) {
target->machine = Machine::MSX;

@ -0,0 +1,26 @@
//
// Target.hpp
// Clock Signal
//
// Created by Thomas Harte on 02/04/2018.
// Copyright © 2018 Thomas Harte. All rights reserved.
//
#ifndef Analyser_Static_MSX_Target_h
#define Analyser_Static_MSX_Target_h
#include "../StaticAnalyser.hpp"
namespace Analyser {
namespace Static {
namespace MSX {
struct Target: public ::Analyser::Static::Target {
bool has_disk_drive = false;
};
}
}
}
#endif /* Analyser_Static_MSX_Target_h */

@ -134,17 +134,17 @@ void Analyser::Static::Oric::AddTargets(const Media &media, std::vector<std::uni
for(const auto &disk: media.disks) {
Storage::Encodings::MFM::Parser parser(true, disk);
if(IsMicrodisc(parser)) {
target->has_microdisc = true;
target->has_microdrive = true;
target->media.disks.push_back(disk);
}
}
} else {
target->has_microdisc = false;
target->has_microdrive = false;
}
// TODO: really this should add two targets if not all votes agree
target->use_atmos_rom = basic11_votes >= basic10_votes;
if(target->has_microdisc) target->use_atmos_rom = true;
if(target->has_microdrive) target->use_atmos_rom = true;
if(target->media.tapes.size() || target->media.disks.size() || target->media.cartridges.size())
destination.push_back(std::move(target));

@ -6,8 +6,8 @@
// Copyright © 2018 Thomas Harte. All rights reserved.
//
#ifndef Target_h
#define Target_h
#ifndef Analyser_Static_Oric_Target_h
#define Analyser_Static_Oric_Target_h
namespace Analyser {
namespace Static {
@ -15,11 +15,11 @@ namespace Oric {
struct Target: public ::Analyser::Static::Target {
bool use_atmos_rom = false;
bool has_microdisc = false;
bool has_microdrive = false;
};
}
}
}
#endif /* Target_h */
#endif /* Analyser_Static_Oric_Target_h */

@ -40,11 +40,11 @@ void Analyser::Static::ZX8081::AddTargets(const Media &media, std::vector<std::u
// Guess the machine type from the file only if it isn't already known.
switch(potential_platforms & (TargetPlatform::ZX80 | TargetPlatform::ZX81)) {
default:
target->isZX81 = files.front().isZX81;
target->is_ZX81 = files.front().isZX81;
break;
case TargetPlatform::ZX80: target->isZX81 = false; break;
case TargetPlatform::ZX81: target->isZX81 = true; break;
case TargetPlatform::ZX80: target->is_ZX81 = false; break;
case TargetPlatform::ZX81: target->is_ZX81 = true; break;
}
/*if(files.front().data.size() > 16384) {
@ -57,7 +57,7 @@ void Analyser::Static::ZX8081::AddTargets(const Media &media, std::vector<std::u
target->media.tapes = media.tapes;
// TODO: how to run software once loaded? Might require a BASIC detokeniser.
if(target->isZX81) {
if(target->is_ZX81) {
target->loading_command = "J\"\"\n";
} else {
target->loading_command = "W\n";

@ -6,8 +6,8 @@
// Copyright © 2018 Thomas Harte. All rights reserved.
//
#ifndef Target_h
#define Target_h
#ifndef Analyser_Static_ZX8081_Target_h
#define Analyser_Static_ZX8081_Target_h
#include "../StaticAnalyser.hpp"
@ -23,11 +23,12 @@ struct Target: public ::Analyser::Static::Target {
};
MemoryModel memory_model = MemoryModel::Unexpanded;
bool isZX81 = false;
bool is_ZX81 = false;
bool ZX80_uses_ZX81_ROM = false;
};
}
}
}
#endif /* Target_h */
#endif /* Analyser_Static_ZX8081_Target_h */

@ -40,6 +40,8 @@
#include "../../Configurable/StandardOptions.hpp"
#include "../../ClockReceiver/ForceInline.hpp"
#include "../../Analyser/Static/MSX/Target.hpp"
namespace MSX {
std::vector<std::unique_ptr<Configurable::Option>> get_options() {
@ -183,8 +185,10 @@ class ConcreteMachine:
}
void configure_as_target(const Analyser::Static::Target *target) override {
auto *const msx_target = dynamic_cast<const Analyser::Static::MSX::Target *>(target);
// Add a disk cartridge if any disks were supplied.
if(!target->media.disks.empty()) {
if(msx_target->has_disk_drive) {
map(2, 0, 0x4000, 0x2000);
unmap(2, 0x6000, 0x2000);
memory_slots_[2].set_handler(new DiskROM(memory_slots_[2].source));

@ -271,7 +271,7 @@ class ConcreteMachine:
void configure_as_target(const Analyser::Static::Target *target) override final {
auto *const oric_target = dynamic_cast<const Analyser::Static::Oric::Target *>(target);
if(oric_target->has_microdisc) {
if(oric_target->has_microdrive) {
microdisc_is_enabled_ = true;
microdisc_did_change_paging_flags(&microdisc_);
microdisc_.set_delegate(this);

@ -285,7 +285,7 @@ template<bool is_zx81> class ConcreteMachine:
void configure_as_target(const Analyser::Static::Target *target) override final {
auto *const zx8081_target = dynamic_cast<const Analyser::Static::ZX8081::Target *>(target);
is_zx81_ = zx8081_target->isZX81;
is_zx81_ = zx8081_target->is_ZX81;
if(is_zx81_) {
rom_ = zx81_rom_;
tape_trap_address_ = 0x37c;
@ -295,7 +295,7 @@ template<bool is_zx81> class ConcreteMachine:
automatic_tape_motor_start_address_ = 0x0340;
automatic_tape_motor_end_address_ = 0x03c3;
} else {
rom_ = zx80_rom_;
rom_ = zx8081_target->ZX80_uses_ZX81_ROM ? zx81_rom_ : zx80_rom_;
tape_trap_address_ = 0x220;
tape_return_address_ = 0x248;
vsync_start_ = HalfCycles(26);
@ -528,7 +528,7 @@ Machine *Machine::ZX8081(const Analyser::Static::Target *target_hint) {
const Analyser::Static::ZX8081::Target *const hint = dynamic_cast<const Analyser::Static::ZX8081::Target *>(target_hint);
// Instantiate the correct type of machine.
if(hint->isZX81)
if(hint->is_ZX81)
return new ZX8081::ConcreteMachine<true>();
else
return new ZX8081::ConcreteMachine<false>();

@ -291,6 +291,8 @@
4B9BE400203A0C0600FFAE60 /* MultiSpeaker.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4B9BE3FE203A0C0600FFAE60 /* MultiSpeaker.cpp */; };
4B9BE401203A0C0600FFAE60 /* MultiSpeaker.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4B9BE3FE203A0C0600FFAE60 /* MultiSpeaker.cpp */; };
4BA0F68E1EEA0E8400E9489E /* ZX8081.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4BA0F68C1EEA0E8400E9489E /* ZX8081.cpp */; };
4BA141BD2072E8A500A31EC9 /* MachinePicker.xib in Resources */ = {isa = PBXBuildFile; fileRef = 4BA141BB2072E8A400A31EC9 /* MachinePicker.xib */; };
4BA141BF2072E8AF00A31EC9 /* MachinePicker.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4BA141BE2072E8AF00A31EC9 /* MachinePicker.swift */; };
4BA61EB01D91515900B3C876 /* NSData+StdVector.mm in Sources */ = {isa = PBXBuildFile; fileRef = 4BA61EAF1D91515900B3C876 /* NSData+StdVector.mm */; };
4BAD13441FF709C700FD114A /* MSX.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4B0E61051FF34737002A9DBD /* MSX.cpp */; };
4BAE49582032881E004BE78E /* CSZX8081.mm in Sources */ = {isa = PBXBuildFile; fileRef = 4B14978E1EE4B4D200CE2596 /* CSZX8081.mm */; };
@ -975,6 +977,9 @@
4B9BE3FF203A0C0600FFAE60 /* MultiSpeaker.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = MultiSpeaker.hpp; sourceTree = "<group>"; };
4BA0F68C1EEA0E8400E9489E /* ZX8081.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = ZX8081.cpp; path = Data/ZX8081.cpp; sourceTree = "<group>"; };
4BA0F68D1EEA0E8400E9489E /* ZX8081.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; name = ZX8081.hpp; path = Data/ZX8081.hpp; sourceTree = "<group>"; };
4BA141BC2072E8A400A31EC9 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = Base; path = Base.lproj/MachinePicker.xib; sourceTree = "<group>"; };
4BA141BE2072E8AF00A31EC9 /* MachinePicker.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MachinePicker.swift; sourceTree = "<group>"; };
4BA141C12073100800A31EC9 /* Target.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = Target.hpp; sourceTree = "<group>"; };
4BA61EAE1D91515900B3C876 /* NSData+StdVector.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "NSData+StdVector.h"; sourceTree = "<group>"; };
4BA61EAF1D91515900B3C876 /* NSData+StdVector.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = "NSData+StdVector.mm"; sourceTree = "<group>"; };
4BA9C3CF1D8164A9002DDB61 /* ConfigurationTarget.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = ConfigurationTarget.hpp; sourceTree = "<group>"; };
@ -2235,6 +2240,7 @@
4B047075201ABC180047AB0D /* Cartridge.hpp */,
4B894510201967B4007DE474 /* StaticAnalyser.hpp */,
4B894511201967B4007DE474 /* Tape.hpp */,
4BA141C12073100800A31EC9 /* Target.hpp */,
);
path = MSX;
sourceTree = "<group>";
@ -2259,6 +2265,16 @@
path = Implementation;
sourceTree = "<group>";
};
4BA141C02072E8B300A31EC9 /* MachinePicker */ = {
isa = PBXGroup;
children = (
4BA141BE2072E8AF00A31EC9 /* MachinePicker.swift */,
4BA141BB2072E8A400A31EC9 /* MachinePicker.xib */,
);
name = MachinePicker;
path = "New Group";
sourceTree = "<group>";
};
4BAB62AA1D3272D200DF5BA0 /* Disk */ = {
isa = PBXGroup;
children = (
@ -2622,11 +2638,12 @@
4BB73EAD1B587A5100552FC2 /* Info.plist */,
4BB73EA11B587A5100552FC2 /* AppDelegate.swift */,
4BB73EA81B587A5100552FC2 /* Assets.xcassets */,
4BB73EAA1B587A5100552FC2 /* MainMenu.xib */,
4B2A538F1D117D36003C6002 /* Audio */,
4B643F3D1D77B88000D431D6 /* Document Controller */,
4B55CE551C3B7D360093A61B /* Documents */,
4B2A53921D117D36003C6002 /* Machine */,
4BA141C02072E8B300A31EC9 /* MachinePicker */,
4BB73EAA1B587A5100552FC2 /* MainMenu.xib */,
4BE5F85A1C3E1C2500C43F01 /* Resources */,
4BD5F1961D1352A000631CD1 /* Updater */,
4B55CE5A1C3B7D6F0093A61B /* Views */,
@ -3114,6 +3131,7 @@
4B2C45421E3C3896002A2389 /* cartridge.png in Resources */,
4BB73EA91B587A5100552FC2 /* Assets.xcassets in Resources */,
4B79E4451E3AF38600141F11 /* floppy35.png in Resources */,
4BA141BD2072E8A500A31EC9 /* MachinePicker.xib in Resources */,
4B1EDB451E39A0AC009D6819 /* chip.png in Resources */,
4B2A332D1DB86821002876E3 /* OricOptions.xib in Resources */,
4BD61664206B2AC800236112 /* QuickLoadOptions.xib in Resources */,
@ -3650,6 +3668,7 @@
4B71368E1F788112008B8ED9 /* Parser.cpp in Sources */,
4B12C0ED1FCFA98D005BFD93 /* Keyboard.cpp in Sources */,
4BA0F68E1EEA0E8400E9489E /* ZX8081.cpp in Sources */,
4BA141BF2072E8AF00A31EC9 /* MachinePicker.swift in Sources */,
4BD468F71D8DF41D0084958B /* 1770.cpp in Sources */,
4BD3A30B1EE755C800B5B501 /* Video.cpp in Sources */,
4BBF99141C8FBA6F0075DAFB /* TextureBuilder.cpp in Sources */,
@ -3829,6 +3848,14 @@
name = QuickLoadCompositeOptions.xib;
sourceTree = "<group>";
};
4BA141BB2072E8A400A31EC9 /* MachinePicker.xib */ = {
isa = PBXVariantGroup;
children = (
4BA141BC2072E8A400A31EC9 /* Base */,
);
name = MachinePicker.xib;
sourceTree = "<group>";
};
4BB73EAA1B587A5100552FC2 /* MainMenu.xib */ = {
isa = PBXVariantGroup;
children = (

@ -9,4 +9,20 @@
import Cocoa
class DocumentController: NSDocumentController {
override func newDocument(_ sender: Any?) {
// Show the new document window.
Bundle.main.loadNibNamed(NSNib.Name(rawValue: "MachinePicker"), owner: self, topLevelObjects: nil)
}
@IBOutlet var machinePicker: MachinePicker?
@IBAction func createMachine(_ sender: NSButton?) {
let machine = machinePicker!.selectedMachine()
let document: MachineDocument = try! openUntitledDocumentAndDisplay(true) as! MachineDocument
document.configureAs(machine)
sender?.window?.close()
}
@IBAction func cancelCreateMachine(_ sender: NSButton?) {
sender?.window?.close()
}
}

@ -48,30 +48,34 @@ class MachineDocument:
override func windowControllerDidLoadNib(_ aController: NSWindowController) {
super.windowControllerDidLoadNib(aController)
aController.window?.contentAspectRatio = self.aspectRatio()
setupMachineOutput()
}
// establish the output aspect ratio and audio
let displayAspectRatio = self.aspectRatio()
aController.window?.contentAspectRatio = displayAspectRatio
openGLView.perform(glContext: {
self.machine.setView(self.openGLView, aspectRatio: Float(displayAspectRatio.width / displayAspectRatio.height))
})
fileprivate func setupMachineOutput() {
if let machine = self.machine, let openGLView = self.openGLView {
// establish the output aspect ratio and audio
let aspectRatio = self.aspectRatio()
openGLView.perform(glContext: {
machine.setView(openGLView, aspectRatio: Float(aspectRatio.width / aspectRatio.height))
})
self.machine.delegate = self
self.bestEffortUpdater = CSBestEffortUpdater()
machine.delegate = self
self.bestEffortUpdater = CSBestEffortUpdater()
// callbacks from the OpenGL may come on a different thread, immediately following the .delegate set;
// hence the full setup of the best-effort updater prior to setting self as a delegate
self.openGLView.delegate = self
self.openGLView.responderDelegate = self
// callbacks from the OpenGL may come on a different thread, immediately following the .delegate set;
// hence the full setup of the best-effort updater prior to setting self as a delegate
openGLView.delegate = self
openGLView.responderDelegate = self
setupAudioQueueClockRate()
self.optionsPanel?.establishStoredOptions()
setupAudioQueueClockRate()
// bring OpenGL view-holding window on top of the options panel
self.openGLView.window!.makeKeyAndOrderFront(self)
// bring OpenGL view-holding window on top of the options panel
openGLView.window!.makeKeyAndOrderFront(self)
// start accepting best effort updates
self.bestEffortUpdater!.delegate = self
// start accepting best effort updates
self.bestEffortUpdater!.delegate = self
}
}
func machineSpeakerDidChangeInputClock(_ machine: CSMachine!) {
@ -95,9 +99,11 @@ class MachineDocument:
optionsPanel = nil
bestEffortLock.lock()
bestEffortUpdater!.delegate = nil
bestEffortUpdater!.flush()
bestEffortUpdater = nil
if let bestEffortUpdater = bestEffortUpdater {
bestEffortUpdater.delegate = nil
bestEffortUpdater.flush()
self.bestEffortUpdater = nil
}
bestEffortLock.unlock()
actionLock.lock()
@ -115,12 +121,14 @@ class MachineDocument:
func configureAs(_ analysis: CSStaticAnalyser) {
if let machine = CSMachine(analyser: analysis) {
self.machine = machine
}
setupMachineOutput()
if let optionsPanelNibName = analysis.optionsPanelNibName {
Bundle.main.loadNibNamed(NSNib.Name(rawValue: optionsPanelNibName), owner: self, topLevelObjects: nil)
self.optionsPanel.machine = self.machine
showOptions(self)
if let optionsPanelNibName = analysis.optionsPanelNibName {
Bundle.main.loadNibNamed(NSNib.Name(rawValue: optionsPanelNibName), owner: self, topLevelObjects: nil)
self.optionsPanel.machine = self.machine
self.optionsPanel?.establishStoredOptions()
showOptions(self)
}
}
}
@ -185,7 +193,7 @@ class MachineDocument:
// MARK: Input management
func windowDidResignKey(_ notification: Notification) {
self.machine.clearAllKeys()
// self.machine.clearAllKeys()
}
func keyDown(_ event: NSEvent) {

@ -10,10 +10,39 @@
@class CSMachine;
typedef NS_ENUM(NSInteger, CSMachineCPCModel) {
CSMachineCPCModel464,
CSMachineCPCModel664,
CSMachineCPCModel6128
};
typedef NS_ENUM(NSInteger, CSMachineOricModel) {
CSMachineOricModelOric1,
CSMachineOricModelOricAtmos
};
typedef NS_ENUM(NSInteger, CSMachineVic20Region) {
CSMachineVic20RegionAmerican,
CSMachineVic20RegionEuropean,
CSMachineVic20RegionDanish,
CSMachineVic20RegionSwedish,
CSMachineVic20RegionJapanese,
};
typedef int Kilobytes;
@interface CSStaticAnalyser : NSObject
- (instancetype)initWithFileAtURL:(NSURL *)url;
- (instancetype)initWithElectronDFS:(BOOL)dfs adfs:(BOOL)adfs;
- (instancetype)initWithAmstradCPCModel:(CSMachineCPCModel)model;
- (instancetype)initWithMSXHasDiskDrive:(BOOL)hasDiskDrive;
- (instancetype)initWithOricModel:(CSMachineOricModel)model hasMicrodrive:(BOOL)hasMicrodrive;
- (instancetype)initWithVic20Region:(CSMachineVic20Region)region memorySize:(Kilobytes)memorySize hasC1540:(BOOL)hasC1540;
- (instancetype)initWithZX80MemorySize:(Kilobytes)memorySize useZX81ROM:(BOOL)useZX81ROM;
- (instancetype)initWithZX81MemorySize:(Kilobytes)memorySize;
@property(nonatomic, readonly) NSString *optionsPanelNibName;
@property(nonatomic, readonly) NSString *displayName;

@ -13,6 +13,13 @@
#include "StaticAnalyser.hpp"
#include "../../../../../Analyser/Static/Acorn/Target.hpp"
#include "../../../../../Analyser/Static/AmstradCPC/Target.hpp"
#include "../../../../../Analyser/Static/Commodore/Target.hpp"
#include "../../../../../Analyser/Static/MSX/Target.hpp"
#include "../../../../../Analyser/Static/Oric/Target.hpp"
#include "../../../../../Analyser/Static/ZX8081/Target.hpp"
#import "Clock_Signal-Swift.h"
@implementation CSStaticAnalyser {
@ -32,6 +39,120 @@
return self;
}
- (instancetype)initWithElectronDFS:(BOOL)dfs adfs:(BOOL)adfs {
self = [super init];
if(self) {
using Target = Analyser::Static::Acorn::Target;
std::unique_ptr<Target> target(new Target);
target->machine = Analyser::Machine::Electron;
target->has_dfs = !!dfs;
target->has_adfs = !!adfs;
_targets.push_back(std::move(target));
}
return self;
}
- (instancetype)initWithAmstradCPCModel:(CSMachineCPCModel)model {
self = [super init];
if(self) {
using Target = Analyser::Static::AmstradCPC::Target;
std::unique_ptr<Target> target(new Target);
target->machine = Analyser::Machine::AmstradCPC;
switch(model) {
case CSMachineCPCModel464: target->model = Analyser::Static::AmstradCPC::Target::Model::CPC464; break;
case CSMachineCPCModel664: target->model = Analyser::Static::AmstradCPC::Target::Model::CPC664; break;
case CSMachineCPCModel6128: target->model = Analyser::Static::AmstradCPC::Target::Model::CPC6128; break;
}
_targets.push_back(std::move(target));
}
return self;
}
- (instancetype)initWithMSXHasDiskDrive:(BOOL)hasDiskDrive {
self = [super init];
if(self) {
using Target = Analyser::Static::MSX::Target;
std::unique_ptr<Target> target(new Target);
target->machine = Analyser::Machine::MSX;
target->has_disk_drive = !!hasDiskDrive;
_targets.push_back(std::move(target));
}
return self;
}
- (instancetype)initWithOricModel:(CSMachineOricModel)model hasMicrodrive:(BOOL)hasMicrodrive {
self = [super init];
if(self) {
using Target = Analyser::Static::Oric::Target;
std::unique_ptr<Target> target(new Target);
target->machine = Analyser::Machine::Oric;
target->use_atmos_rom = (model == CSMachineOricModelOricAtmos);
target->has_microdrive = !!hasMicrodrive;
_targets.push_back(std::move(target));
}
return self;
}
- (instancetype)initWithVic20Region:(CSMachineVic20Region)region memorySize:(Kilobytes)memorySize hasC1540:(BOOL)hasC1540 {
self = [super init];
if(self) {
using Target = Analyser::Static::Commodore::Target;
std::unique_ptr<Target> target(new Target);
target->machine = Analyser::Machine::Vic20;
switch(region) {
case CSMachineVic20RegionDanish: target->region = Target::Region::Danish; break;
case CSMachineVic20RegionSwedish: target->region = Target::Region::Swedish; break;
case CSMachineVic20RegionAmerican: target->region = Target::Region::American; break;
case CSMachineVic20RegionEuropean: target->region = Target::Region::European; break;
case CSMachineVic20RegionJapanese: target->region = Target::Region::Japanese; break;
}
switch(memorySize) {
default: target->memory_model = Target::MemoryModel::Unexpanded; break;
case 8: target->memory_model = Target::MemoryModel::EightKB; break;
case 32: target->memory_model = Target::MemoryModel::ThirtyTwoKB; break;
}
target->has_c1540 = !!hasC1540;
_targets.push_back(std::move(target));
}
return self;
}
static Analyser::Static::ZX8081::Target::MemoryModel ZX8081MemoryModelFromSize(Kilobytes size) {
using MemoryModel = Analyser::Static::ZX8081::Target::MemoryModel;
switch(size) {
default: return MemoryModel::Unexpanded;
case 16: return MemoryModel::SixteenKB;
case 64: return MemoryModel::SixtyFourKB;
}
}
- (instancetype)initWithZX80MemorySize:(Kilobytes)memorySize useZX81ROM:(BOOL)useZX81ROM {
self = [super init];
if(self) {
using Target = Analyser::Static::ZX8081::Target;
std::unique_ptr<Target> target(new Target);
target->machine = Analyser::Machine::ZX8081;
target->is_ZX81 = false;
target->ZX80_uses_ZX81_ROM = !!useZX81ROM;
target->memory_model = ZX8081MemoryModelFromSize(memorySize);
_targets.push_back(std::move(target));
}
return self;
}
- (instancetype)initWithZX81MemorySize:(Kilobytes)memorySize {
self = [super init];
if(self) {
using Target = Analyser::Static::ZX8081::Target;
std::unique_ptr<Target> target(new Target);
target->machine = Analyser::Machine::ZX8081;
target->is_ZX81 = true;
target->memory_model = ZX8081MemoryModelFromSize(memorySize);
_targets.push_back(std::move(target));
}
return self;
}
- (NSString *)optionsPanelNibName {
switch(_targets.front()->machine) {
case Analyser::Machine::AmstradCPC: return nil;

@ -0,0 +1,387 @@
<?xml version="1.0" encoding="UTF-8"?>
<document type="com.apple.InterfaceBuilder3.Cocoa.XIB" version="3.0" toolsVersion="14109" targetRuntime="MacOSX.Cocoa" propertyAccessControl="none" useAutolayout="YES" customObjectInstantitationMethod="direct">
<dependencies>
<deployment identifier="macosx"/>
<plugIn identifier="com.apple.InterfaceBuilder.CocoaPlugin" version="14109"/>
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
</dependencies>
<objects>
<customObject id="-2" userLabel="File's Owner" customClass="DocumentController" customModule="Clock_Signal" customModuleProvider="target">
<connections>
<outlet property="machinePicker" destination="192-Eb-Rpg" id="7p2-GL-AVt"/>
</connections>
</customObject>
<customObject id="-1" userLabel="First Responder" customClass="FirstResponder"/>
<customObject id="-3" userLabel="Application" customClass="NSObject"/>
<window title="Window" allowsToolTipsWhenApplicationIsInactive="NO" autorecalculatesKeyViewLoop="NO" oneShot="NO" releasedWhenClosed="NO" animationBehavior="default" id="QvC-M9-y7g">
<windowStyleMask key="styleMask" titled="YES" closable="YES" miniaturizable="YES" resizable="YES"/>
<windowPositionMask key="initialPositionMask" leftStrut="YES" rightStrut="YES" topStrut="YES" bottomStrut="YES"/>
<rect key="contentRect" x="196" y="240" width="562" height="203"/>
<rect key="screenRect" x="0.0" y="0.0" width="1366" height="768"/>
<view key="contentView" wantsLayer="YES" id="EiT-Mj-1SZ">
<rect key="frame" x="0.0" y="0.0" width="562" height="203"/>
<autoresizingMask key="autoresizingMask"/>
<subviews>
<tabView translatesAutoresizingMaskIntoConstraints="NO" id="VUb-QG-x7c">
<rect key="frame" x="13" y="51" width="536" height="138"/>
<font key="font" metaFont="system"/>
<tabViewItems>
<tabViewItem label="Acorn Electron" identifier="electron" id="muc-z9-Vqc">
<view key="view" id="SRc-2D-95G">
<rect key="frame" x="10" y="33" width="516" height="92"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<subviews>
<button verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="JqM-IK-FMP">
<rect key="frame" x="15" y="73" width="164" height="18"/>
<buttonCell key="cell" type="check" title="With Disk Filing System" bezelStyle="regularSquare" imagePosition="left" state="on" inset="2" id="tpW-5C-xKp">
<behavior key="behavior" changeContents="YES" doesNotDimImage="YES" lightByContents="YES"/>
<font key="font" metaFont="system"/>
</buttonCell>
</button>
<button verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="945-wU-JOH">
<rect key="frame" x="15" y="53" width="228" height="18"/>
<buttonCell key="cell" type="check" title="With Advanced Disk Filing System" bezelStyle="regularSquare" imagePosition="left" state="on" inset="2" id="S0c-Jg-7Pu">
<behavior key="behavior" changeContents="YES" doesNotDimImage="YES" lightByContents="YES"/>
<font key="font" metaFont="system"/>
</buttonCell>
</button>
</subviews>
<constraints>
<constraint firstItem="945-wU-JOH" firstAttribute="leading" secondItem="SRc-2D-95G" secondAttribute="leading" constant="17" id="1iM-70-oZq"/>
<constraint firstAttribute="bottom" relation="greaterThanOrEqual" secondItem="945-wU-JOH" secondAttribute="bottom" constant="17" id="7ZL-rR-aaz"/>
<constraint firstItem="JqM-IK-FMP" firstAttribute="leading" secondItem="SRc-2D-95G" secondAttribute="leading" constant="17" id="NfY-dE-aJw"/>
<constraint firstAttribute="trailing" relation="greaterThanOrEqual" secondItem="945-wU-JOH" secondAttribute="trailing" constant="20" id="dmY-PV-ap4"/>
<constraint firstItem="JqM-IK-FMP" firstAttribute="top" secondItem="SRc-2D-95G" secondAttribute="top" constant="3" id="ggl-QH-mV4"/>
<constraint firstAttribute="trailing" relation="greaterThanOrEqual" secondItem="JqM-IK-FMP" secondAttribute="trailing" constant="20" id="mvO-UZ-BtT"/>
<constraint firstItem="945-wU-JOH" firstAttribute="top" secondItem="JqM-IK-FMP" secondAttribute="bottom" constant="6" id="pes-xi-zkv"/>
</constraints>
</view>
</tabViewItem>
<tabViewItem label="Amstrad CPC" identifier="cpc" id="JmB-OF-xcM">
<view key="view" id="5zS-Nj-Ynx">
<rect key="frame" x="10" y="33" width="516" height="92"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<subviews>
<popUpButton verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="00d-sg-Krh">
<rect key="frame" x="54" y="65" width="94" height="26"/>
<popUpButtonCell key="cell" type="push" title="CPC6128" bezelStyle="rounded" alignment="left" lineBreakMode="truncatingTail" state="on" borderStyle="borderAndBezel" tag="6128" imageScaling="proportionallyDown" inset="2" selectedItem="klh-ZE-Agp" id="hVJ-h6-iea">
<behavior key="behavior" lightByBackground="YES" lightByGray="YES"/>
<font key="font" metaFont="menu"/>
<menu key="menu" id="r3D-C2-Ruq">
<items>
<menuItem title="CPC464" tag="464" id="5kZ-XF-RFl"/>
<menuItem title="CPC664" tag="664" id="Sct-ZX-Qp1"/>
<menuItem title="CPC6128" state="on" tag="6128" id="klh-ZE-Agp"/>
</items>
</menu>
</popUpButtonCell>
</popUpButton>
<textField horizontalHuggingPriority="251" verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="q9q-sl-J0q">
<rect key="frame" x="8" y="70" width="42" height="17"/>
<textFieldCell key="cell" scrollable="YES" lineBreakMode="clipping" sendsActionOnEndEditing="YES" title="Model" id="Cw3-q5-1bC">
<font key="font" metaFont="system"/>
<color key="textColor" name="labelColor" catalog="System" colorSpace="catalog"/>
<color key="backgroundColor" name="controlColor" catalog="System" colorSpace="catalog"/>
</textFieldCell>
</textField>
</subviews>
<constraints>
<constraint firstItem="00d-sg-Krh" firstAttribute="top" secondItem="5zS-Nj-Ynx" secondAttribute="top" constant="3" id="KHk-pr-avq"/>
<constraint firstItem="00d-sg-Krh" firstAttribute="leading" secondItem="q9q-sl-J0q" secondAttribute="trailing" constant="8" id="Sr4-Xg-lgt"/>
<constraint firstItem="q9q-sl-J0q" firstAttribute="leading" secondItem="5zS-Nj-Ynx" secondAttribute="leading" constant="10" id="Wof-5h-gfD"/>
<constraint firstAttribute="bottom" relation="greaterThanOrEqual" secondItem="00d-sg-Krh" secondAttribute="bottom" constant="17" id="t3s-ba-0dx"/>
<constraint firstItem="q9q-sl-J0q" firstAttribute="centerY" secondItem="00d-sg-Krh" secondAttribute="centerY" id="vA8-IA-Uwf"/>
<constraint firstAttribute="trailing" relation="greaterThanOrEqual" secondItem="00d-sg-Krh" secondAttribute="trailing" constant="17" id="y6y-bJ-ECA"/>
</constraints>
</view>
</tabViewItem>
<tabViewItem label="MSX" identifier="msx" id="6SR-DY-zdI">
<view key="view" id="mWD-An-tR7">
<rect key="frame" x="10" y="33" width="516" height="92"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<subviews>
<button verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="8xT-Pr-8SE">
<rect key="frame" x="15" y="73" width="124" height="18"/>
<buttonCell key="cell" type="check" title="Attach disk drive" bezelStyle="regularSquare" imagePosition="left" state="on" inset="2" id="CB3-nA-VTM">
<behavior key="behavior" changeContents="YES" doesNotDimImage="YES" lightByContents="YES"/>
<font key="font" metaFont="system"/>
</buttonCell>
</button>
</subviews>
<constraints>
<constraint firstItem="8xT-Pr-8SE" firstAttribute="top" secondItem="mWD-An-tR7" secondAttribute="top" constant="3" id="CPl-8F-YcG"/>
<constraint firstAttribute="trailing" relation="greaterThanOrEqual" secondItem="8xT-Pr-8SE" secondAttribute="trailing" constant="17" id="l8P-UW-8ig"/>
<constraint firstAttribute="bottom" relation="greaterThanOrEqual" secondItem="8xT-Pr-8SE" secondAttribute="bottom" constant="17" id="mga-YX-Bek"/>
<constraint firstItem="8xT-Pr-8SE" firstAttribute="leading" secondItem="mWD-An-tR7" secondAttribute="leading" constant="17" id="q8Q-kh-Opj"/>
</constraints>
</view>
</tabViewItem>
<tabViewItem label="Oric" identifier="oric" id="NSx-DC-p4M">
<view key="view" id="sOR-e0-8iZ">
<rect key="frame" x="10" y="33" width="516" height="92"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<subviews>
<button verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="mZw-PY-0Yv">
<rect key="frame" x="15" y="46" width="129" height="18"/>
<buttonCell key="cell" type="check" title="Attach Microdrive" bezelStyle="regularSquare" imagePosition="left" state="on" inset="2" id="Wl2-KO-smb">
<behavior key="behavior" changeContents="YES" doesNotDimImage="YES" lightByContents="YES"/>
<font key="font" metaFont="system"/>
</buttonCell>
</button>
<textField horizontalHuggingPriority="251" verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="0ct-tf-uRH">
<rect key="frame" x="17" y="72" width="42" height="17"/>
<textFieldCell key="cell" scrollable="YES" lineBreakMode="clipping" sendsActionOnEndEditing="YES" title="Model" id="Xm1-7x-YVl">
<font key="font" metaFont="system"/>
<color key="textColor" name="labelColor" catalog="System" colorSpace="catalog"/>
<color key="backgroundColor" name="controlColor" catalog="System" colorSpace="catalog"/>
</textFieldCell>
</textField>
<popUpButton verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="ENP-hI-BVZ">
<rect key="frame" x="63" y="67" width="105" height="26"/>
<popUpButtonCell key="cell" type="push" title="Oric-1" bezelStyle="rounded" alignment="left" lineBreakMode="truncatingTail" state="on" borderStyle="borderAndBezel" tag="1" imageScaling="proportionallyDown" inset="2" selectedItem="jGN-1a-biF" id="Jll-EJ-cMr">
<behavior key="behavior" lightByBackground="YES" lightByGray="YES"/>
<font key="font" metaFont="menu"/>
<menu key="menu" id="E9d-fH-Eak">
<items>
<menuItem title="Oric-1" state="on" tag="1" id="jGN-1a-biF"/>
<menuItem title="Oric Atmos" tag="2" id="p5O-Jq-Tft"/>
</items>
</menu>
</popUpButtonCell>
</popUpButton>
</subviews>
<constraints>
<constraint firstAttribute="bottom" relation="greaterThanOrEqual" secondItem="mZw-PY-0Yv" secondAttribute="bottom" constant="17" id="74q-Nf-cCV"/>
<constraint firstItem="ENP-hI-BVZ" firstAttribute="top" secondItem="sOR-e0-8iZ" secondAttribute="top" constant="1" id="Bgq-8R-8I4"/>
<constraint firstItem="mZw-PY-0Yv" firstAttribute="top" secondItem="ENP-hI-BVZ" secondAttribute="bottom" constant="8" id="Mjq-84-vdN"/>
<constraint firstAttribute="trailing" relation="greaterThanOrEqual" secondItem="ENP-hI-BVZ" secondAttribute="trailing" constant="17" id="Sr5-QZ-xU3"/>
<constraint firstItem="ENP-hI-BVZ" firstAttribute="leading" secondItem="0ct-tf-uRH" secondAttribute="trailing" constant="8" id="Wcg-1P-z6l"/>
<constraint firstItem="0ct-tf-uRH" firstAttribute="centerY" secondItem="ENP-hI-BVZ" secondAttribute="centerY" id="e8Q-nY-gIr"/>
<constraint firstItem="mZw-PY-0Yv" firstAttribute="leading" secondItem="sOR-e0-8iZ" secondAttribute="leading" constant="17" id="equ-PG-WAg"/>
<constraint firstAttribute="trailing" relation="greaterThanOrEqual" secondItem="mZw-PY-0Yv" secondAttribute="trailing" constant="17" id="erm-Kw-icY"/>
<constraint firstItem="0ct-tf-uRH" firstAttribute="leading" secondItem="sOR-e0-8iZ" secondAttribute="leading" constant="19" id="huH-9L-97Y"/>
</constraints>
</view>
</tabViewItem>
<tabViewItem label="Vic-20" identifier="vic20" id="cyO-PU-hSU">
<view key="view" id="fLI-XB-QCr">
<rect key="frame" x="10" y="33" width="516" height="94"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<subviews>
<popUpButton verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="ueK-gq-gaF">
<rect key="frame" x="67" y="67" width="144" height="26"/>
<popUpButtonCell key="cell" type="push" title="European (PAL)" bezelStyle="rounded" alignment="left" lineBreakMode="truncatingTail" state="on" borderStyle="borderAndBezel" imageScaling="proportionallyDown" inset="2" selectedItem="45i-0n-gau" id="yi7-eo-I0q">
<behavior key="behavior" lightByBackground="YES" lightByGray="YES"/>
<font key="font" metaFont="menu"/>
<menu key="menu" id="uCQ-9l-eBb">
<items>
<menuItem title="European (PAL)" state="on" id="45i-0n-gau"/>
<menuItem title="American (NTSC)" tag="1" id="jNT-iG-JUR"/>
<menuItem title="Danish (PAL)" tag="2" id="IpZ-Wv-lEe"/>
<menuItem title="Swedish (PAL)" tag="3" id="7x0-gL-mKG"/>
<menuItem title="Japanese (NTSC)" tag="4" id="kyq-LZ-O2M"/>
</items>
</menu>
</popUpButtonCell>
</popUpButton>
<popUpButton verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="2eV-Us-eEv">
<rect key="frame" x="102" y="36" width="114" height="26"/>
<popUpButtonCell key="cell" type="push" title="Unexpanded" bezelStyle="rounded" alignment="left" lineBreakMode="truncatingTail" state="on" borderStyle="borderAndBezel" imageScaling="proportionallyDown" inset="2" selectedItem="fOl-8Q-fsA" id="rH0-7T-pJE">
<behavior key="behavior" lightByBackground="YES" lightByGray="YES"/>
<font key="font" metaFont="menu"/>
<menu key="menu" id="e9J-Ie-PjH">
<items>
<menuItem title="Unexpanded" state="on" id="fOl-8Q-fsA"/>
<menuItem title="8 kb" tag="8" id="hEJ-yK-WZQ"/>
<menuItem title="32 kb" tag="32" id="8E5-8M-aTA"/>
</items>
</menu>
</popUpButtonCell>
</popUpButton>
<textField horizontalHuggingPriority="251" verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="MTh-9p-FqC">
<rect key="frame" x="17" y="72" width="46" height="17"/>
<textFieldCell key="cell" scrollable="YES" lineBreakMode="clipping" sendsActionOnEndEditing="YES" title="Region" id="F3g-Ya-ypU">
<font key="font" metaFont="system"/>
<color key="textColor" name="labelColor" catalog="System" colorSpace="catalog"/>
<color key="backgroundColor" name="controlColor" catalog="System" colorSpace="catalog"/>
</textFieldCell>
</textField>
<textField horizontalHuggingPriority="251" verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="gRS-DK-rIy">
<rect key="frame" x="15" y="41" width="83" height="17"/>
<textFieldCell key="cell" scrollable="YES" lineBreakMode="clipping" sendsActionOnEndEditing="YES" title="Memory Size" id="a4I-vG-yCp">
<font key="font" metaFont="system"/>
<color key="textColor" name="labelColor" catalog="System" colorSpace="catalog"/>
<color key="backgroundColor" name="controlColor" catalog="System" colorSpace="catalog"/>
</textFieldCell>
</textField>
<button verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="Lrf-gL-6EI">
<rect key="frame" x="15" y="15" width="173" height="18"/>
<buttonCell key="cell" type="check" title="Attach C-1540 disk drive" bezelStyle="regularSquare" imagePosition="left" state="on" inset="2" id="tsq-YD-xw8">
<behavior key="behavior" changeContents="YES" doesNotDimImage="YES" lightByContents="YES"/>
<font key="font" metaFont="system"/>
</buttonCell>
</button>
</subviews>
<constraints>
<constraint firstItem="Lrf-gL-6EI" firstAttribute="leading" secondItem="fLI-XB-QCr" secondAttribute="leading" constant="17" id="2Sb-f9-Qim"/>
<constraint firstItem="MTh-9p-FqC" firstAttribute="centerY" secondItem="ueK-gq-gaF" secondAttribute="centerY" id="8KD-Bm-KRA"/>
<constraint firstItem="ueK-gq-gaF" firstAttribute="leading" secondItem="MTh-9p-FqC" secondAttribute="trailing" constant="8" id="9m6-6j-8j2"/>
<constraint firstAttribute="trailing" relation="greaterThanOrEqual" secondItem="Lrf-gL-6EI" secondAttribute="trailing" constant="17" id="M08-mP-Plz"/>
<constraint firstItem="ueK-gq-gaF" firstAttribute="top" secondItem="fLI-XB-QCr" secondAttribute="top" constant="3" id="XN3-GK-BX9"/>
<constraint firstAttribute="trailing" relation="greaterThanOrEqual" secondItem="ueK-gq-gaF" secondAttribute="trailing" constant="17" id="YZ9-7N-ssA"/>
<constraint firstItem="MTh-9p-FqC" firstAttribute="leading" secondItem="fLI-XB-QCr" secondAttribute="leading" constant="19" id="bgZ-k9-IQC"/>
<constraint firstAttribute="trailing" relation="greaterThanOrEqual" secondItem="2eV-Us-eEv" secondAttribute="trailing" constant="17" id="eiB-vH-17d"/>
<constraint firstItem="2eV-Us-eEv" firstAttribute="top" secondItem="ueK-gq-gaF" secondAttribute="bottom" constant="10" id="flM-aa-vxB"/>
<constraint firstItem="2eV-Us-eEv" firstAttribute="leading" secondItem="gRS-DK-rIy" secondAttribute="trailing" constant="8" id="hQ9-uy-KHg"/>
<constraint firstItem="gRS-DK-rIy" firstAttribute="leading" secondItem="fLI-XB-QCr" secondAttribute="leading" constant="17" id="iyp-1K-rdC"/>
<constraint firstItem="gRS-DK-rIy" firstAttribute="centerY" secondItem="2eV-Us-eEv" secondAttribute="centerY" id="qWf-Nb-PfJ"/>
<constraint firstAttribute="bottom" relation="greaterThanOrEqual" secondItem="Lrf-gL-6EI" secondAttribute="bottom" constant="17" id="vNb-Sw-Mxw"/>
<constraint firstItem="Lrf-gL-6EI" firstAttribute="top" secondItem="2eV-Us-eEv" secondAttribute="bottom" constant="8" id="zBX-Qq-j5f"/>
</constraints>
</view>
</tabViewItem>
<tabViewItem label="ZX80" identifier="zx80" id="tMH-kF-GUz">
<view key="view" id="8hL-Vn-Hg0">
<rect key="frame" x="10" y="33" width="516" height="92"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<subviews>
<popUpButton verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="I1a-Eu-5UB">
<rect key="frame" x="102" y="65" width="114" height="26"/>
<popUpButtonCell key="cell" type="push" title="Unexpanded" bezelStyle="rounded" alignment="left" lineBreakMode="truncatingTail" state="on" borderStyle="borderAndBezel" imageScaling="proportionallyDown" inset="2" selectedItem="4Sa-jR-xOd" id="B8M-do-Yod">
<behavior key="behavior" lightByBackground="YES" lightByGray="YES"/>
<font key="font" metaFont="menu"/>
<menu key="menu" id="Of4-DY-mE5">
<items>
<menuItem title="Unexpanded" state="on" id="4Sa-jR-xOd"/>
<menuItem title="16 kb" tag="16" id="bWl-oP-jGn"/>
<menuItem title="64 kb" tag="64" id="WNJ-kT-TYn"/>
</items>
</menu>
</popUpButtonCell>
</popUpButton>
<textField horizontalHuggingPriority="251" verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="NCX-4e-lSu">
<rect key="frame" x="15" y="70" width="83" height="17"/>
<textFieldCell key="cell" scrollable="YES" lineBreakMode="clipping" sendsActionOnEndEditing="YES" title="Memory Size" id="e6x-TE-OC5">
<font key="font" metaFont="system"/>
<color key="textColor" name="labelColor" catalog="System" colorSpace="catalog"/>
<color key="backgroundColor" name="controlColor" catalog="System" colorSpace="catalog"/>
</textFieldCell>
</textField>
<button verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="ReP-bV-Thu">
<rect key="frame" x="15" y="46" width="114" height="18"/>
<buttonCell key="cell" type="check" title="Use ZX81 ROM" bezelStyle="regularSquare" imagePosition="left" state="on" inset="2" id="VQH-nv-Pfm">
<behavior key="behavior" changeContents="YES" doesNotDimImage="YES" lightByContents="YES"/>
<font key="font" metaFont="system"/>
</buttonCell>
</button>
</subviews>
<constraints>
<constraint firstAttribute="trailing" relation="greaterThanOrEqual" secondItem="I1a-Eu-5UB" secondAttribute="trailing" constant="17" id="0eZ-Nf-Vli"/>
<constraint firstItem="NCX-4e-lSu" firstAttribute="centerY" secondItem="I1a-Eu-5UB" secondAttribute="centerY" id="1ve-sc-QwI"/>
<constraint firstItem="I1a-Eu-5UB" firstAttribute="leading" secondItem="NCX-4e-lSu" secondAttribute="trailing" constant="8" id="Bu6-60-74x"/>
<constraint firstItem="NCX-4e-lSu" firstAttribute="leading" secondItem="8hL-Vn-Hg0" secondAttribute="leading" constant="17" id="W09-iG-ARI"/>
<constraint firstItem="I1a-Eu-5UB" firstAttribute="top" secondItem="8hL-Vn-Hg0" secondAttribute="top" constant="3" id="fkf-wO-Q8i"/>
<constraint firstAttribute="bottom" relation="greaterThanOrEqual" secondItem="ReP-bV-Thu" secondAttribute="bottom" constant="17" id="fmT-7E-hUT"/>
<constraint firstItem="ReP-bV-Thu" firstAttribute="top" secondItem="I1a-Eu-5UB" secondAttribute="bottom" constant="6" id="hYk-xC-63o"/>
<constraint firstItem="ReP-bV-Thu" firstAttribute="leading" secondItem="8hL-Vn-Hg0" secondAttribute="leading" constant="17" id="qen-KS-rWi"/>
<constraint firstAttribute="trailing" relation="greaterThanOrEqual" secondItem="ReP-bV-Thu" secondAttribute="trailing" constant="17" id="r7F-DT-oRc"/>
</constraints>
</view>
</tabViewItem>
<tabViewItem label="ZX81" identifier="zx81" id="Wnn-nQ-gZ6">
<view key="view" id="bmd-gL-gzT">
<rect key="frame" x="10" y="33" width="516" height="92"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<subviews>
<popUpButton verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="5aO-UX-HnX">
<rect key="frame" x="102" y="65" width="114" height="26"/>
<popUpButtonCell key="cell" type="push" title="Unexpanded" bezelStyle="rounded" alignment="left" lineBreakMode="truncatingTail" state="on" borderStyle="borderAndBezel" imageScaling="proportionallyDown" inset="2" selectedItem="7QC-Ij-hES" id="d3W-Gl-3Mf">
<behavior key="behavior" lightByBackground="YES" lightByGray="YES"/>
<font key="font" metaFont="menu"/>
<menu key="menu" id="mua-Lp-9wl">
<items>
<menuItem title="Unexpanded" state="on" id="7QC-Ij-hES"/>
<menuItem title="16 kb" tag="16" id="1HK-zJ-udx"/>
<menuItem title="64 kb" tag="64" id="PEx-W6-eGK"/>
</items>
</menu>
</popUpButtonCell>
</popUpButton>
<textField horizontalHuggingPriority="251" verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="8tU-73-XEE">
<rect key="frame" x="15" y="70" width="83" height="17"/>
<textFieldCell key="cell" scrollable="YES" lineBreakMode="clipping" sendsActionOnEndEditing="YES" title="Memory Size" id="z4b-oR-Yl2">
<font key="font" metaFont="system"/>
<color key="textColor" name="labelColor" catalog="System" colorSpace="catalog"/>
<color key="backgroundColor" name="controlColor" catalog="System" colorSpace="catalog"/>
</textFieldCell>
</textField>
</subviews>
<constraints>
<constraint firstItem="8tU-73-XEE" firstAttribute="centerY" secondItem="5aO-UX-HnX" secondAttribute="centerY" id="1Jm-YL-OKU"/>
<constraint firstAttribute="trailing" relation="greaterThanOrEqual" secondItem="5aO-UX-HnX" secondAttribute="trailing" constant="17" id="ALj-0x-bFb"/>
<constraint firstAttribute="bottom" relation="greaterThanOrEqual" secondItem="5aO-UX-HnX" secondAttribute="bottom" constant="17" id="LJ2-W9-fOf"/>
<constraint firstItem="8tU-73-XEE" firstAttribute="leading" secondItem="bmd-gL-gzT" secondAttribute="leading" constant="17" id="M6Y-jN-LAf"/>
<constraint firstItem="5aO-UX-HnX" firstAttribute="top" secondItem="bmd-gL-gzT" secondAttribute="top" constant="3" id="PPD-Jz-qCL"/>
<constraint firstItem="5aO-UX-HnX" firstAttribute="leading" secondItem="8tU-73-XEE" secondAttribute="trailing" constant="8" id="j1u-n4-2IK"/>
</constraints>
</view>
</tabViewItem>
</tabViewItems>
</tabView>
<button verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="hKn-1l-OSN">
<rect key="frame" x="412" y="13" width="136" height="32"/>
<buttonCell key="cell" type="push" title="Create Machine" bezelStyle="rounded" alignment="center" borderStyle="border" imageScaling="proportionallyDown" inset="2" id="MnM-xo-4Qa">
<behavior key="behavior" pushIn="YES" lightByBackground="YES" lightByGray="YES"/>
<font key="font" metaFont="system"/>
</buttonCell>
<connections>
<action selector="createMachine:" target="-2" id="2wo-Zv-H4f"/>
</connections>
</button>
<button verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="JQy-Cj-AOK">
<rect key="frame" x="331" y="13" width="82" height="32"/>
<buttonCell key="cell" type="push" title="Cancel" bezelStyle="rounded" alignment="center" borderStyle="border" imageScaling="proportionallyDown" inset="2" id="sub-rB-Req">
<behavior key="behavior" pushIn="YES" lightByBackground="YES" lightByGray="YES"/>
<font key="font" metaFont="system"/>
<string key="keyEquivalent" base64-UTF8="YES">
Gw
</string>
</buttonCell>
<connections>
<action selector="cancelCreateMachine:" target="-2" id="lf8-PM-c0m"/>
</connections>
</button>
</subviews>
<constraints>
<constraint firstAttribute="trailing" secondItem="VUb-QG-x7c" secondAttribute="trailing" constant="20" id="Bem-7v-AY6"/>
<constraint firstItem="JQy-Cj-AOK" firstAttribute="leading" relation="greaterThanOrEqual" secondItem="EiT-Mj-1SZ" secondAttribute="leading" constant="20" id="FMm-eV-4eu"/>
<constraint firstAttribute="bottom" secondItem="JQy-Cj-AOK" secondAttribute="bottom" constant="20" id="Kvh-1K-iI8"/>
<constraint firstItem="hKn-1l-OSN" firstAttribute="top" secondItem="VUb-QG-x7c" secondAttribute="bottom" constant="20" id="TqB-gT-0bf"/>
<constraint firstItem="hKn-1l-OSN" firstAttribute="leading" secondItem="JQy-Cj-AOK" secondAttribute="trailing" constant="11" id="f3Q-Om-rI0"/>
<constraint firstItem="VUb-QG-x7c" firstAttribute="leading" secondItem="EiT-Mj-1SZ" secondAttribute="leading" constant="20" id="j1W-rQ-Ypd"/>
<constraint firstAttribute="trailing" secondItem="hKn-1l-OSN" secondAttribute="trailing" constant="20" id="mJg-vd-ddP"/>
<constraint firstAttribute="bottom" secondItem="hKn-1l-OSN" secondAttribute="bottom" constant="20" id="rG2-Ea-klR"/>
<constraint firstItem="VUb-QG-x7c" firstAttribute="top" secondItem="EiT-Mj-1SZ" secondAttribute="top" constant="20" id="zT3-Ea-QQJ"/>
</constraints>
</view>
<point key="canvasLocation" x="34" y="127.5"/>
</window>
<customObject id="192-Eb-Rpg" customClass="MachinePicker" customModule="Clock_Signal" customModuleProvider="target">
<connections>
<outlet property="cpcModelTypeButton" destination="00d-sg-Krh" id="VyV-b1-A6x"/>
<outlet property="electronADFSButton" destination="945-wU-JOH" id="Fjm-W8-kvh"/>
<outlet property="electronDFSButton" destination="JqM-IK-FMP" id="C80-1k-TdQ"/>
<outlet property="machineSelector" destination="VUb-QG-x7c" id="crR-hB-jGd"/>
<outlet property="msxHasDiskDriveButton" destination="8xT-Pr-8SE" id="zGH-GA-9QF"/>
<outlet property="oricHasMicrodriveButton" destination="mZw-PY-0Yv" id="EuA-uL-PNR"/>
<outlet property="oricModelTypeButton" destination="ENP-hI-BVZ" id="n9i-Ym-miE"/>
<outlet property="vic20HasC1540Button" destination="Lrf-gL-6EI" id="21g-dJ-mOo"/>
<outlet property="vic20MemorySizeButton" destination="2eV-Us-eEv" id="5j4-jw-89d"/>
<outlet property="vic20RegionButton" destination="ueK-gq-gaF" id="qMq-uP-y4r"/>
<outlet property="zx80MemorySizeButton" destination="I1a-Eu-5UB" id="1QF-k5-aMM"/>
<outlet property="zx80UsesZX81ROMButton" destination="ReP-bV-Thu" id="Oe9-gC-jXp"/>
<outlet property="zx81MemorySizeButton" destination="5aO-UX-HnX" id="QHV-97-d19"/>
</connections>
</customObject>
</objects>
</document>

@ -0,0 +1,90 @@
//
// MachinePicker.swift
// Clock Signal
//
// Created by Thomas Harte on 02/04/2018.
// Copyright © 2018 Thomas Harte. All rights reserved.
//
import Cocoa
class MachinePicker: NSObject {
@IBOutlet var machineSelector: NSTabView?
// MARK: - Electron properties
@IBOutlet var electronDFSButton: NSButton?
@IBOutlet var electronADFSButton: NSButton?
// MARK: - CPC properties
@IBOutlet var cpcModelTypeButton: NSPopUpButton?
// MARK: - MSX properties
@IBOutlet var msxHasDiskDriveButton: NSButton?
// MARK: - Oric properties
@IBOutlet var oricModelTypeButton: NSPopUpButton?
@IBOutlet var oricHasMicrodriveButton: NSButton?
// MARK: - Vic-20 properties
@IBOutlet var vic20RegionButton: NSPopUpButton?
@IBOutlet var vic20MemorySizeButton: NSPopUpButton?
@IBOutlet var vic20HasC1540Button: NSButton?
// MARK: - ZX80 properties
@IBOutlet var zx80MemorySizeButton: NSPopUpButton?
@IBOutlet var zx80UsesZX81ROMButton: NSButton?
// MARK: - ZX81 properties
@IBOutlet var zx81MemorySizeButton: NSPopUpButton?
// MARK: - Machine builder
func selectedMachine() -> CSStaticAnalyser {
switch machineSelector!.selectedTabViewItem!.identifier as! String {
case "electron":
return CSStaticAnalyser(electronDFS: electronDFSButton!.state == .on, adfs: electronADFSButton!.state == .on)!
case "cpc":
switch cpcModelTypeButton!.selectedItem!.tag {
case 464: return CSStaticAnalyser(amstradCPCModel: .model464)
case 664: return CSStaticAnalyser(amstradCPCModel: .model664)
case 6128: fallthrough
default: return CSStaticAnalyser(amstradCPCModel: .model6128)
}
case "msx":
return CSStaticAnalyser(msxHasDiskDrive: msxHasDiskDriveButton!.state == .on)
case "oric":
let hasMicrodrive = oricHasMicrodriveButton!.state == .on
switch oricModelTypeButton!.selectedItem!.tag {
case 1: return CSStaticAnalyser(oricModel: .oric1, hasMicrodrive: hasMicrodrive)
default: return CSStaticAnalyser(oricModel: .oricAtmos, hasMicrodrive: hasMicrodrive)
}
case "vic20":
let memorySize = Kilobytes(vic20MemorySizeButton!.selectedItem!.tag)
let hasC1540 = vic20HasC1540Button!.state == .on
switch vic20RegionButton!.selectedItem?.tag {
case 1:
return CSStaticAnalyser(vic20Region: .american, memorySize: memorySize, hasC1540: hasC1540)
case 2:
return CSStaticAnalyser(vic20Region: .danish, memorySize: memorySize, hasC1540: hasC1540)
case 3:
return CSStaticAnalyser(vic20Region: .swedish, memorySize: memorySize, hasC1540: hasC1540)
case 4:
return CSStaticAnalyser(vic20Region: .japanese, memorySize: memorySize, hasC1540: hasC1540)
case 0: fallthrough
default:
return CSStaticAnalyser(vic20Region: .european, memorySize: memorySize, hasC1540: hasC1540)
}
case "zx80":
return CSStaticAnalyser(zx80MemorySize: Kilobytes(zx80MemorySizeButton!.selectedItem!.tag), useZX81ROM: zx80UsesZX81ROMButton!.state == .on)
case "zx81":
return CSStaticAnalyser(zx81MemorySize: Kilobytes(zx81MemorySizeButton!.selectedItem!.tag))
default: return CSStaticAnalyser()
}
}
}