diff --git a/higan/emulator/emulator.hpp b/higan/emulator/emulator.hpp index 7b6083da..7ab0b575 100644 --- a/higan/emulator/emulator.hpp +++ b/higan/emulator/emulator.hpp @@ -13,7 +13,7 @@ using namespace nall; namespace Emulator { static const string Name = "higan"; - static const string Version = "106.50"; + static const string Version = "106.51"; static const string Author = "byuu"; static const string License = "GPLv3"; static const string Website = "https://byuu.org/"; diff --git a/higan/emulator/interface.hpp b/higan/emulator/interface.hpp index c5ef8073..bdde0888 100644 --- a/higan/emulator/interface.hpp +++ b/higan/emulator/interface.hpp @@ -58,6 +58,7 @@ struct Interface { virtual auto unload() -> void {} //system interface + virtual auto connected(uint port) -> uint { return 0; } virtual auto connect(uint port, uint device) -> void {} virtual auto power() -> void {} virtual auto reset() -> void {} diff --git a/higan/fc/interface/interface.cpp b/higan/fc/interface/interface.cpp index 2e49241d..36d9ed0e 100644 --- a/higan/fc/interface/interface.cpp +++ b/higan/fc/interface/interface.cpp @@ -132,6 +132,13 @@ auto Interface::unload() -> void { system.unload(); } +auto Interface::connected(uint port) -> uint { + if(port == ID::Port::Controller1) return settings.controllerPort1; + if(port == ID::Port::Controller2) return settings.controllerPort2; + if(port == ID::Port::Expansion) return settings.expansionPort; + return 0; +} + auto Interface::connect(uint port, uint device) -> void { if(port == ID::Port::Controller1) controllerPort1.connect(settings.controllerPort1 = device); if(port == ID::Port::Controller2) controllerPort2.connect(settings.controllerPort2 = device); diff --git a/higan/fc/interface/interface.hpp b/higan/fc/interface/interface.hpp index 9478783f..a184a8c1 100644 --- a/higan/fc/interface/interface.hpp +++ b/higan/fc/interface/interface.hpp @@ -36,6 +36,7 @@ struct Interface : Emulator::Interface { auto save() -> void override; auto unload() -> void override; + auto connected(uint port) -> uint override; auto connect(uint port, uint device) -> void override; auto power() -> void override; auto reset() -> void override; @@ -55,9 +56,9 @@ struct Settings { bool colorEmulation = true; bool scanlineEmulation = true; - uint controllerPort1 = 0; - uint controllerPort2 = 0; - uint expansionPort = 0; + uint controllerPort1 = ID::Device::Gamepad; + uint controllerPort2 = ID::Device::Gamepad; + uint expansionPort = ID::Device::None; }; extern Settings settings; diff --git a/higan/gb/system/system.cpp b/higan/gb/system/system.cpp index 8b0996c2..5a90a522 100644 --- a/higan/gb/system/system.cpp +++ b/higan/gb/system/system.cpp @@ -85,6 +85,7 @@ auto System::power() -> void { Emulator::video.reset(interface); Emulator::video.setPalette(); Emulator::video.setEffect(Emulator::Video::Effect::InterframeBlending, settings.blurEmulation); + Emulator::audio.reset(interface); } diff --git a/higan/md/interface/interface.cpp b/higan/md/interface/interface.cpp index 7e7f74d6..cba5cb22 100644 --- a/higan/md/interface/interface.cpp +++ b/higan/md/interface/interface.cpp @@ -116,6 +116,13 @@ auto Interface::unload() -> void { system.unload(); } +auto Interface::connected(uint port) -> uint { + if(port == ID::Port::Controller1) return settings.controllerPort1; + if(port == ID::Port::Controller2) return settings.controllerPort2; + if(port == ID::Port::Extension) return settings.extensionPort; + return 0; +} + auto Interface::connect(uint port, uint device) -> void { if(port == ID::Port::Controller1) controllerPort1.connect(settings.controllerPort1 = device); if(port == ID::Port::Controller2) controllerPort2.connect(settings.controllerPort2 = device); diff --git a/higan/md/interface/interface.hpp b/higan/md/interface/interface.hpp index 75547e11..46d9679b 100644 --- a/higan/md/interface/interface.hpp +++ b/higan/md/interface/interface.hpp @@ -36,6 +36,7 @@ struct Interface : Emulator::Interface { auto save() -> void override; auto unload() -> void override; + auto connected(uint port) -> uint override; auto connect(uint port, uint device) -> void override; auto power() -> void override; auto reset() -> void override; @@ -52,9 +53,9 @@ struct Interface : Emulator::Interface { }; struct Settings { - uint controllerPort1 = 0; - uint controllerPort2 = 0; - uint extensionPort = 0; + uint controllerPort1 = ID::Device::ControlPad; + uint controllerPort2 = ID::Device::ControlPad; + uint extensionPort = ID::Device::None; }; extern Settings settings; diff --git a/higan/ms/interface/interface.hpp b/higan/ms/interface/interface.hpp index 54473267..6e20cc66 100644 --- a/higan/ms/interface/interface.hpp +++ b/higan/ms/interface/interface.hpp @@ -31,7 +31,6 @@ struct Interface : Emulator::Interface { auto save() -> void override; auto unload() -> void override; - auto connect(uint port, uint device) -> void override {} auto power() -> void override; auto run() -> void override; diff --git a/higan/pce/interface/interface.cpp b/higan/pce/interface/interface.cpp index 092b9dc9..1b72600b 100644 --- a/higan/pce/interface/interface.cpp +++ b/higan/pce/interface/interface.cpp @@ -83,6 +83,11 @@ auto Interface::unload() -> void { system.unload(); } +auto Interface::connected(uint port) -> uint { + if(port == ID::Port::Controller) return settings.controllerPort; + return 0; +} + auto Interface::connect(uint port, uint device) -> void { if(port == ID::Port::Controller) controllerPort.connect(settings.controllerPort = device); } diff --git a/higan/pce/interface/interface.hpp b/higan/pce/interface/interface.hpp index 0e79f304..27e7f999 100644 --- a/higan/pce/interface/interface.hpp +++ b/higan/pce/interface/interface.hpp @@ -32,6 +32,7 @@ struct Interface : Emulator::Interface { auto save() -> void override; auto unload() -> void override; + auto connected(uint port) -> uint override; auto connect(uint port, uint device) -> void override; auto power() -> void override; auto run() -> void override; @@ -59,7 +60,7 @@ struct SuperGrafxInterface : Interface { }; struct Settings { - uint controllerPort = 0; + uint controllerPort = ID::Device::Gamepad; }; extern Settings settings; diff --git a/higan/sfc/interface/interface.cpp b/higan/sfc/interface/interface.cpp index 98b5236a..49138dcd 100644 --- a/higan/sfc/interface/interface.cpp +++ b/higan/sfc/interface/interface.cpp @@ -186,6 +186,13 @@ auto Interface::unload() -> void { system.unload(); } +auto Interface::connected(uint port) -> uint { + if(port == ID::Port::Controller1) return settings.controllerPort1; + if(port == ID::Port::Controller2) return settings.controllerPort2; + if(port == ID::Port::Expansion) return settings.expansionPort; + return 0; +} + auto Interface::connect(uint port, uint device) -> void { if(port == ID::Port::Controller1) controllerPort1.connect(settings.controllerPort1 = device); if(port == ID::Port::Controller2) controllerPort2.connect(settings.controllerPort2 = device); diff --git a/higan/sfc/interface/interface.hpp b/higan/sfc/interface/interface.hpp index 6a56921e..6b59e4e7 100644 --- a/higan/sfc/interface/interface.hpp +++ b/higan/sfc/interface/interface.hpp @@ -48,6 +48,7 @@ struct Interface : Emulator::Interface { auto save() -> void override; auto unload() -> void override; + auto connected(uint port) -> uint override; auto connect(uint port, uint device) -> void override; auto power() -> void override; auto reset() -> void override; @@ -76,9 +77,9 @@ struct Settings { bool colorEmulation = true; bool scanlineEmulation = true; - uint controllerPort1 = 0; - uint controllerPort2 = 0; - uint expansionPort = 0; + uint controllerPort1 = ID::Device::Gamepad; + uint controllerPort2 = ID::Device::Gamepad; + uint expansionPort = ID::Device::None; bool random = true; }; diff --git a/higan/target-bsnes/presentation/presentation.cpp b/higan/target-bsnes/presentation/presentation.cpp index 53b8ee6d..5fd8d2f2 100644 --- a/higan/target-bsnes/presentation/presentation.cpp +++ b/higan/target-bsnes/presentation/presentation.cpp @@ -21,38 +21,7 @@ Presentation::Presentation() { controllerPort1.setIcon(Icon::Device::Joypad).setText(tr("Controller Port 1")); controllerPort2.setIcon(Icon::Device::Joypad).setText(tr("Controller Port 2")); expansionPort.setIcon(Icon::Device::Storage).setText(tr("Expansion Port")); - for(auto& port : emulator->ports) { - Menu* menu = nullptr; - if(port.name == "Controller Port 1") menu = &controllerPort1; - if(port.name == "Controller Port 2") menu = &controllerPort2; - if(port.name == "Expansion Port") menu = &expansionPort; - if(!menu) continue; - - Group devices; - for(auto& device : port.devices) { - if(port.name != "Expansion Port" && device.name == "None") continue; - if(port.name == "Expansion Port" && device.name == "21fx") continue; - MenuRadioItem item{menu}; - item.setText(tr(device.name)).onActivate([=] { - auto path = string{"Emulator/", port.name}.replace(" ", ""); - settings(path).setValue(device.name); - emulator->connect(port.id, device.id); - }); - devices.append(item); - } - auto path = string{"Emulator/", port.name}.replace(" ", ""); - auto device = settings(path).text(); - bool found = false; - if(devices.objectCount() > 1) { - for(auto item : devices.objects()) { - if(item.text() == device) item.setChecked(), found = true; - } - } - //select the first device when a new settings file is being created - if(devices.objectCount() && !found) { - devices.objects()(0).doActivate(); - } - } + updateDeviceMenu(); quit.setIcon(Icon::Action::Quit).setText(tr("Quit")).onActivate([&] { program->quit(); }); settingsMenu.setText(tr("Settings")); @@ -372,6 +341,64 @@ auto Presentation::toggleFullscreenMode() -> void { } } +auto Presentation::updateDeviceMenu() -> void { + controllerPort1.reset(); + controllerPort2.reset(); + expansionPort.reset(); + + for(auto& port : emulator->ports) { + Menu* menu = nullptr; + if(port.name == "Controller Port 1") menu = &controllerPort1; + if(port.name == "Controller Port 2") menu = &controllerPort2; + if(port.name == "Expansion Port") menu = &expansionPort; + if(!menu) continue; + + auto path = string{"Emulator/", port.name}.replace(" ", ""); + auto deviceName = settings(path).text(); + auto deviceID = emulator->connected(port.id); + + Group devices; + for(auto& device : port.devices) { + if(port.name == "Expansion Port" && device.name == "21fx") continue; + + MenuRadioItem item{menu}; + item.setProperty("deviceID", device.id); + item.setText(tr(device.name)); + item.onActivate([=] { + settings(path).setValue(device.name); + emulator->connect(port.id, device.id); + updateDeviceSelections(); + }); + devices.append(item); + + if(deviceName == device.name) item.doActivate(); + if(!deviceName && deviceID == device.id) item.doActivate(); + } + } + + updateDeviceSelections(); +} + +auto Presentation::updateDeviceSelections() -> void { + for(auto& port : emulator->ports) { + Menu* menu = nullptr; + if(port.name == "Controller Port 1") menu = &controllerPort1; + if(port.name == "Controller Port 2") menu = &controllerPort2; + if(port.name == "Expansion Port") menu = &expansionPort; + if(!menu) continue; + + auto deviceID = emulator->connected(port.id); + for(auto& action : menu->actions()) { + if(auto item = action.cast()) { + if(item.property("deviceID").natural() == deviceID) { + item.setChecked(); + break; + } + } + } + } +} + //generate a list of size multipliers auto Presentation::updateSizeMenu() -> void { assert(sizeMenu.actions() == 0); //should only be called once diff --git a/higan/target-bsnes/presentation/presentation.hpp b/higan/target-bsnes/presentation/presentation.hpp index a0663923..9f90f924 100644 --- a/higan/target-bsnes/presentation/presentation.hpp +++ b/higan/target-bsnes/presentation/presentation.hpp @@ -33,6 +33,8 @@ struct Presentation : Window { auto resizeWindow() -> void; auto updateStatus() -> void; auto toggleFullscreenMode() -> void; + auto updateDeviceMenu() -> void; + auto updateDeviceSelections() -> void; auto updateSizeMenu() -> void; auto clearRecentGames() -> void; auto updateRecentGames() -> void; diff --git a/higan/target-bsnes/program/game.cpp b/higan/target-bsnes/program/game.cpp index 94ad89a8..68dc4522 100644 --- a/higan/target-bsnes/program/game.cpp +++ b/higan/target-bsnes/program/game.cpp @@ -18,7 +18,6 @@ auto Program::load() -> void { return showMessage("Game loading cancelled"); } } - updateInputDevices(); hackCompatibility(); emulator->power(); if(settingsWindow->advanced.autoLoadStateOnLoad.checked()) { diff --git a/higan/target-bsnes/program/input.cpp b/higan/target-bsnes/program/input.cpp index 78f9c30b..260c011b 100644 --- a/higan/target-bsnes/program/input.cpp +++ b/higan/target-bsnes/program/input.cpp @@ -15,16 +15,3 @@ auto Program::updateInputDriver() -> void { return updateInputDriver(); } } - -auto Program::updateInputDevices() -> void { - for(auto& port : emulator->ports) { - auto path = string{"Emulator/", port.name}.replace(" ", ""); - auto name = settings(path).text(); - for(auto& device : port.devices) { - if(device.name == name) { - emulator->connect(port.id, device.id); - break; - } - } - } -} diff --git a/higan/target-bsnes/program/program.hpp b/higan/target-bsnes/program/program.hpp index 4b6366dd..b31ca758 100644 --- a/higan/target-bsnes/program/program.hpp +++ b/higan/target-bsnes/program/program.hpp @@ -74,7 +74,6 @@ struct Program : Emulator::Platform { //input.cpp auto updateInputDriver() -> void; - auto updateInputDevices() -> void; //utility.cpp auto showMessage(string text) -> void; diff --git a/higan/target-higan/presentation/presentation.cpp b/higan/target-higan/presentation/presentation.cpp index 07daff6f..f15fea51 100644 --- a/higan/target-higan/presentation/presentation.cpp +++ b/higan/target-higan/presentation/presentation.cpp @@ -9,9 +9,6 @@ Presentation::Presentation() { systemsMenu.setText("Systems"); systemMenu.setVisible(false); - resetSystem.setText("Soft Reset").onActivate([&] { program->softReset(); }); - powerSystem.setText("Power Cycle").onActivate([&] { program->powerCycle(); }); - unloadSystem.setText("Unload").onActivate([&] { program->unloadMedium(); }); settingsMenu.setText("Settings"); videoScaleMenu.setText("Video Scale"); @@ -165,44 +162,86 @@ Presentation::Presentation() { #endif } -auto Presentation::updateEmulator() -> void { +auto Presentation::updateEmulatorMenu() -> void { if(!emulator) return; - inputPort1.setVisible(false).reset(); - inputPort2.setVisible(false).reset(); - inputPort3.setVisible(false).reset(); - for(auto n : range(emulator->ports.size())) { - if(n >= 3) break; - auto& port = emulator->ports[n]; - auto& menu = (n == 0 ? inputPort1 : n == 1 ? inputPort2 : inputPort3); + systemMenu.reset(); + for(auto& port : emulator->ports) { + Menu menu{&systemMenu}; + menu.setProperty("portID", port.id); menu.setText(port.name); + if(port.name.beginsWith("Expansion") || port.name.beginsWith("Extension")) { + menu.setIcon(Icon::Device::Storage); + } else { + menu.setIcon(Icon::Device::Joypad); + } + + auto path = string{emulator->information.name, "/", port.name}.replace(" ", ""); + auto deviceName = settings(path).text(); + auto deviceID = emulator->connected(port.id); Group devices; for(auto& device : port.devices) { MenuRadioItem item{&menu}; - item.setText(device.name).onActivate([=] { - auto path = string{emulator->information.name, "/", port.name}.replace(" ", ""); - settings[path].setValue(device.name); + item.setProperty("deviceID", device.id); + item.setText(device.name); + item.onActivate([=] { + settings(path).setValue(device.name); emulator->connect(port.id, device.id); + updateEmulatorDeviceSelections(); }); devices.append(item); + + if(deviceName == device.name) item.doActivate(); + if(!deviceName && deviceID == device.id) item.doActivate(); } - if(devices.objectCount() > 1) { - auto path = string{emulator->information.name, "/", port.name}.replace(" ", ""); - auto device = settings(path).text(); - for(auto item : devices.objects()) { - if(item.text() == device) item.setChecked(); - } - menu.setVisible(); + + if(devices.objectCount() == 0) { + menu.setVisible(false); } } - systemMenuSeparatorPorts.setVisible(inputPort1.visible() || inputPort2.visible() || inputPort3.visible()); - resetSystem.setVisible(emulator->information.resettable); + if(systemMenu.actionCount()) { + systemMenu.append(MenuSeparator()); + } - emulator->set("Blur Emulation", blurEmulation.checked()); - emulator->set("Color Emulation", colorEmulation.checked()); - emulator->set("Scanline Emulation", scanlineEmulation.checked()); + if(emulator->information.resettable) { + systemMenu.append(MenuItem().setText("Soft Reset").setIcon(Icon::Action::Refresh).onActivate([&] { + program->softReset(); + })); + } + + systemMenu.append(MenuItem().setText("Power Cycle").setIcon(Icon::Action::Refresh).onActivate([&] { + program->powerCycle(); + })); + + systemMenu.append(MenuItem().setText("Unload").setIcon(Icon::Media::Eject).onActivate([&] { + program->unloadMedium(); + })); + + updateEmulatorDeviceSelections(); +} + +auto Presentation::updateEmulatorDeviceSelections() -> void { + if(!emulator) return; + + for(auto& port : emulator->ports) { + for(auto& action : systemMenu->actions()) { + auto portID = action.property("portID"); + if(portID && portID.natural() == port.id) { + if(auto menu = action.cast()) { + auto deviceID = emulator->connected(port.id); + for(auto& action : menu.actions()) { + if(auto item = action.cast()) { + if(item.property("deviceID").natural() == deviceID) { + item.setChecked(); + } + } + } + } + } + } + } } auto Presentation::drawIcon(uint32_t* output, uint length, uint width, uint height) -> void { diff --git a/higan/target-higan/presentation/presentation.hpp b/higan/target-higan/presentation/presentation.hpp index 3ec8e710..55cde3e9 100644 --- a/higan/target-higan/presentation/presentation.hpp +++ b/higan/target-higan/presentation/presentation.hpp @@ -10,7 +10,8 @@ struct AboutWindow : Window { struct Presentation : Window { Presentation(); - auto updateEmulator() -> void; + auto updateEmulatorMenu() -> void; + auto updateEmulatorDeviceSelections() -> void; auto drawIcon(uint32_t* output, uint length, uint width, uint height) -> void; auto clearViewport() -> void; auto resizeViewport(bool resizeWindow = true) -> void; diff --git a/higan/target-higan/program/medium.cpp b/higan/target-higan/program/medium.cpp index e30a47b9..efff4d18 100644 --- a/higan/target-higan/program/medium.cpp +++ b/higan/target-higan/program/medium.cpp @@ -20,13 +20,16 @@ auto Program::loadMedium(Emulator::Interface& interface, const Emulator::Interfa mediumPaths.append(locate({"systems/", medium.name, ".sys/"})); inputManager->bind(emulator = &interface); + presentation->updateEmulatorMenu(); if(!emulator->load(medium.id)) { emulator = nullptr; mediumPaths.reset(); return; } - connectDevices(); emulator->power(); + emulator->set("Blur Emulation", presentation->blurEmulation.checked()); + emulator->set("Color Emulation", presentation->colorEmulation.checked()); + emulator->set("Scanline Emulation", presentation->scanlineEmulation.checked()); updateAudioDriver(); updateAudioEffects(); @@ -34,7 +37,6 @@ auto Program::loadMedium(Emulator::Interface& interface, const Emulator::Interfa presentation->setTitle(emulator->title()); presentation->systemMenu.setText(medium.name).setVisible(true); presentation->toolsMenu.setVisible(true); - presentation->updateEmulator(); toolsManager->cheatEditor.loadCheats(); toolsManager->stateManager.doRefresh(); toolsManager->manifestViewer.doRefresh(); diff --git a/higan/target-higan/program/program.hpp b/higan/target-higan/program/program.hpp index 84182a49..5a9cecee 100644 --- a/higan/target-higan/program/program.hpp +++ b/higan/target-higan/program/program.hpp @@ -34,7 +34,6 @@ struct Program : Emulator::Platform { auto powerCycle() -> void; auto togglePause() -> void; auto rotateDisplay() -> void; - auto connectDevices() -> void; auto showMessage(const string& text) -> void; auto updateStatusText() -> void; auto updateVideoPalette() -> void; diff --git a/higan/target-higan/program/utility.cpp b/higan/target-higan/program/utility.cpp index ef9990dd..43f7ec91 100644 --- a/higan/target-higan/program/utility.cpp +++ b/higan/target-higan/program/utility.cpp @@ -94,20 +94,6 @@ auto Program::rotateDisplay() -> void { showMessage("Display rotated"); } -auto Program::connectDevices() -> void { - if(!emulator) return; - for(auto& port : emulator->ports) { - auto path = string{emulator->information.name, "/", port.name}.replace(" ", ""); - auto name = settings(path).text(); - for(auto& device : port.devices) { - if(device.name == name) { - emulator->connect(port.id, device.id); - break; - } - } - } -} - auto Program::showMessage(const string& text) -> void { statusTime = time(nullptr); statusMessage = text; diff --git a/hiro/core/shared.hpp b/hiro/core/shared.hpp index 6e3c9dd4..04fc1909 100644 --- a/hiro/core/shared.hpp +++ b/hiro/core/shared.hpp @@ -15,6 +15,12 @@ template Name(T* parent, P&&... p) : Name() { \ if(parent) (*parent)->append(*this, std::forward

(p)...); \ } \ + template auto cast() -> T { \ + if(auto pointer = dynamic_cast(data())) { \ + if(auto shared = pointer->instance.acquire()) return T(shared); \ + } \ + return T(); \ + } \ auto enabled(bool recursive = false) const { return self().enabled(recursive); } \ auto focused() const { return self().focused(); } \ auto font(bool recursive = false) const { return self().font(recursive); } \ @@ -52,13 +58,6 @@ struct Object : sObject { DeclareSharedObject(Object) using internalType = mObject; - - template auto cast() -> T { - if(auto pointer = dynamic_cast(data())) { - if(auto shared = pointer->instance.acquire()) return T(shared); - } - return T(); - } }; #endif