mirror of
https://github.com/TomHarte/CLK.git
synced 2024-11-19 08:31:11 +00:00
Merge pull request #939 from TomHarte/DragAndDropState
Accept insertion of state snapshots into existing windows
This commit is contained in:
commit
488c2aed51
@ -74,7 +74,7 @@
|
|||||||
</CommandLineArgument>
|
</CommandLineArgument>
|
||||||
<CommandLineArgument
|
<CommandLineArgument
|
||||||
argument = "--new=amstradcpc"
|
argument = "--new=amstradcpc"
|
||||||
isEnabled = "NO">
|
isEnabled = "YES">
|
||||||
</CommandLineArgument>
|
</CommandLineArgument>
|
||||||
<CommandLineArgument
|
<CommandLineArgument
|
||||||
argument = ""/Users/thomasharte/Library/Mobile Documents/com~apple~CloudDocs/Desktop/Soft/ColecoVision/Galaxian (1983)(Atari).col""
|
argument = ""/Users/thomasharte/Library/Mobile Documents/com~apple~CloudDocs/Desktop/Soft/ColecoVision/Galaxian (1983)(Atari).col""
|
||||||
@ -106,11 +106,11 @@
|
|||||||
</CommandLineArgument>
|
</CommandLineArgument>
|
||||||
<CommandLineArgument
|
<CommandLineArgument
|
||||||
argument = "--rompath=/Users/thomasharte/Projects/CLK/ROMImages"
|
argument = "--rompath=/Users/thomasharte/Projects/CLK/ROMImages"
|
||||||
isEnabled = "NO">
|
isEnabled = "YES">
|
||||||
</CommandLineArgument>
|
</CommandLineArgument>
|
||||||
<CommandLineArgument
|
<CommandLineArgument
|
||||||
argument = "--help"
|
argument = "--help"
|
||||||
isEnabled = "YES">
|
isEnabled = "NO">
|
||||||
</CommandLineArgument>
|
</CommandLineArgument>
|
||||||
<CommandLineArgument
|
<CommandLineArgument
|
||||||
argument = "--model=cpc6128"
|
argument = "--model=cpc6128"
|
||||||
|
@ -87,6 +87,14 @@ class MachineDocument:
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private func dismissPanels() {
|
||||||
|
activityPanel?.setIsVisible(false)
|
||||||
|
activityPanel = nil
|
||||||
|
|
||||||
|
optionsPanel?.setIsVisible(false)
|
||||||
|
optionsPanel = nil
|
||||||
|
}
|
||||||
|
|
||||||
override func close() {
|
override func close() {
|
||||||
// Close any dangling sheets.
|
// Close any dangling sheets.
|
||||||
//
|
//
|
||||||
@ -105,11 +113,7 @@ class MachineDocument:
|
|||||||
machine?.stop()
|
machine?.stop()
|
||||||
|
|
||||||
// Dismiss panels.
|
// Dismiss panels.
|
||||||
activityPanel?.setIsVisible(false)
|
dismissPanels()
|
||||||
activityPanel = nil
|
|
||||||
|
|
||||||
optionsPanel?.setIsVisible(false)
|
|
||||||
optionsPanel = nil
|
|
||||||
|
|
||||||
// End the update cycle.
|
// End the update cycle.
|
||||||
actionLock.lock()
|
actionLock.lock()
|
||||||
@ -137,19 +141,23 @@ class MachineDocument:
|
|||||||
func configureAs(_ analysis: CSStaticAnalyser) {
|
func configureAs(_ analysis: CSStaticAnalyser) {
|
||||||
self.machineDescription = analysis
|
self.machineDescription = analysis
|
||||||
|
|
||||||
|
actionLock.lock()
|
||||||
|
drawLock.lock()
|
||||||
|
|
||||||
let missingROMs = NSMutableArray()
|
let missingROMs = NSMutableArray()
|
||||||
if let machine = CSMachine(analyser: analysis, missingROMs: missingROMs) {
|
if let machine = CSMachine(analyser: analysis, missingROMs: missingROMs) {
|
||||||
self.machine = machine
|
self.machine = machine
|
||||||
setupActivityDisplay()
|
|
||||||
machine.setVolume(userDefaultsVolume())
|
machine.setVolume(userDefaultsVolume())
|
||||||
setupMachineOutput()
|
setupMachineOutput()
|
||||||
} else {
|
} else {
|
||||||
// Store the selected machine and list of missing ROMs, and
|
// Store the selected machine and list of missing ROMs, and
|
||||||
// show the missing ROMs dialogue.
|
// show the missing ROMs dialogue.
|
||||||
self.missingROMs = missingROMs.map({$0 as! CSMissingROM})
|
self.missingROMs = missingROMs.map({$0 as! CSMissingROM})
|
||||||
|
|
||||||
requestRoms()
|
requestRoms()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
actionLock.unlock()
|
||||||
|
drawLock.unlock()
|
||||||
}
|
}
|
||||||
|
|
||||||
enum InteractionMode {
|
enum InteractionMode {
|
||||||
@ -200,6 +208,9 @@ class MachineDocument:
|
|||||||
let aspectRatio = self.aspectRatio()
|
let aspectRatio = self.aspectRatio()
|
||||||
machine.setView(scanTargetView, aspectRatio: Float(aspectRatio.width / aspectRatio.height))
|
machine.setView(scanTargetView, aspectRatio: Float(aspectRatio.width / aspectRatio.height))
|
||||||
|
|
||||||
|
// Get rid of all existing accessory panels.
|
||||||
|
dismissPanels()
|
||||||
|
|
||||||
// Attach an options panel if one is available.
|
// Attach an options panel if one is available.
|
||||||
if let optionsPanelNibName = self.machineDescription?.optionsPanelNibName {
|
if let optionsPanelNibName = self.machineDescription?.optionsPanelNibName {
|
||||||
Bundle.main.loadNibNamed(optionsPanelNibName, owner: self, topLevelObjects: nil)
|
Bundle.main.loadNibNamed(optionsPanelNibName, owner: self, topLevelObjects: nil)
|
||||||
@ -208,11 +219,10 @@ class MachineDocument:
|
|||||||
showOptions(self)
|
showOptions(self)
|
||||||
}
|
}
|
||||||
|
|
||||||
machine.delegate = self
|
// Create and populate an activity display if required.
|
||||||
|
setupActivityDisplay()
|
||||||
|
|
||||||
// Callbacks from the OpenGL may come on a different thread, immediately following the .delegate set;
|
machine.delegate = self
|
||||||
// hence the full setup of the best-effort updater prior to setting self as a delegate.
|
|
||||||
// scanTargetView.delegate = self
|
|
||||||
scanTargetView.responderDelegate = self
|
scanTargetView.responderDelegate = self
|
||||||
|
|
||||||
// If this machine has a mouse, enable mouse capture; also indicate whether usurption
|
// If this machine has a mouse, enable mouse capture; also indicate whether usurption
|
||||||
@ -252,7 +262,7 @@ class MachineDocument:
|
|||||||
let isStereo = self.machine.isStereo
|
let isStereo = self.machine.isStereo
|
||||||
if selectedSamplingRate > 0 {
|
if selectedSamplingRate > 0 {
|
||||||
// [Re]create the audio queue only if necessary.
|
// [Re]create the audio queue only if necessary.
|
||||||
if self.audioQueue == nil || self.audioQueue.samplingRate != selectedSamplingRate {
|
if self.audioQueue == nil || self.audioQueue.samplingRate != selectedSamplingRate || self.audioQueue != self.machine.audioQueue {
|
||||||
self.machine.audioQueue = nil
|
self.machine.audioQueue = nil
|
||||||
self.audioQueue = CSAudioQueue(samplingRate: Float64(selectedSamplingRate), isStereo:isStereo)
|
self.audioQueue = CSAudioQueue(samplingRate: Float64(selectedSamplingRate), isStereo:isStereo)
|
||||||
self.audioQueue.delegate = self
|
self.audioQueue.delegate = self
|
||||||
@ -280,8 +290,7 @@ class MachineDocument:
|
|||||||
|
|
||||||
/// Delegate message to receive drag and drop files.
|
/// Delegate message to receive drag and drop files.
|
||||||
final func scanTargetView(_ view: CSScanTargetView, didReceiveFileAt URL: URL) {
|
final func scanTargetView(_ view: CSScanTargetView, didReceiveFileAt URL: URL) {
|
||||||
let mediaSet = CSMediaSet(fileAt: URL)
|
insertFile(URL)
|
||||||
mediaSet.apply(to: self.machine)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Action for the insert menu command; displays an NSOpenPanel and then segues into the same process
|
/// Action for the insert menu command; displays an NSOpenPanel and then segues into the same process
|
||||||
@ -292,10 +301,27 @@ class MachineDocument:
|
|||||||
openPanel.beginSheetModal(for: self.windowControllers[0].window!) { (response) in
|
openPanel.beginSheetModal(for: self.windowControllers[0].window!) { (response) in
|
||||||
if response == .OK {
|
if response == .OK {
|
||||||
for url in openPanel.urls {
|
for url in openPanel.urls {
|
||||||
let mediaSet = CSMediaSet(fileAt: url)
|
self.insertFile(url)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private func insertFile(_ URL: URL) {
|
||||||
|
// Try to insert media.
|
||||||
|
let mediaSet = CSMediaSet(fileAt: URL)
|
||||||
|
if !mediaSet.empty {
|
||||||
mediaSet.apply(to: self.machine)
|
mediaSet.apply(to: self.machine)
|
||||||
|
return
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
// Failing that see whether a new machine is required.
|
||||||
|
// TODO.
|
||||||
|
if let newMachine = CSStaticAnalyser(fileAt: URL) {
|
||||||
|
machine?.stop()
|
||||||
|
self.interactionMode = .notStarted
|
||||||
|
self.scanTargetView.willChangeScanTargetOwner()
|
||||||
|
configureAs(newMachine)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -114,6 +114,8 @@ typedef int Kilobytes;
|
|||||||
- (instancetype)initWithFileAtURL:(NSURL *)url;
|
- (instancetype)initWithFileAtURL:(NSURL *)url;
|
||||||
- (void)applyToMachine:(CSMachine *)machine;
|
- (void)applyToMachine:(CSMachine *)machine;
|
||||||
|
|
||||||
|
@property(nonatomic, readonly) BOOL empty;
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
|
||||||
NS_ASSUME_NONNULL_END
|
NS_ASSUME_NONNULL_END
|
||||||
|
@ -309,4 +309,8 @@ static Analyser::Static::ZX8081::Target::MemoryModel ZX8081MemoryModelFromSize(K
|
|||||||
[machine applyMedia:_media];
|
[machine applyMedia:_media];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
- (BOOL)empty {
|
||||||
|
return _media.empty();
|
||||||
|
}
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
@ -22,4 +22,6 @@
|
|||||||
|
|
||||||
- (nonnull NSBitmapImageRep *)imageRepresentation;
|
- (nonnull NSBitmapImageRep *)imageRepresentation;
|
||||||
|
|
||||||
|
- (void)willChangeOwner;
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
@ -1143,6 +1143,10 @@ using BufferingScanTarget = Outputs::Display::BufferingScanTarget;
|
|||||||
return &_scanTarget;
|
return &_scanTarget;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
- (void)willChangeOwner {
|
||||||
|
self.scanTarget->will_change_owner();
|
||||||
|
}
|
||||||
|
|
||||||
- (NSBitmapImageRep *)imageRepresentation {
|
- (NSBitmapImageRep *)imageRepresentation {
|
||||||
// Create an NSBitmapRep as somewhere to copy pixel data to.
|
// Create an NSBitmapRep as somewhere to copy pixel data to.
|
||||||
NSBitmapImageRep *const result =
|
NSBitmapImageRep *const result =
|
||||||
|
@ -162,4 +162,10 @@
|
|||||||
*/
|
*/
|
||||||
@property(nonatomic, readonly, nonnull) CSScanTarget *scanTarget;
|
@property(nonatomic, readonly, nonnull) CSScanTarget *scanTarget;
|
||||||
|
|
||||||
|
/*!
|
||||||
|
Indicates that the enclosed scan target is about to be handed off to a new owner;
|
||||||
|
exactly identical to calling scanTarget.will_change_owner().
|
||||||
|
*/
|
||||||
|
- (void)willChangeScanTargetOwner;
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
@ -129,6 +129,10 @@ static CVReturn DisplayLinkCallback(__unused CVDisplayLinkRef displayLink, const
|
|||||||
return _scanTarget;
|
return _scanTarget;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
- (void)willChangeScanTargetOwner {
|
||||||
|
[_scanTarget willChangeOwner];
|
||||||
|
}
|
||||||
|
|
||||||
- (void)updateBacking {
|
- (void)updateBacking {
|
||||||
[_scanTarget updateFrameBuffer];
|
[_scanTarget updateFrameBuffer];
|
||||||
}
|
}
|
||||||
|
@ -470,13 +470,56 @@ class DynamicWindowTitler {
|
|||||||
update_window_title();
|
update_window_title();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void set_file_name(const std::string &name) {
|
||||||
|
file_name_ = name;
|
||||||
|
update_window_title();
|
||||||
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void update_window_title() {
|
void update_window_title() {
|
||||||
SDL_SetWindowTitle(window_, window_title().c_str());
|
SDL_SetWindowTitle(window_, window_title().c_str());
|
||||||
}
|
}
|
||||||
bool mouse_is_captured_ = false;
|
bool mouse_is_captured_ = false;
|
||||||
SDL_Window *window_ = nullptr;
|
SDL_Window *window_ = nullptr;
|
||||||
const std::string file_name_;
|
std::string file_name_;
|
||||||
|
};
|
||||||
|
|
||||||
|
/*!
|
||||||
|
Provides a wrapper for SDL_Joystick pointers that can keep track
|
||||||
|
of historic hat values.
|
||||||
|
*/
|
||||||
|
class SDLJoystick {
|
||||||
|
public:
|
||||||
|
SDLJoystick(SDL_Joystick *joystick) : joystick_(joystick) {
|
||||||
|
hat_values_.resize(SDL_JoystickNumHats(joystick));
|
||||||
|
}
|
||||||
|
|
||||||
|
~SDLJoystick() {
|
||||||
|
SDL_JoystickClose(joystick_);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// @returns The underlying SDL_Joystick.
|
||||||
|
SDL_Joystick *get() {
|
||||||
|
return joystick_;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// @returns A reference to the storage for the previous state of hat @c c.
|
||||||
|
Uint8 &last_hat_value(int c) {
|
||||||
|
return hat_values_[c];
|
||||||
|
}
|
||||||
|
|
||||||
|
/// @returns The logic OR of all stored hat states.
|
||||||
|
Uint8 hat_values() {
|
||||||
|
Uint8 value = 0;
|
||||||
|
for(const auto hat_value: hat_values_) {
|
||||||
|
value |= hat_value;
|
||||||
|
}
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
SDL_Joystick *joystick_;
|
||||||
|
std::vector<Uint8> hat_values_;
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
@ -723,7 +766,7 @@ int main(int argc, char *argv[]) {
|
|||||||
if(!rom.descriptive_name.empty()) {
|
if(!rom.descriptive_name.empty()) {
|
||||||
std::cerr << rom.descriptive_name << "; ";
|
std::cerr << rom.descriptive_name << "; ";
|
||||||
}
|
}
|
||||||
std::cerr << "accepted crc32s: ";
|
std::cerr << "usual crc32s: ";
|
||||||
bool is_first = true;
|
bool is_first = true;
|
||||||
for(const auto crc32: rom.crc32s) {
|
for(const auto crc32: rom.crc32s) {
|
||||||
if(!is_first) std::cerr << ", ";
|
if(!is_first) std::cerr << ", ";
|
||||||
@ -791,10 +834,6 @@ int main(int argc, char *argv[]) {
|
|||||||
SDL_StartTextInput();
|
SDL_StartTextInput();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Wire up the best-effort updater, its delegate, and the speaker delegate.
|
|
||||||
machine_runner.machine = machine.get();
|
|
||||||
machine_runner.machine_mutex = &machine_mutex;
|
|
||||||
|
|
||||||
// Ensure all media is inserted, if this machine accepts it.
|
// Ensure all media is inserted, if this machine accepts it.
|
||||||
{
|
{
|
||||||
auto media_target = machine->media_target();
|
auto media_target = machine->media_target();
|
||||||
@ -844,6 +883,15 @@ int main(int argc, char *argv[]) {
|
|||||||
|
|
||||||
// Setup output, assuming a CRT machine for now, and prepare a best-effort updater.
|
// Setup output, assuming a CRT machine for now, and prepare a best-effort updater.
|
||||||
Outputs::Display::OpenGL::ScanTarget scan_target(target_framebuffer);
|
Outputs::Display::OpenGL::ScanTarget scan_target(target_framebuffer);
|
||||||
|
std::unique_ptr<ActivityObserver> activity_observer;
|
||||||
|
bool uses_mouse;
|
||||||
|
std::vector<SDLJoystick> joysticks;
|
||||||
|
|
||||||
|
machine_runner.machine_mutex = &machine_mutex;
|
||||||
|
const auto setup_machine_input_output = [&scan_target, &machine, &speaker_delegate, &activity_observer, &joysticks, &uses_mouse, &machine_runner] {
|
||||||
|
// Wire up the best-effort updater, its delegate, and the speaker delegate.
|
||||||
|
machine_runner.machine = machine.get();
|
||||||
|
|
||||||
machine->scan_producer()->set_scan_target(&scan_target);
|
machine->scan_producer()->set_scan_target(&scan_target);
|
||||||
|
|
||||||
// For now, lie about audio output intentions.
|
// For now, lie about audio output intentions.
|
||||||
@ -869,65 +917,35 @@ int main(int argc, char *argv[]) {
|
|||||||
SDL_PauseAudioDevice(speaker_delegate.audio_device, 0);
|
SDL_PauseAudioDevice(speaker_delegate.audio_device, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
int window_width, window_height;
|
/*
|
||||||
SDL_GetWindowSize(window, &window_width, &window_height);
|
If the machine offers anything for activity observation,
|
||||||
|
create and register an activity observer.
|
||||||
|
*/
|
||||||
|
Activity::Source *const activity_source = machine->activity_source();
|
||||||
|
if(activity_source) {
|
||||||
|
activity_observer = std::make_unique<ActivityObserver>(activity_source, 4.0f / 3.0f);
|
||||||
|
} else {
|
||||||
|
activity_observer = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
// If this is a joystick machine, check for and open attached joysticks.
|
// If this is a joystick machine, check for and open attached joysticks.
|
||||||
/*!
|
|
||||||
Provides a wrapper for SDL_Joystick pointers that can keep track
|
|
||||||
of historic hat values.
|
|
||||||
*/
|
|
||||||
class SDLJoystick {
|
|
||||||
public:
|
|
||||||
SDLJoystick(SDL_Joystick *joystick) : joystick_(joystick) {
|
|
||||||
hat_values_.resize(SDL_JoystickNumHats(joystick));
|
|
||||||
}
|
|
||||||
|
|
||||||
~SDLJoystick() {
|
|
||||||
SDL_JoystickClose(joystick_);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// @returns The underlying SDL_Joystick.
|
|
||||||
SDL_Joystick *get() {
|
|
||||||
return joystick_;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// @returns A reference to the storage for the previous state of hat @c c.
|
|
||||||
Uint8 &last_hat_value(int c) {
|
|
||||||
return hat_values_[c];
|
|
||||||
}
|
|
||||||
|
|
||||||
/// @returns The logic OR of all stored hat states.
|
|
||||||
Uint8 hat_values() {
|
|
||||||
Uint8 value = 0;
|
|
||||||
for(const auto hat_value: hat_values_) {
|
|
||||||
value |= hat_value;
|
|
||||||
}
|
|
||||||
return value;
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
SDL_Joystick *joystick_;
|
|
||||||
std::vector<Uint8> hat_values_;
|
|
||||||
};
|
|
||||||
std::vector<SDLJoystick> joysticks;
|
|
||||||
const auto joystick_machine = machine->joystick_machine();
|
const auto joystick_machine = machine->joystick_machine();
|
||||||
if(joystick_machine) {
|
if(joystick_machine) {
|
||||||
SDL_InitSubSystem(SDL_INIT_JOYSTICK);
|
SDL_InitSubSystem(SDL_INIT_JOYSTICK);
|
||||||
for(int c = 0; c < SDL_NumJoysticks(); ++c) {
|
for(int c = 0; c < SDL_NumJoysticks(); ++c) {
|
||||||
joysticks.emplace_back(SDL_JoystickOpen(c));
|
joysticks.emplace_back(SDL_JoystickOpen(c));
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
joysticks.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
// Keep a record of whether mouse events can be forwarded.
|
||||||
If the machine offers anything for activity observation,
|
uses_mouse = !!machine->mouse_machine();
|
||||||
create and register an activity observer.
|
};
|
||||||
*/
|
setup_machine_input_output();
|
||||||
std::unique_ptr<ActivityObserver> activity_observer;
|
|
||||||
Activity::Source *const activity_source = machine->activity_source();
|
int window_width, window_height;
|
||||||
if(activity_source) {
|
SDL_GetWindowSize(window, &window_width, &window_height);
|
||||||
activity_observer = std::make_unique<ActivityObserver>(activity_source, 4.0f / 3.0f);
|
|
||||||
}
|
|
||||||
|
|
||||||
// SDL 2.x delivers key up/down events and text inputs separately even when they're correlated;
|
// SDL 2.x delivers key up/down events and text inputs separately even when they're correlated;
|
||||||
// this struct and map is used to correlate them by time.
|
// this struct and map is used to correlate them by time.
|
||||||
@ -945,7 +963,6 @@ int main(int argc, char *argv[]) {
|
|||||||
std::vector<KeyPress> keypresses;
|
std::vector<KeyPress> keypresses;
|
||||||
|
|
||||||
// Run the main event loop until the OS tells us to quit.
|
// Run the main event loop until the OS tells us to quit.
|
||||||
const bool uses_mouse = !!machine->mouse_machine();
|
|
||||||
bool should_quit = false;
|
bool should_quit = false;
|
||||||
Uint32 fullscreen_mode = 0;
|
Uint32 fullscreen_mode = 0;
|
||||||
machine_runner.start();
|
machine_runner.start();
|
||||||
@ -987,8 +1004,26 @@ int main(int argc, char *argv[]) {
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case SDL_DROPFILE: {
|
case SDL_DROPFILE: {
|
||||||
Analyser::Static::Media media = Analyser::Static::GetMedia(event.drop.file);
|
const Analyser::Static::Media media = Analyser::Static::GetMedia(event.drop.file);
|
||||||
|
|
||||||
|
// If the new file is only media, insert it; if it is a state snapshot then
|
||||||
|
// tear down the entire machine and replace it.
|
||||||
|
if(!media.empty()) {
|
||||||
machine->media_target()->insert_media(media);
|
machine->media_target()->insert_media(media);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
targets = Analyser::Static::GetTargets(event.drop.file);
|
||||||
|
if(targets.empty()) break;
|
||||||
|
|
||||||
|
::Machine::Error error;
|
||||||
|
std::unique_ptr<::Machine::DynamicMachine> new_machine(::Machine::MachineForTargets(targets, rom_fetcher, error));
|
||||||
|
if(error != Machine::Error::None) break;
|
||||||
|
|
||||||
|
machine = std::move(new_machine);
|
||||||
|
static_cast<Outputs::Display::ScanTarget *>(&scan_target)->will_change_owner();
|
||||||
|
setup_machine_input_output();
|
||||||
|
window_titler.set_file_name(final_path_component(event.drop.file));
|
||||||
} break;
|
} break;
|
||||||
|
|
||||||
case SDL_TEXTINPUT:
|
case SDL_TEXTINPUT:
|
||||||
|
Loading…
Reference in New Issue
Block a user