From 69f520428d1f7345d28ed75debffa546cd94816c Mon Sep 17 00:00:00 2001 From: Thomas Harte Date: Mon, 2 Apr 2018 22:42:41 -0400 Subject: [PATCH] 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. --- Analyser/Static/Acorn/Target.hpp | 6 +- Analyser/Static/AmstradCPC/Target.hpp | 6 +- Analyser/Static/Atari/Target.hpp | 6 +- Analyser/Static/Commodore/Target.hpp | 6 +- Analyser/Static/MSX/StaticAnalyser.cpp | 9 +- Analyser/Static/MSX/Target.hpp | 26 ++ Analyser/Static/Oric/StaticAnalyser.cpp | 6 +- Analyser/Static/Oric/Target.hpp | 8 +- Analyser/Static/ZX8081/StaticAnalyser.cpp | 8 +- Analyser/Static/ZX8081/Target.hpp | 9 +- Machines/MSX/MSX.cpp | 6 +- Machines/Oric/Oric.cpp | 2 +- Machines/ZX8081/ZX8081.cpp | 6 +- .../Clock Signal.xcodeproj/project.pbxproj | 29 +- .../DocumentController.swift | 16 + .../Documents/MachineDocument.swift | 62 +-- .../Machine/StaticAnalyser/CSStaticAnalyser.h | 29 ++ .../StaticAnalyser/CSStaticAnalyser.mm | 121 ++++++ .../New Group/Base.lproj/MachinePicker.xib | 387 ++++++++++++++++++ .../New Group/MachinePicker.swift | 90 ++++ 20 files changed, 775 insertions(+), 63 deletions(-) create mode 100644 Analyser/Static/MSX/Target.hpp create mode 100644 OSBindings/Mac/Clock Signal/New Group/Base.lproj/MachinePicker.xib create mode 100644 OSBindings/Mac/Clock Signal/New Group/MachinePicker.swift diff --git a/Analyser/Static/Acorn/Target.hpp b/Analyser/Static/Acorn/Target.hpp index c2f9f22b4..e7e97d467 100644 --- a/Analyser/Static/Acorn/Target.hpp +++ b/Analyser/Static/Acorn/Target.hpp @@ -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 */ diff --git a/Analyser/Static/AmstradCPC/Target.hpp b/Analyser/Static/AmstradCPC/Target.hpp index 795106435..ae656399e 100644 --- a/Analyser/Static/AmstradCPC/Target.hpp +++ b/Analyser/Static/AmstradCPC/Target.hpp @@ -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 */ diff --git a/Analyser/Static/Atari/Target.hpp b/Analyser/Static/Atari/Target.hpp index 9f0119ada..d102368cc 100644 --- a/Analyser/Static/Atari/Target.hpp +++ b/Analyser/Static/Atari/Target.hpp @@ -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 */ diff --git a/Analyser/Static/Commodore/Target.hpp b/Analyser/Static/Commodore/Target.hpp index 35b4c3426..1dc54db88 100644 --- a/Analyser/Static/Commodore/Target.hpp +++ b/Analyser/Static/Commodore/Target.hpp @@ -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 */ diff --git a/Analyser/Static/MSX/StaticAnalyser.cpp b/Analyser/Static/MSX/StaticAnalyser.cpp index 26351bf2b..9b4e4377a 100644 --- a/Analyser/Static/MSX/StaticAnalyser.cpp +++ b/Analyser/Static/MSX/StaticAnalyser.cpp @@ -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 CartridgeTarget( output_segments.emplace_back(start_address, segment.data); } - std::unique_ptr target(new Analyser::Static::Target); + std::unique_ptr target(new Analyser::Static::MSX::Target); target->machine = Analyser::Machine::MSX; target->confidence = confidence; @@ -259,9 +261,9 @@ static std::vector> CartridgeTargetsFr return targets; } -void Analyser::Static::MSX::AddTargets(const Media &media, std::vector> &destination) { +void Analyser::Static::MSX::AddTargets(const Media &media, std::vector> &destination) { // Append targets for any cartridges that look correct. - std::vector> 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::vectormedia.disks = media.disks; + target->has_disk_drive = !media.disks.empty(); if(!target->media.empty()) { target->machine = Machine::MSX; diff --git a/Analyser/Static/MSX/Target.hpp b/Analyser/Static/MSX/Target.hpp new file mode 100644 index 000000000..6c6c2cea7 --- /dev/null +++ b/Analyser/Static/MSX/Target.hpp @@ -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 */ diff --git a/Analyser/Static/Oric/StaticAnalyser.cpp b/Analyser/Static/Oric/StaticAnalyser.cpp index 7f7391e96..e53aa6463 100644 --- a/Analyser/Static/Oric/StaticAnalyser.cpp +++ b/Analyser/Static/Oric/StaticAnalyser.cpp @@ -134,17 +134,17 @@ void Analyser::Static::Oric::AddTargets(const Media &media, std::vectorhas_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)); diff --git a/Analyser/Static/Oric/Target.hpp b/Analyser/Static/Oric/Target.hpp index f920d7e5a..4bd5bb16e 100644 --- a/Analyser/Static/Oric/Target.hpp +++ b/Analyser/Static/Oric/Target.hpp @@ -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 */ diff --git a/Analyser/Static/ZX8081/StaticAnalyser.cpp b/Analyser/Static/ZX8081/StaticAnalyser.cpp index 4ee957325..a405bf8bf 100644 --- a/Analyser/Static/ZX8081/StaticAnalyser.cpp +++ b/Analyser/Static/ZX8081/StaticAnalyser.cpp @@ -40,11 +40,11 @@ void Analyser::Static::ZX8081::AddTargets(const Media &media, std::vectorisZX81 = 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::vectormedia.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"; diff --git a/Analyser/Static/ZX8081/Target.hpp b/Analyser/Static/ZX8081/Target.hpp index 7fef01e08..5f40e0bdf 100644 --- a/Analyser/Static/ZX8081/Target.hpp +++ b/Analyser/Static/ZX8081/Target.hpp @@ -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 */ diff --git a/Machines/MSX/MSX.cpp b/Machines/MSX/MSX.cpp index 87fea0628..3502c8161 100644 --- a/Machines/MSX/MSX.cpp +++ b/Machines/MSX/MSX.cpp @@ -40,6 +40,8 @@ #include "../../Configurable/StandardOptions.hpp" #include "../../ClockReceiver/ForceInline.hpp" +#include "../../Analyser/Static/MSX/Target.hpp" + namespace MSX { std::vector> get_options() { @@ -183,8 +185,10 @@ class ConcreteMachine: } void configure_as_target(const Analyser::Static::Target *target) override { + auto *const msx_target = dynamic_cast(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)); diff --git a/Machines/Oric/Oric.cpp b/Machines/Oric/Oric.cpp index afd2dc1da..5215badf4 100644 --- a/Machines/Oric/Oric.cpp +++ b/Machines/Oric/Oric.cpp @@ -271,7 +271,7 @@ class ConcreteMachine: void configure_as_target(const Analyser::Static::Target *target) override final { auto *const oric_target = dynamic_cast(target); - if(oric_target->has_microdisc) { + if(oric_target->has_microdrive) { microdisc_is_enabled_ = true; microdisc_did_change_paging_flags(µdisc_); microdisc_.set_delegate(this); diff --git a/Machines/ZX8081/ZX8081.cpp b/Machines/ZX8081/ZX8081.cpp index ec30e8ebc..7d17bd357 100644 --- a/Machines/ZX8081/ZX8081.cpp +++ b/Machines/ZX8081/ZX8081.cpp @@ -285,7 +285,7 @@ template class ConcreteMachine: void configure_as_target(const Analyser::Static::Target *target) override final { auto *const zx8081_target = dynamic_cast(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 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(target_hint); // Instantiate the correct type of machine. - if(hint->isZX81) + if(hint->is_ZX81) return new ZX8081::ConcreteMachine(); else return new ZX8081::ConcreteMachine(); diff --git a/OSBindings/Mac/Clock Signal.xcodeproj/project.pbxproj b/OSBindings/Mac/Clock Signal.xcodeproj/project.pbxproj index 202c24e47..ef546f057 100644 --- a/OSBindings/Mac/Clock Signal.xcodeproj/project.pbxproj +++ b/OSBindings/Mac/Clock Signal.xcodeproj/project.pbxproj @@ -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 = ""; }; 4BA0F68C1EEA0E8400E9489E /* ZX8081.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = ZX8081.cpp; path = Data/ZX8081.cpp; sourceTree = ""; }; 4BA0F68D1EEA0E8400E9489E /* ZX8081.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; name = ZX8081.hpp; path = Data/ZX8081.hpp; sourceTree = ""; }; + 4BA141BC2072E8A400A31EC9 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = Base; path = Base.lproj/MachinePicker.xib; sourceTree = ""; }; + 4BA141BE2072E8AF00A31EC9 /* MachinePicker.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MachinePicker.swift; sourceTree = ""; }; + 4BA141C12073100800A31EC9 /* Target.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = Target.hpp; sourceTree = ""; }; 4BA61EAE1D91515900B3C876 /* NSData+StdVector.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "NSData+StdVector.h"; sourceTree = ""; }; 4BA61EAF1D91515900B3C876 /* NSData+StdVector.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = "NSData+StdVector.mm"; sourceTree = ""; }; 4BA9C3CF1D8164A9002DDB61 /* ConfigurationTarget.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = ConfigurationTarget.hpp; sourceTree = ""; }; @@ -2235,6 +2240,7 @@ 4B047075201ABC180047AB0D /* Cartridge.hpp */, 4B894510201967B4007DE474 /* StaticAnalyser.hpp */, 4B894511201967B4007DE474 /* Tape.hpp */, + 4BA141C12073100800A31EC9 /* Target.hpp */, ); path = MSX; sourceTree = ""; @@ -2259,6 +2265,16 @@ path = Implementation; sourceTree = ""; }; + 4BA141C02072E8B300A31EC9 /* MachinePicker */ = { + isa = PBXGroup; + children = ( + 4BA141BE2072E8AF00A31EC9 /* MachinePicker.swift */, + 4BA141BB2072E8A400A31EC9 /* MachinePicker.xib */, + ); + name = MachinePicker; + path = "New Group"; + sourceTree = ""; + }; 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 = ""; }; + 4BA141BB2072E8A400A31EC9 /* MachinePicker.xib */ = { + isa = PBXVariantGroup; + children = ( + 4BA141BC2072E8A400A31EC9 /* Base */, + ); + name = MachinePicker.xib; + sourceTree = ""; + }; 4BB73EAA1B587A5100552FC2 /* MainMenu.xib */ = { isa = PBXVariantGroup; children = ( diff --git a/OSBindings/Mac/Clock Signal/Document Controller/DocumentController.swift b/OSBindings/Mac/Clock Signal/Document Controller/DocumentController.swift index 01ec875bb..62e221294 100644 --- a/OSBindings/Mac/Clock Signal/Document Controller/DocumentController.swift +++ b/OSBindings/Mac/Clock Signal/Document Controller/DocumentController.swift @@ -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() + } } diff --git a/OSBindings/Mac/Clock Signal/Documents/MachineDocument.swift b/OSBindings/Mac/Clock Signal/Documents/MachineDocument.swift index f2e72b86a..defa25a86 100644 --- a/OSBindings/Mac/Clock Signal/Documents/MachineDocument.swift +++ b/OSBindings/Mac/Clock Signal/Documents/MachineDocument.swift @@ -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) { diff --git a/OSBindings/Mac/Clock Signal/Machine/StaticAnalyser/CSStaticAnalyser.h b/OSBindings/Mac/Clock Signal/Machine/StaticAnalyser/CSStaticAnalyser.h index 47457adeb..17082cff3 100644 --- a/OSBindings/Mac/Clock Signal/Machine/StaticAnalyser/CSStaticAnalyser.h +++ b/OSBindings/Mac/Clock Signal/Machine/StaticAnalyser/CSStaticAnalyser.h @@ -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; diff --git a/OSBindings/Mac/Clock Signal/Machine/StaticAnalyser/CSStaticAnalyser.mm b/OSBindings/Mac/Clock Signal/Machine/StaticAnalyser/CSStaticAnalyser.mm index b1849f8f1..de2b46097 100644 --- a/OSBindings/Mac/Clock Signal/Machine/StaticAnalyser/CSStaticAnalyser.mm +++ b/OSBindings/Mac/Clock Signal/Machine/StaticAnalyser/CSStaticAnalyser.mm @@ -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(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(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(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(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(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(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(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; diff --git a/OSBindings/Mac/Clock Signal/New Group/Base.lproj/MachinePicker.xib b/OSBindings/Mac/Clock Signal/New Group/Base.lproj/MachinePicker.xib new file mode 100644 index 000000000..b3841fa84 --- /dev/null +++ b/OSBindings/Mac/Clock Signal/New Group/Base.lproj/MachinePicker.xib @@ -0,0 +1,387 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/OSBindings/Mac/Clock Signal/New Group/MachinePicker.swift b/OSBindings/Mac/Clock Signal/New Group/MachinePicker.swift new file mode 100644 index 000000000..b133ea980 --- /dev/null +++ b/OSBindings/Mac/Clock Signal/New Group/MachinePicker.swift @@ -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() + } + } +}