Update to 20180731 release.

byuu says:

I've completed moving all the class objects from `unique_pointer<T>` to
just T. The one exception is the Emulator::Interface instance. I can
absolutely make that a global object, but only in bsnes where there's
just the one emulation core.

I also moved all the SettingsWindow and ToolsWindow panels out to their
own global objects, and fixed a very difficult bug with GTK TabFrame
controls.

The configuration settings panel is now the emulator settings panel. And
I added some spacing between bold label sections on both the emulator
and driver settings panels.

I gave fixing ComboButtonItem my best shot, given I can't reproduce the
crash. Probably won't work, though.

Also made a very slight consistency improvement to ruby and renamed
driverName() to driver().

...

An important change ... as a result of moving bsnes to global objects,
this means that the constructors for all windows run before the
presentation window is displayed. Before this change, only the
presentation window was constructed first berore displaying it, followed
by the construction of the rest of the GUI windows.

The upside to this is that as soon as you see the main window, the GUI
is ready to go without a period where it's unresponsive.

The downside to this is it takes about 1.5 seconds to show the main
window, compared to around 0.75 seconds before.

I've no intention of changing that back. So if the startup time becomes
a problem, then we'll just have to work on optimizing hiro, so that it
can construct all the global Window objects quicker. The main way to do
that would be to not do calls to the Layout::setGeometry functions for
every widget added, and instead wait until the window is displayed. But
I don't have an easy way to do that, because you want the widget
geometry values to be sane even before the window is visible to help
size certain things.
This commit is contained in:
Tim Allen 2018-07-31 20:56:45 +10:00
parent 212da0a966
commit 2335bb0df8
57 changed files with 557 additions and 560 deletions

View File

@ -34,6 +34,6 @@ auto nall::main(vector<string> arguments) -> void {
Application::locale().scan(locate("locales/")); Application::locale().scan(locate("locales/"));
Application::locale().select(locale); Application::locale().select(locale);
emulator = new SuperFamicom::Interface; emulator = new SuperFamicom::Interface;
new Program(arguments); program.create(arguments);
Application::run(); Application::run();
} }

View File

@ -2,7 +2,7 @@ auto InputManager::bindHotkeys() -> void {
static int stateSlot = 1; static int stateSlot = 1;
hotkeys.append(InputHotkey("Toggle Fullscreen Mode").onPress([] { hotkeys.append(InputHotkey("Toggle Fullscreen Mode").onPress([] {
presentation->toggleFullscreenMode(); presentation.toggleFullscreenMode();
})); }));
hotkeys.append(InputHotkey("Toggle Mouse Capture").onPress([] { hotkeys.append(InputHotkey("Toggle Mouse Capture").onPress([] {
@ -10,40 +10,37 @@ auto InputManager::bindHotkeys() -> void {
})); }));
hotkeys.append(InputHotkey("Toggle Cheat Codes").onPress([] { hotkeys.append(InputHotkey("Toggle Cheat Codes").onPress([] {
toolsWindow->cheatEditor.enableCheats.setChecked( cheatEditor.enableCheats.setChecked(!cheatEditor.enableCheats.checked()).doToggle();
!toolsWindow->cheatEditor.enableCheats.checked()
);
toolsWindow->cheatEditor.enableCheats.doToggle();
})); }));
hotkeys.append(InputHotkey("Save State").onPress([&] { hotkeys.append(InputHotkey("Save State").onPress([&] {
program->saveState({"quick/slot ", stateSlot}); program.saveState({"quick/slot ", stateSlot});
})); }));
hotkeys.append(InputHotkey("Load State").onPress([&] { hotkeys.append(InputHotkey("Load State").onPress([&] {
program->loadState({"quick/slot ", stateSlot}); program.loadState({"quick/slot ", stateSlot});
})); }));
hotkeys.append(InputHotkey("Load Undo State").onPress([&] { hotkeys.append(InputHotkey("Load Undo State").onPress([&] {
program->loadState("quick/undo"); program.loadState("quick/undo");
})); }));
hotkeys.append(InputHotkey("Load Redo State").onPress([&] { hotkeys.append(InputHotkey("Load Redo State").onPress([&] {
program->loadState("quick/redo"); program.loadState("quick/redo");
})); }));
hotkeys.append(InputHotkey("Increment State Slot").onPress([&] { hotkeys.append(InputHotkey("Increment State Slot").onPress([&] {
if(--stateSlot < 1) stateSlot = 9; if(--stateSlot < 1) stateSlot = 9;
program->showMessage({"Selected state slot ", stateSlot}); program.showMessage({"Selected state slot ", stateSlot});
})); }));
hotkeys.append(InputHotkey("Decrement State Slot").onPress([&] { hotkeys.append(InputHotkey("Decrement State Slot").onPress([&] {
if(++stateSlot > 9) stateSlot = 1; if(++stateSlot > 9) stateSlot = 1;
program->showMessage({"Selected state slot ", stateSlot}); program.showMessage({"Selected state slot ", stateSlot});
})); }));
hotkeys.append(InputHotkey("Capture Screenshot").onPress([] { hotkeys.append(InputHotkey("Capture Screenshot").onPress([] {
program->captureScreenshot(); program.captureScreenshot();
})); }));
hotkeys.append(InputHotkey("Fast Forward").onPress([] { hotkeys.append(InputHotkey("Fast Forward").onPress([] {
@ -55,19 +52,19 @@ auto InputManager::bindHotkeys() -> void {
})); }));
hotkeys.append(InputHotkey("Pause Emulation").onPress([] { hotkeys.append(InputHotkey("Pause Emulation").onPress([] {
presentation->pauseEmulation.setChecked(!presentation->pauseEmulation.checked()); presentation.pauseEmulation.setChecked(!presentation.pauseEmulation.checked());
})); }));
hotkeys.append(InputHotkey("Frame Advance").onPress([] { hotkeys.append(InputHotkey("Frame Advance").onPress([] {
presentation->frameAdvance.doActivate(); presentation.frameAdvance.doActivate();
})); }));
hotkeys.append(InputHotkey("Reset Emulation").onPress([] { hotkeys.append(InputHotkey("Reset Emulation").onPress([] {
program->reset(); program.reset();
})); }));
hotkeys.append(InputHotkey("Quit Emulator").onPress([] { hotkeys.append(InputHotkey("Quit Emulator").onPress([] {
program->quit(); program.quit();
})); }));
for(auto& hotkey : hotkeys) { for(auto& hotkey : hotkeys) {
@ -78,7 +75,7 @@ auto InputManager::bindHotkeys() -> void {
} }
auto InputManager::pollHotkeys() -> void { auto InputManager::pollHotkeys() -> void {
if(!program->focused()) return; if(!program.focused()) return;
for(auto& hotkey : hotkeys) { for(auto& hotkey : hotkeys) {
auto state = hotkey.poll(); auto state = hotkey.poll();

View File

@ -1,6 +1,6 @@
#include "../bsnes.hpp" #include "../bsnes.hpp"
#include "hotkeys.cpp" #include "hotkeys.cpp"
unique_pointer<InputManager> inputManager; InputManager inputManager;
auto InputMapping::bind() -> void { auto InputMapping::bind() -> void {
mappings.reset(); mappings.reset();
@ -15,7 +15,7 @@ auto InputMapping::bind() -> void {
string qualifier = token(3, "None"); string qualifier = token(3, "None");
Mapping mapping; Mapping mapping;
for(auto& device : inputManager->devices) { for(auto& device : inputManager.devices) {
if(id != device->id()) continue; if(id != device->id()) continue;
mapping.device = device; mapping.device = device;
@ -103,9 +103,9 @@ auto InputMapping::unbind() -> void {
auto InputMapping::poll() -> int16 { auto InputMapping::poll() -> int16 {
if(turboID) { if(turboID) {
auto& mapping = inputManager->ports[portID].devices[deviceID].mappings[turboID()]; auto& mapping = inputManager.ports[portID].devices[deviceID].mappings[turboID()];
auto result = mapping.poll(); auto result = mapping.poll();
if(result) return inputManager->turboCounter >= inputManager->turboFrequency; if(result) return inputManager.turboCounter >= inputManager.turboFrequency;
} }
int16 result; int16 result;
@ -180,16 +180,11 @@ auto InputMapping::displayName() -> string {
// //
InputManager::InputManager() {
inputManager = this;
}
auto InputManager::initialize() -> void { auto InputManager::initialize() -> void {
devices.reset(); devices.reset();
ports.reset(); ports.reset();
hotkeys.reset(); hotkeys.reset();
if(!input) return;
input.onChange({&InputManager::onChange, this}); input.onChange({&InputManager::onChange, this});
lastPoll = chrono::millisecond(); lastPoll = chrono::millisecond();
@ -283,9 +278,9 @@ auto InputManager::frame() -> void {
} }
auto InputManager::onChange(shared_pointer<HID::Device> device, uint group, uint input, int16_t oldValue, int16_t newValue) -> void { auto InputManager::onChange(shared_pointer<HID::Device> device, uint group, uint input, int16_t oldValue, int16_t newValue) -> void {
if(settingsWindow->focused()) { if(settingsWindow.focused()) {
settingsWindow->input.inputEvent(device, group, input, oldValue, newValue); inputSettings.inputEvent(device, group, input, oldValue, newValue);
settingsWindow->hotkeys.inputEvent(device, group, input, oldValue, newValue); hotkeySettings.inputEvent(device, group, input, oldValue, newValue);
} }
} }

View File

@ -67,7 +67,6 @@ struct InputPort {
}; };
struct InputManager { struct InputManager {
InputManager();
auto initialize() -> void; auto initialize() -> void;
auto bind() -> void; auto bind() -> void;
auto poll() -> void; auto poll() -> void;
@ -92,4 +91,4 @@ public:
uint turboFrequency = 0; uint turboFrequency = 0;
}; };
extern unique_pointer<InputManager> inputManager; extern InputManager inputManager;

View File

@ -1,28 +1,26 @@
#include "../bsnes.hpp" #include "../bsnes.hpp"
#include "about.cpp" #include "about.cpp"
AboutWindow aboutWindow; AboutWindow aboutWindow;
unique_pointer<Presentation> presentation; Presentation presentation;
Presentation::Presentation() {
presentation = this;
auto Presentation::create() -> void {
systemMenu.setText(tr("System")); systemMenu.setText(tr("System"));
loadGame.setIcon(Icon::Action::Open).setText({tr("Load Game"), " ..."}).onActivate([&] { loadGame.setIcon(Icon::Action::Open).setText({tr("Load Game"), " ..."}).onActivate([&] {
program->load(); program.load();
}); });
loadRecentGame.setIcon(Icon::Action::Open).setText(tr("Load Recent Game")); loadRecentGame.setIcon(Icon::Action::Open).setText(tr("Load Recent Game"));
updateRecentGames(); updateRecentGames();
resetSystem.setIcon(Icon::Action::Refresh).setText(tr("Reset System")).setEnabled(false).onActivate([&] { resetSystem.setIcon(Icon::Action::Refresh).setText(tr("Reset System")).setEnabled(false).onActivate([&] {
program->reset(); program.reset();
}); });
unloadGame.setIcon(Icon::Action::Remove).setText(tr("Unload Game")).setEnabled(false).onActivate([&] { unloadGame.setIcon(Icon::Action::Remove).setText(tr("Unload Game")).setEnabled(false).onActivate([&] {
program->unload(); program.unload();
}); });
controllerPort1.setIcon(Icon::Device::Joypad).setText(tr("Controller Port 1")); controllerPort1.setIcon(Icon::Device::Joypad).setText(tr("Controller Port 1"));
controllerPort2.setIcon(Icon::Device::Joypad).setText(tr("Controller Port 2")); controllerPort2.setIcon(Icon::Device::Joypad).setText(tr("Controller Port 2"));
expansionPort.setIcon(Icon::Device::Storage).setText(tr("Expansion Port")); expansionPort.setIcon(Icon::Device::Storage).setText(tr("Expansion Port"));
updateDeviceMenu(); updateDeviceMenu();
quit.setIcon(Icon::Action::Quit).setText(tr("Quit")).onActivate([&] { program->quit(); }); quit.setIcon(Icon::Action::Quit).setText(tr("Quit")).onActivate([&] { program.quit(); });
settingsMenu.setText(tr("Settings")); settingsMenu.setText(tr("Settings"));
sizeMenu.setIcon(Icon::Emblem::Image).setText("Size"); sizeMenu.setIcon(Icon::Emblem::Image).setText("Size");
@ -58,7 +56,7 @@ Presentation::Presentation() {
shaderMenu.setIcon(Icon::Emblem::Image).setText("Shader"); shaderMenu.setIcon(Icon::Emblem::Image).setText("Shader");
muteAudio.setText("Mute Audio").setChecked(settings["Audio/Mute"].boolean()).onToggle([&] { muteAudio.setText("Mute Audio").setChecked(settings["Audio/Mute"].boolean()).onToggle([&] {
settings["Audio/Mute"].setValue(muteAudio.checked()); settings["Audio/Mute"].setValue(muteAudio.checked());
program->updateAudioEffects(); program.updateAudioEffects();
}); });
showStatusBar.setText("Show Status Bar").setChecked(settings["UserInterface/ShowStatusBar"].boolean()).onToggle([&] { showStatusBar.setText("Show Status Bar").setChecked(settings["UserInterface/ShowStatusBar"].boolean()).onToggle([&] {
settings["UserInterface/ShowStatusBar"].setValue(showStatusBar.checked()); settings["UserInterface/ShowStatusBar"].setValue(showStatusBar.checked());
@ -69,13 +67,13 @@ Presentation::Presentation() {
} }
if(visible()) resizeWindow(); if(visible()) resizeWindow();
}); });
videoSettings.setIcon(Icon::Device::Display).setText("Video ...").onActivate([&] { settingsWindow->show(0); }); videoSettings.setIcon(Icon::Device::Display).setText("Video ...").onActivate([&] { settingsWindow.show(0); });
audioSettings.setIcon(Icon::Device::Speaker).setText("Audio ...").onActivate([&] { settingsWindow->show(1); }); audioSettings.setIcon(Icon::Device::Speaker).setText("Audio ...").onActivate([&] { settingsWindow.show(1); });
inputSettings.setIcon(Icon::Device::Joypad).setText("Input ...").onActivate([&] { settingsWindow->show(2); }); inputSettings.setIcon(Icon::Device::Joypad).setText("Input ...").onActivate([&] { settingsWindow.show(2); });
hotkeySettings.setIcon(Icon::Device::Keyboard).setText("Hotkeys ...").onActivate([&] { settingsWindow->show(3); }); hotkeySettings.setIcon(Icon::Device::Keyboard).setText("Hotkeys ...").onActivate([&] { settingsWindow.show(3); });
pathSettings.setIcon(Icon::Emblem::Folder).setText("Paths ...").onActivate([&] { settingsWindow->show(4); }); pathSettings.setIcon(Icon::Emblem::Folder).setText("Paths ...").onActivate([&] { settingsWindow.show(4); });
configurationSettings.setIcon(Icon::Action::Settings).setText("Configuration ...").onActivate([&] { settingsWindow->show(5); }); emulatorSettings.setIcon(Icon::Action::Settings).setText("Emulator ...").onActivate([&] { settingsWindow.show(5); });
driverSettings.setIcon(Icon::Place::Settings).setText("Drivers ...").onActivate([&] { settingsWindow->show(6); }); driverSettings.setIcon(Icon::Place::Settings).setText("Drivers ...").onActivate([&] { settingsWindow.show(6); });
toolsMenu.setText(tr("Tools")).setVisible(false); toolsMenu.setText(tr("Tools")).setVisible(false);
saveState.setIcon(Icon::Action::Save).setText("Save State"); saveState.setIcon(Icon::Action::Save).setText("Save State");
@ -84,7 +82,7 @@ Presentation::Presentation() {
item.setProperty("name", {"quick/slot ", 1 + index}); item.setProperty("name", {"quick/slot ", 1 + index});
item.setProperty("title", {"Slot ", 1 + index}); item.setProperty("title", {"Slot ", 1 + index});
item.setText({"Slot ", 1 + index}); item.setText({"Slot ", 1 + index});
item.onActivate([=] { program->saveState({"quick/slot ", 1 + index}); }); item.onActivate([=] { program.saveState({"quick/slot ", 1 + index}); });
} }
loadState.setIcon(Icon::Media::Play).setText("Load State"); loadState.setIcon(Icon::Media::Play).setText("Load State");
for(uint index : range(QuickStates)) { for(uint index : range(QuickStates)) {
@ -92,48 +90,48 @@ Presentation::Presentation() {
item.setProperty("name", {"quick/slot ", 1 + index}); item.setProperty("name", {"quick/slot ", 1 + index});
item.setProperty("title", {"Slot ", 1 + index}); item.setProperty("title", {"Slot ", 1 + index});
item.setText({"Slot ", 1 + index}); item.setText({"Slot ", 1 + index});
item.onActivate([=] { program->loadState({"quick/slot ", 1 + index}); }); item.onActivate([=] { program.loadState({"quick/slot ", 1 + index}); });
} }
loadState.append(MenuSeparator()); loadState.append(MenuSeparator());
loadState.append(MenuItem() loadState.append(MenuItem()
.setProperty("name", "quick/undo") .setProperty("name", "quick/undo")
.setProperty("title", "Undo Last Save") .setProperty("title", "Undo Last Save")
.setIcon(Icon::Edit::Undo).setText("Undo Last Save").onActivate([&] { .setIcon(Icon::Edit::Undo).setText("Undo Last Save").onActivate([&] {
program->loadState("quick/undo"); program.loadState("quick/undo");
})); }));
loadState.append(MenuItem() loadState.append(MenuItem()
.setProperty("name", "quick/redo") .setProperty("name", "quick/redo")
.setProperty("title", "Redo Last Undo") .setProperty("title", "Redo Last Undo")
.setIcon(Icon::Edit::Redo).setText("Redo Last Undo").onActivate([&] { .setIcon(Icon::Edit::Redo).setText("Redo Last Undo").onActivate([&] {
program->loadState("quick/redo"); program.loadState("quick/redo");
})); }));
loadState.append(MenuItem().setIcon(Icon::Edit::Clear).setText("Remove All States").onActivate([&] { loadState.append(MenuItem().setIcon(Icon::Edit::Clear).setText("Remove All States").onActivate([&] {
if(MessageDialog("Are you sure you want to permanently remove all quick states for this game?").setParent(*this).question() == "Yes") { if(MessageDialog("Are you sure you want to permanently remove all quick states for this game?").setParent(*this).question() == "Yes") {
for(uint index : range(QuickStates)) program->removeState({"quick/slot ", 1 + index}); for(uint index : range(QuickStates)) program.removeState({"quick/slot ", 1 + index});
program->removeState("quick/undo"); program.removeState("quick/undo");
program->removeState("quick/redo"); program.removeState("quick/redo");
updateStateMenus(); updateStateMenus();
} }
})); }));
speedMenu.setIcon(Icon::Device::Clock).setText("Speed"); speedMenu.setIcon(Icon::Device::Clock).setText("Speed");
speedSlowest.setText("50% (Slowest)").setProperty("multiplier", "2.0").onActivate([&] { program->updateAudioFrequency(); }); speedSlowest.setText("50% (Slowest)").setProperty("multiplier", "2.0").onActivate([&] { program.updateAudioFrequency(); });
speedSlow.setText("75% (Slow)").setProperty("multiplier", "1.333").onActivate([&] { program->updateAudioFrequency(); }); speedSlow.setText("75% (Slow)").setProperty("multiplier", "1.333").onActivate([&] { program.updateAudioFrequency(); });
speedNormal.setText("100% (Normal)").setProperty("multiplier", "1.0").onActivate([&] { program->updateAudioFrequency(); }); speedNormal.setText("100% (Normal)").setProperty("multiplier", "1.0").onActivate([&] { program.updateAudioFrequency(); });
speedFast.setText("150% (Fast)").setProperty("multiplier", "0.667").onActivate([&] { program->updateAudioFrequency(); }); speedFast.setText("150% (Fast)").setProperty("multiplier", "0.667").onActivate([&] { program.updateAudioFrequency(); });
speedFastest.setText("200% (Fastest)").setProperty("multiplier", "0.5").onActivate([&] { program->updateAudioFrequency(); }); speedFastest.setText("200% (Fastest)").setProperty("multiplier", "0.5").onActivate([&] { program.updateAudioFrequency(); });
pauseEmulation.setText("Pause Emulation").onToggle([&] { pauseEmulation.setText("Pause Emulation").onToggle([&] {
if(pauseEmulation.checked()) audio.clear(); if(pauseEmulation.checked()) audio.clear();
}); });
frameAdvance.setIcon(Icon::Media::Next).setText("Frame Advance").onActivate([&] { frameAdvance.setIcon(Icon::Media::Next).setText("Frame Advance").onActivate([&] {
pauseEmulation.setChecked(false); pauseEmulation.setChecked(false);
program->frameAdvance = true; program.frameAdvance = true;
}); });
captureScreenshot.setIcon(Icon::Emblem::Image).setText("Capture Screenshot").onActivate([&] { captureScreenshot.setIcon(Icon::Emblem::Image).setText("Capture Screenshot").onActivate([&] {
program->captureScreenshot(); program.captureScreenshot();
}); });
cheatEditor.setIcon(Icon::Edit::Replace).setText("Cheat Editor ...").onActivate([&] { toolsWindow->show(0); }); cheatEditor.setIcon(Icon::Edit::Replace).setText("Cheat Editor ...").onActivate([&] { toolsWindow.show(0); });
stateManager.setIcon(Icon::Application::FileManager).setText("State Manager ...").onActivate([&] { toolsWindow->show(1); }); stateManager.setIcon(Icon::Application::FileManager).setText("State Manager ...").onActivate([&] { toolsWindow.show(1); });
manifestViewer.setIcon(Icon::Emblem::Text).setText("Manifest Viewer ...").onActivate([&] { toolsWindow->show(2); }); manifestViewer.setIcon(Icon::Emblem::Text).setText("Manifest Viewer ...").onActivate([&] { toolsWindow.show(2); });
helpMenu.setText(tr("Help")); helpMenu.setText(tr("Help"));
documentation.setIcon(Icon::Application::Browser).setText({tr("Documentation"), " ..."}).onActivate([&] { documentation.setIcon(Icon::Application::Browser).setText({tr("Documentation"), " ..."}).onActivate([&] {
@ -144,8 +142,8 @@ Presentation::Presentation() {
}); });
viewport.setDroppable().onDrop([&](vector<string> locations) { viewport.setDroppable().onDrop([&](vector<string> locations) {
program->gameQueue = locations; program.gameQueue = locations;
program->load(); program.load();
setFocused(); setFocused();
}); });
@ -175,10 +173,10 @@ Presentation::Presentation() {
spacerRight.setBackgroundColor(back).setForegroundColor(fore); spacerRight.setBackgroundColor(back).setForegroundColor(fore);
program->updateStatus(); program.updateStatus();
onClose([&] { onClose([&] {
program->quit(); program.quit();
}); });
onSize([&] { onSize([&] {
@ -199,7 +197,7 @@ Presentation::Presentation() {
#if defined(PLATFORM_MACOS) #if defined(PLATFORM_MACOS)
Application::Cocoa::onAbout([&] { about.doActivate(); }); Application::Cocoa::onAbout([&] { about.doActivate(); });
Application::Cocoa::onActivate([&] { setFocused(); }); Application::Cocoa::onActivate([&] { setFocused(); });
Application::Cocoa::onPreferences([&] { settingsWindow->show(2); }); Application::Cocoa::onPreferences([&] { settingsWindow.show(2); });
Application::Cocoa::onQuit([&] { doClose(); }); Application::Cocoa::onQuit([&] { doClose(); });
#endif #endif
} }
@ -210,7 +208,7 @@ auto Presentation::updateStatusIcon() -> void {
icon.fill(0xff202020); icon.fill(0xff202020);
if(emulator->loaded()) { if(emulator->loaded()) {
image emblem{program->verified() ? Icon::Emblem::Program : Icon::Emblem::Binary}; image emblem{program.verified() ? Icon::Emblem::Program : Icon::Emblem::Binary};
icon.impose(image::blend::sourceAlpha, 0, (StatusHeight - 16) / 2, emblem, 0, 0, 16, 16); icon.impose(image::blend::sourceAlpha, 0, (StatusHeight - 16) / 2, emblem, 0, 0, 16, 16);
} }
@ -440,13 +438,13 @@ auto Presentation::updateSizeMenu() -> void {
} }
auto Presentation::updateStateMenus() -> void { auto Presentation::updateStateMenus() -> void {
auto states = program->availableStates("quick/"); auto states = program.availableStates("quick/");
for(auto& action : saveState.actions()) { for(auto& action : saveState.actions()) {
if(auto item = action.cast<MenuItem>()) { if(auto item = action.cast<MenuItem>()) {
if(auto name = item.property("name")) { if(auto name = item.property("name")) {
if(states.find(name)) { if(states.find(name)) {
auto timestamp = program->stateTimestamp(item.property("name")); auto timestamp = program.stateTimestamp(item.property("name"));
item.setText({item.property("title"), " [", chrono::local::datetime(timestamp), "]"}); item.setText({item.property("title"), " [", chrono::local::datetime(timestamp), "]"});
} else { } else {
item.setText({item.property("title"), " [Empty]"}); item.setText({item.property("title"), " [Empty]"});
@ -459,7 +457,7 @@ auto Presentation::updateStateMenus() -> void {
if(auto item = action.cast<MenuItem>()) { if(auto item = action.cast<MenuItem>()) {
if(auto name = item.property("name")) { if(auto name = item.property("name")) {
if(states.find(name)) { if(states.find(name)) {
auto timestamp = program->stateTimestamp(item.property("name")); auto timestamp = program.stateTimestamp(item.property("name"));
item.setEnabled(true); item.setEnabled(true);
item.setText({item.property("title"), " [", chrono::local::datetime(timestamp), "]"}); item.setText({item.property("title"), " [", chrono::local::datetime(timestamp), "]"});
} else { } else {
@ -509,8 +507,8 @@ auto Presentation::updateRecentGames() -> void {
item.setIcon(games(0).endsWith("/") ? Icon::Action::Open : Icon::Emblem::File); item.setIcon(games(0).endsWith("/") ? Icon::Action::Open : Icon::Emblem::File);
item.setText(displayName); item.setText(displayName);
item.onActivate([=] { item.onActivate([=] {
program->gameQueue = games; program.gameQueue = games;
program->load(); program.load();
}); });
} else { } else {
item.setText({"[", tr("Empty"), "]"}); item.setText({"[", tr("Empty"), "]"});
@ -551,14 +549,14 @@ auto Presentation::updateShaders() -> void {
MenuRadioItem none{&shaderMenu}; MenuRadioItem none{&shaderMenu};
none.setText("None").onActivate([&] { none.setText("None").onActivate([&] {
settings["Video/Shader"].setValue("None"); settings["Video/Shader"].setValue("None");
program->updateVideoShader(); program.updateVideoShader();
}); });
shaders.append(none); shaders.append(none);
MenuRadioItem blur{&shaderMenu}; MenuRadioItem blur{&shaderMenu};
blur.setText("Blur").onActivate([&] { blur.setText("Blur").onActivate([&] {
settings["Video/Shader"].setValue("Blur"); settings["Video/Shader"].setValue("Blur");
program->updateVideoShader(); program.updateVideoShader();
}); });
shaders.append(blur); shaders.append(blur);
@ -570,7 +568,7 @@ auto Presentation::updateShaders() -> void {
MenuRadioItem item{&shaderMenu}; MenuRadioItem item{&shaderMenu};
item.setText(string{shader}.trimRight(".shader/", 1L)).onActivate([=] { item.setText(string{shader}.trimRight(".shader/", 1L)).onActivate([=] {
settings["Video/Shader"].setValue({location, shader}); settings["Video/Shader"].setValue({location, shader});
program->updateVideoShader(); program.updateVideoShader();
}); });
shaders.append(item); shaders.append(item);
} }

View File

@ -20,11 +20,11 @@ struct AboutWindow : Window {
struct Presentation : Window { struct Presentation : Window {
Application::Namespace tr{"Presentation"}; Application::Namespace tr{"Presentation"};
auto create() -> void;
enum : uint { RecentGames = 9, QuickStates = 9 }; enum : uint { RecentGames = 9, QuickStates = 9 };
enum : uint { StatusHeight = 24 }; enum : uint { StatusHeight = 24 };
Presentation();
auto updateStatusIcon() -> void; auto updateStatusIcon() -> void;
auto drawIcon(uint32_t* output, uint length, uint width, uint height) -> void; auto drawIcon(uint32_t* output, uint length, uint width, uint height) -> void;
auto clearViewport() -> void; auto clearViewport() -> void;
@ -75,7 +75,7 @@ struct Presentation : Window {
MenuItem inputSettings{&settingsMenu}; MenuItem inputSettings{&settingsMenu};
MenuItem hotkeySettings{&settingsMenu}; MenuItem hotkeySettings{&settingsMenu};
MenuItem pathSettings{&settingsMenu}; MenuItem pathSettings{&settingsMenu};
MenuItem configurationSettings{&settingsMenu}; MenuItem emulatorSettings{&settingsMenu};
MenuItem driverSettings{&settingsMenu}; MenuItem driverSettings{&settingsMenu};
Menu toolsMenu{&menuBar}; Menu toolsMenu{&menuBar};
Menu saveState{&toolsMenu}; Menu saveState{&toolsMenu};
@ -113,4 +113,4 @@ struct Presentation : Window {
}; };
extern AboutWindow aboutWindow; extern AboutWindow aboutWindow;
extern unique_pointer<Presentation> presentation; extern Presentation presentation;

View File

@ -1,7 +1,7 @@
auto Program::updateAudioDriver(Window parent) -> void { auto Program::updateAudioDriver(Window parent) -> void {
auto changed = (bool)audio; auto changed = (bool)audio;
audio.create(settings["Audio/Driver"].text()); audio.create(settings["Audio/Driver"].text());
audio.setContext(presentation->viewport.handle()); audio.setContext(presentation.viewport.handle());
audio.setChannels(2); audio.setChannels(2);
if(changed) { if(changed) {
settings["Audio/Device"].setValue(audio.device()); settings["Audio/Device"].setValue(audio.device());
@ -54,7 +54,7 @@ auto Program::updateAudioFrequency() -> void {
} }
audio.setFrequency(settings["Audio/Frequency"].real()); audio.setFrequency(settings["Audio/Frequency"].real());
double frequency = settings["Audio/Frequency"].real() + settings["Audio/Skew"].integer(); double frequency = settings["Audio/Frequency"].real() + settings["Audio/Skew"].integer();
for(auto item : presentation->speedGroup.objects<MenuRadioItem>()) { for(auto item : presentation.speedGroup.objects<MenuRadioItem>()) {
if(item.checked()) frequency *= item.property("multiplier").real(); if(item.checked()) frequency *= item.property("multiplier").real();
} }
Emulator::audio.setFrequency(frequency); Emulator::audio.setFrequency(frequency);

View File

@ -3,14 +3,14 @@ auto Program::load() -> void {
if(auto configuration = string::read(locate("configuration.bml"))) { if(auto configuration = string::read(locate("configuration.bml"))) {
emulator->configure(configuration); emulator->configure(configuration);
settingsWindow->configuration.updateConfiguration(); emulatorSettings.updateConfiguration();
} }
if(!emulator->load()) return; if(!emulator->load()) return;
gameQueue = {}; gameQueue = {};
screenshot = {}; screenshot = {};
frameAdvance = false; frameAdvance = false;
if(!verified() && settingsWindow->configuration.warnOnUnverifiedGames.checked()) { if(!verified() && emulatorSettings.warnOnUnverifiedGames.checked()) {
auto response = MessageDialog( auto response = MessageDialog(
"Warning: this game image is unverified.\n" "Warning: this game image is unverified.\n"
"Running it *may* be a security risk.\n\n" "Running it *may* be a security risk.\n\n"
@ -21,37 +21,37 @@ auto Program::load() -> void {
return showMessage("Game loading cancelled"); return showMessage("Game loading cancelled");
} }
if(response == "Always") { if(response == "Always") {
settingsWindow->configuration.warnOnUnverifiedGames.setChecked(false).doToggle(); emulatorSettings.warnOnUnverifiedGames.setChecked(false).doToggle();
} }
} }
hackCompatibility(); hackCompatibility();
emulator->power(); emulator->power();
if(settingsWindow->configuration.autoLoadStateOnLoad.checked()) { if(emulatorSettings.autoLoadStateOnLoad.checked()) {
program->loadState("quick/undo"); program.loadState("quick/undo");
} }
showMessage({ showMessage({
verified() ? "Verified game loaded" : "Game loaded", verified() ? "Verified game loaded" : "Game loaded",
appliedPatch() ? " and patch applied" : "" appliedPatch() ? " and patch applied" : ""
}); });
presentation->setTitle(emulator->titles().merge(" + ")); presentation.setTitle(emulator->titles().merge(" + "));
presentation->resetSystem.setEnabled(true); presentation.resetSystem.setEnabled(true);
presentation->unloadGame.setEnabled(true); presentation.unloadGame.setEnabled(true);
presentation->toolsMenu.setVisible(true); presentation.toolsMenu.setVisible(true);
presentation->updateStateMenus(); presentation.updateStateMenus();
presentation->speedNormal.setChecked(); presentation.speedNormal.setChecked();
presentation->pauseEmulation.setChecked(false); presentation.pauseEmulation.setChecked(false);
presentation->updateStatusIcon(); presentation.updateStatusIcon();
presentation->resizeViewport(); presentation.resizeViewport();
toolsWindow->cheatEditor.loadCheats(); cheatEditor.loadCheats();
toolsWindow->stateManager.loadStates(); stateManager.loadStates();
toolsWindow->manifestViewer.loadManifest(); manifestViewer.loadManifest();
string locations = superFamicom.location; string locations = superFamicom.location;
if(auto& location = gameBoy.location) locations.append("|", location); if(auto& location = gameBoy.location) locations.append("|", location);
if(auto& location = bsMemory.location) locations.append("|", location); if(auto& location = bsMemory.location) locations.append("|", location);
if(auto& location = sufamiTurboA.location) locations.append("|", location); if(auto& location = sufamiTurboA.location) locations.append("|", location);
if(auto& location = sufamiTurboB.location) locations.append("|", location); if(auto& location = sufamiTurboB.location) locations.append("|", location);
presentation->addRecentGame(locations); presentation.addRecentGame(locations);
updateVideoPalette(); updateVideoPalette();
updateAudioEffects(); updateAudioEffects();
@ -283,9 +283,9 @@ auto Program::reset() -> void {
auto Program::unload() -> void { auto Program::unload() -> void {
if(!emulator->loaded()) return; if(!emulator->loaded()) return;
toolsWindow->cheatEditor.saveCheats(); cheatEditor.saveCheats();
toolsWindow->setVisible(false); toolsWindow.setVisible(false);
if(settingsWindow->configuration.autoSaveStateOnUnload.checked()) { if(emulatorSettings.autoSaveStateOnUnload.checked()) {
saveUndoState(); saveUndoState();
} }
if(auto configuration = emulator->configuration()) { if(auto configuration = emulator->configuration()) {
@ -298,12 +298,12 @@ auto Program::unload() -> void {
bsMemory = {}; bsMemory = {};
sufamiTurboA = {}; sufamiTurboA = {};
sufamiTurboB = {}; sufamiTurboB = {};
presentation->setTitle({"bsnes v", Emulator::Version}); presentation.setTitle({"bsnes v", Emulator::Version});
presentation->resetSystem.setEnabled(false); presentation.resetSystem.setEnabled(false);
presentation->unloadGame.setEnabled(false); presentation.unloadGame.setEnabled(false);
presentation->toolsMenu.setVisible(false); presentation.toolsMenu.setVisible(false);
presentation->updateStatusIcon(); presentation.updateStatusIcon();
presentation->clearViewport(); presentation.clearViewport();
} }
//a game is considered verified if the game plus its slot(s) are found in the games database //a game is considered verified if the game plus its slot(s) are found in the games database

View File

@ -1,14 +1,15 @@
auto Program::hackCompatibility() -> void { auto Program::hackCompatibility() -> void {
bool fastPPU = settingsWindow->configuration.fastPPUOption.checked(); bool fastPPU = emulatorSettings.fastPPUOption.checked();
bool fastPPUNoSpriteLimit = settingsWindow->configuration.noSpriteLimit.checked(); bool fastPPUNoSpriteLimit = emulatorSettings.noSpriteLimit.checked();
bool fastPPUHiresMode7 = settingsWindow->configuration.hiresMode7.checked(); bool fastPPUHiresMode7 = emulatorSettings.hiresMode7.checked();
bool fastDSP = settingsWindow->configuration.fastDSPOption.checked(); bool fastDSP = emulatorSettings.fastDSPOption.checked();
auto label = superFamicom.label; auto label = superFamicom.label;
if(label == "AIR STRIKE PATROL" || label == "DESERT FIGHTER") fastPPU = false; if(label == "AIR STRIKE PATROL" || label == "DESERT FIGHTER") fastPPU = false;
if(label == "KOUSHIEN_2") fastDSP = false; if(label == "KOUSHIEN_2") fastDSP = false;
if(label == "RENDERING RANGER R2") fastDSP = false; if(label == "RENDERING RANGER R2") fastDSP = false;
//todo: update to new emulator->configuration API
emulator->set("Fast PPU", fastPPU); emulator->set("Fast PPU", fastPPU);
emulator->set("Fast PPU/No Sprite Limit", fastPPUNoSpriteLimit); emulator->set("Fast PPU/No Sprite Limit", fastPPUNoSpriteLimit);
emulator->set("Fast PPU/Hires Mode 7", fastPPUHiresMode7); emulator->set("Fast PPU/Hires Mode 7", fastPPUHiresMode7);
@ -33,7 +34,7 @@ auto Program::hackPatchMemory(vector<uint8_t>& data) -> void {
auto Program::hackOverclockSuperFX() -> void { auto Program::hackOverclockSuperFX() -> void {
//todo: implement a better way of detecting SuperFX games //todo: implement a better way of detecting SuperFX games
//todo: apply multiplier changes on reset, not just on game load? //todo: apply multiplier changes on reset, not just on game load?
double multiplier = settingsWindow->configuration.superFXValue.text().natural() / 100.0; double multiplier = emulatorSettings.superFXValue.text().natural() / 100.0;
if(multiplier == 1.0) return; if(multiplier == 1.0) return;
auto label = superFamicom.label; auto label = superFamicom.label;

View File

@ -1,13 +1,13 @@
auto Program::updateInputDriver(Window parent) -> void { auto Program::updateInputDriver(Window parent) -> void {
auto changed = (bool)input; auto changed = (bool)input;
input.create(settings["Input/Driver"].text()); input.create(settings["Input/Driver"].text());
input.setContext(presentation->viewport.handle()); input.setContext(presentation.viewport.handle());
if(changed) { if(changed) {
} }
inputManager->initialize(); inputManager.initialize();
settingsWindow->input.reloadPorts(); inputSettings.reloadPorts();
settingsWindow->hotkeys.reloadMappings(); hotkeySettings.reloadMappings();
if(!input.ready()) { if(!input.ready()) {
MessageDialog({ MessageDialog({

View File

@ -92,7 +92,7 @@ auto Program::open(uint id, string name, vfs::file::mode mode, bool required) ->
"Error: missing required data: ", name, "\n\n", "Error: missing required data: ", name, "\n\n",
"Would you like to view the online documentation for more information?" "Would you like to view the online documentation for more information?"
}).setParent(*presentation).error({"Yes", "No"}) == "Yes") { }).setParent(*presentation).error({"Yes", "No"}) == "Yes") {
presentation->documentation.doActivate(); presentation.documentation.doActivate();
} }
} }
@ -197,7 +197,7 @@ auto Program::videoRefresh(uint display, const uint32* data, uint pitch, uint wi
uint length; uint length;
pitch >>= 2; pitch >>= 2;
if(presentation->overscanCropping.checked()) { if(presentation.overscanCropping.checked()) {
if(height == 240) data += 8 * pitch, height -= 16; if(height == 240) data += 8 * pitch, height -= 16;
if(height == 480) data += 16 * pitch, height -= 32; if(height == 480) data += 16 * pitch, height -= 32;
} }
@ -221,11 +221,11 @@ auto Program::videoRefresh(uint display, const uint32* data, uint pitch, uint wi
video.output(); video.output();
} }
inputManager->frame(); inputManager.frame();
if(frameAdvance) { if(frameAdvance) {
frameAdvance = false; frameAdvance = false;
presentation->pauseEmulation.setChecked(); presentation.pauseEmulation.setChecked();
} }
static uint frameCounter = 0; static uint frameCounter = 0;
@ -245,9 +245,9 @@ auto Program::audioSample(const double* samples, uint channels) -> void {
} }
auto Program::inputPoll(uint port, uint device, uint input) -> int16 { auto Program::inputPoll(uint port, uint device, uint input) -> int16 {
if(focused() || settingsWindow->configuration.allowInput().checked()) { if(focused() || emulatorSettings.allowInput().checked()) {
inputManager->poll(); inputManager.poll();
if(auto mapping = inputManager->mapping(port, device, input)) { if(auto mapping = inputManager.mapping(port, device, input)) {
return mapping->poll(); return mapping->poll();
} }
} }
@ -255,8 +255,8 @@ auto Program::inputPoll(uint port, uint device, uint input) -> int16 {
} }
auto Program::inputRumble(uint port, uint device, uint input, bool enable) -> void { auto Program::inputRumble(uint port, uint device, uint input, bool enable) -> void {
if(focused() || settingsWindow->configuration.allowInput().checked() || !enable) { if(focused() || emulatorSettings.allowInput().checked() || !enable) {
if(auto mapping = inputManager->mapping(port, device, input)) { if(auto mapping = inputManager.mapping(port, device, input)) {
return mapping->rumble(enable); return mapping->rumble(enable);
} }
} }

View File

@ -11,22 +11,31 @@
#include "utility.cpp" #include "utility.cpp"
#include "patch.cpp" #include "patch.cpp"
#include "hacks.cpp" #include "hacks.cpp"
unique_pointer<Program> program; Program program;
Program::Program(vector<string> arguments) { auto Program::create(vector<string> arguments) -> void {
program = this;
Emulator::platform = this; Emulator::platform = this;
new Presentation;
presentation->setVisible();
new InputManager;
new SettingsWindow;
new CheatDatabase;
new CheatWindow;
new StateWindow;
new ToolsWindow;
aboutWindow.create(); aboutWindow.create();
presentation.create();
presentation.setVisible();
videoSettings.create();
audioSettings.create();
inputSettings.create();
hotkeySettings.create();
pathSettings.create();
emulatorSettings.create();
driverSettings.create();
settingsWindow.create();
cheatDatabase.create();
cheatWindow.create();
cheatEditor.create();
stateWindow.create();
stateManager.create();
manifestViewer.create();
toolsWindow.create();
if(settings["Crashed"].boolean()) { if(settings["Crashed"].boolean()) {
MessageDialog( MessageDialog(
@ -40,20 +49,20 @@ Program::Program(vector<string> arguments) {
settings["Crashed"].setValue(true); settings["Crashed"].setValue(true);
settings.save(); settings.save();
updateVideoDriver(*presentation); updateVideoDriver(presentation);
updateAudioDriver(*presentation); updateAudioDriver(presentation);
updateInputDriver(*presentation); updateInputDriver(presentation);
settings["Crashed"].setValue(false); settings["Crashed"].setValue(false);
settings.save(); settings.save();
settingsWindow->drivers.videoDriverChanged(); driverSettings.videoDriverChanged();
settingsWindow->drivers.audioDriverChanged(); driverSettings.audioDriverChanged();
settingsWindow->drivers.inputDriverChanged(); driverSettings.inputDriverChanged();
arguments.takeLeft(); //ignore program location in argument parsing arguments.takeLeft(); //ignore program location in argument parsing
for(auto& argument : arguments) { for(auto& argument : arguments) {
if(argument == "--fullscreen") { if(argument == "--fullscreen") {
presentation->toggleFullscreenMode(); presentation.toggleFullscreenMode();
} else if(inode::exists(argument)) { } else if(inode::exists(argument)) {
gameQueue.append(argument); gameQueue.append(argument);
} }
@ -68,8 +77,8 @@ auto Program::main() -> void {
updateStatus(); updateStatus();
video.poll(); video.poll();
inputManager->poll(); inputManager.poll();
inputManager->pollHotkeys(); inputManager.pollHotkeys();
if(paused()) { if(paused()) {
audio.clear(); audio.clear();
@ -78,7 +87,7 @@ auto Program::main() -> void {
} }
emulator->run(); emulator->run();
if(settingsWindow->configuration.autoSaveMemory.checked()) { if(emulatorSettings.autoSaveMemory.checked()) {
auto currentTime = chrono::timestamp(); auto currentTime = chrono::timestamp();
if(currentTime - autoSaveTime >= settings["Emulator/AutoSaveMemory/Interval"].natural()) { if(currentTime - autoSaveTime >= settings["Emulator/AutoSaveMemory/Interval"].natural()) {
autoSaveTime = currentTime; autoSaveTime = currentTime;

View File

@ -2,7 +2,7 @@ struct Program : Emulator::Platform {
Application::Namespace tr{"Program"}; Application::Namespace tr{"Program"};
//program.cpp //program.cpp
Program(vector<string> arguments); auto create(vector<string> arguments) -> void;
auto main() -> void; auto main() -> void;
auto quit() -> void; auto quit() -> void;
@ -147,4 +147,4 @@ public:
string statusFrameRate; string statusFrameRate;
}; };
extern unique_pointer<Program> program; extern Program program;

View File

@ -108,7 +108,7 @@ auto Program::saveState(string filename) -> bool {
output.append(location, s.data(), s.size()); output.append(location, s.data(), s.size());
} }
if(filename.beginsWith("quick/")) presentation->updateStateMenus(); if(filename.beginsWith("quick/")) presentation.updateStateMenus();
return showMessage({"Saved [", prefix, "]"}), true; return showMessage({"Saved [", prefix, "]"}), true;
} }

View File

@ -12,22 +12,22 @@ auto Program::updateStatus() -> void {
if(chrono::timestamp() - statusTime <= 2) { if(chrono::timestamp() - statusTime <= 2) {
message = statusMessage; message = statusMessage;
} }
if(message != presentation->statusLeft.text()) { if(message != presentation.statusLeft.text()) {
presentation->statusLeft.setText(message); presentation.statusLeft.setText(message);
} }
string frameRate; string frameRate;
if(!emulator->loaded()) { if(!emulator->loaded()) {
frameRate = tr("Unloaded"); frameRate = tr("Unloaded");
} else if(presentation->pauseEmulation.checked()) { } else if(presentation.pauseEmulation.checked()) {
frameRate = tr("Paused"); frameRate = tr("Paused");
} else if(!focused() && settingsWindow->configuration.pauseEmulation.checked()) { } else if(!focused() && emulatorSettings.pauseEmulation.checked()) {
frameRate = tr("Paused"); frameRate = tr("Paused");
} else { } else {
frameRate = statusFrameRate; frameRate = statusFrameRate;
} }
if(frameRate != presentation->statusRight.text()) { if(frameRate != presentation.statusRight.text()) {
presentation->statusRight.setText(frameRate); presentation.statusRight.setText(frameRate);
} }
} }
@ -47,14 +47,14 @@ auto Program::captureScreenshot() -> bool {
auto Program::paused() -> bool { auto Program::paused() -> bool {
if(!emulator->loaded()) return true; if(!emulator->loaded()) return true;
if(presentation->pauseEmulation.checked()) return true; if(presentation.pauseEmulation.checked()) return true;
if(!focused() && settingsWindow->configuration.pauseEmulation.checked()) return true; if(!focused() && emulatorSettings.pauseEmulation.checked()) return true;
return false; return false;
} }
auto Program::focused() -> bool { auto Program::focused() -> bool {
//exclusive mode creates its own top-level window: presentation window will not have focus //exclusive mode creates its own top-level window: presentation window will not have focus
if(video && video.exclusive()) return true; if(video && video.exclusive()) return true;
if(presentation && presentation->focused()) return true; if(presentation.focused()) return true;
return false; return false;
} }

View File

@ -1,7 +1,7 @@
auto Program::updateVideoDriver(Window parent) -> void { auto Program::updateVideoDriver(Window parent) -> void {
auto changed = (bool)video; auto changed = (bool)video;
video.create(settings["Video/Driver"].text()); video.create(settings["Video/Driver"].text());
video.setContext(presentation->viewport.handle()); video.setContext(presentation.viewport.handle());
if(changed) { if(changed) {
settings["Video/Format"].setValue(video.format()); settings["Video/Format"].setValue(video.format());
} }
@ -12,12 +12,12 @@ auto Program::updateVideoDriver(Window parent) -> void {
updateVideoShader(); updateVideoShader();
if(video.ready()) { if(video.ready()) {
presentation->clearViewport(); presentation.clearViewport();
updateVideoShader(); updateVideoShader();
} }
video.onUpdate([&](uint width, uint height) { video.onUpdate([&](uint width, uint height) {
if(!emulator->loaded()) presentation->clearViewport(); if(!emulator->loaded()) presentation.clearViewport();
}); });
if(!video.ready()) { if(!video.ready()) {
@ -28,7 +28,7 @@ auto Program::updateVideoDriver(Window parent) -> void {
return updateVideoDriver(parent); return updateVideoDriver(parent);
} }
presentation->updateShaders(); presentation.updateShaders();
} }
auto Program::updateVideoExclusive() -> void { auto Program::updateVideoExclusive() -> void {

View File

@ -1,4 +1,4 @@
AudioSettings::AudioSettings(TabFrame* parent) : TabFrameItem(parent) { auto AudioSettings::create() -> void {
setIcon(Icon::Device::Speaker); setIcon(Icon::Device::Speaker);
setText("Audio"); setText("Audio");
@ -13,7 +13,7 @@ AudioSettings::AudioSettings(TabFrame* parent) : TabFrameItem(parent) {
string value = {skewSlider.position() > 5000 ? "+" : "", (int)skewSlider.position() - 5000}; string value = {skewSlider.position() > 5000 ? "+" : "", (int)skewSlider.position() - 5000};
settings["Audio/Skew"].setValue(value); settings["Audio/Skew"].setValue(value);
skewValue.setText(value); skewValue.setText(value);
if(audio) program->updateAudioFrequency(); program.updateAudioFrequency();
}).doChange(); }).doChange();
volumeLabel.setText("Volume:"); volumeLabel.setText("Volume:");
volumeValue.setAlignment(0.5); volumeValue.setAlignment(0.5);
@ -21,7 +21,7 @@ AudioSettings::AudioSettings(TabFrame* parent) : TabFrameItem(parent) {
string value = {volumeSlider.position(), "%"}; string value = {volumeSlider.position(), "%"};
settings["Audio/Volume"].setValue(value); settings["Audio/Volume"].setValue(value);
volumeValue.setText(value); volumeValue.setText(value);
if(audio) program->updateAudioEffects(); program.updateAudioEffects();
}).doChange(); }).doChange();
balanceLabel.setText("Balance:"); balanceLabel.setText("Balance:");
balanceValue.setAlignment(0.5); balanceValue.setAlignment(0.5);
@ -29,6 +29,6 @@ AudioSettings::AudioSettings(TabFrame* parent) : TabFrameItem(parent) {
string value = {balanceSlider.position(), "%"}; string value = {balanceSlider.position(), "%"};
settings["Audio/Balance"].setValue(value); settings["Audio/Balance"].setValue(value);
balanceValue.setText(value); balanceValue.setText(value);
if(audio) program->updateAudioEffects(); program.updateAudioEffects();
}).doChange(); }).doChange();
} }

View File

@ -1,4 +1,4 @@
DriverSettings::DriverSettings(TabFrame* parent) : TabFrameItem(parent) { auto DriverSettings::create() -> void {
setIcon(Icon::Place::Settings); setIcon(Icon::Place::Settings);
setText("Drivers"); setText("Drivers");
@ -8,29 +8,29 @@ DriverSettings::DriverSettings(TabFrame* parent) : TabFrameItem(parent) {
videoLayout.setSize({2, 2}); videoLayout.setSize({2, 2});
videoDriverLabel.setText("Driver:"); videoDriverLabel.setText("Driver:");
videoDriverOption.onChange([&] { videoDriverOption.onChange([&] {
videoDriverUpdate.setEnabled(videoDriverOption.selected().text() != video.driverName()); videoDriverUpdate.setEnabled(videoDriverOption.selected().text() != video.driver());
}); });
videoDriverUpdate.setText("Change").onActivate([&] { videoDriverChange(); }); videoDriverUpdate.setText("Change").onActivate([&] { videoDriverChange(); });
videoFormatLabel.setText("Format:"); videoFormatLabel.setText("Format:");
videoFormatOption.onChange([&] { videoFormatChange(); }); videoFormatOption.onChange([&] { videoFormatChange(); });
videoExclusiveToggle.setText("Exclusive fullscreen").onToggle([&] { videoExclusiveToggle.setText("Exclusive fullscreen").onToggle([&] {
settings["Video/Exclusive"].setValue(videoExclusiveToggle.checked()); settings["Video/Exclusive"].setValue(videoExclusiveToggle.checked());
program->updateVideoExclusive(); program.updateVideoExclusive();
}); });
videoBlockingToggle.setText("Synchronize").onToggle([&] { videoBlockingToggle.setText("Synchronize").onToggle([&] {
settings["Video/Blocking"].setValue(videoBlockingToggle.checked()); settings["Video/Blocking"].setValue(videoBlockingToggle.checked());
program->updateVideoBlocking(); program.updateVideoBlocking();
}); });
videoFlushToggle.setText("GPU sync").onToggle([&] { videoFlushToggle.setText("GPU sync").onToggle([&] {
settings["Video/Flush"].setValue(videoFlushToggle.checked()); settings["Video/Flush"].setValue(videoFlushToggle.checked());
program->updateVideoFlush(); program.updateVideoFlush();
}); });
audioLabel.setText("Audio").setFont(Font().setBold()); audioLabel.setText("Audio").setFont(Font().setBold());
audioLayout.setSize({2, 2}); audioLayout.setSize({2, 2});
audioDriverLabel.setText("Driver:"); audioDriverLabel.setText("Driver:");
audioDriverOption.onChange([&] { audioDriverOption.onChange([&] {
audioDriverUpdate.setEnabled(audioDriverOption.selected().text() != audio.driverName()); audioDriverUpdate.setEnabled(audioDriverOption.selected().text() != audio.driver());
}); });
audioDriverUpdate.setText("Change").onActivate([&] { audioDriverChange(); }); audioDriverUpdate.setText("Change").onActivate([&] { audioDriverChange(); });
audioDeviceLabel.setText("Device:"); audioDeviceLabel.setText("Device:");
@ -41,29 +41,29 @@ DriverSettings::DriverSettings(TabFrame* parent) : TabFrameItem(parent) {
audioLatencyOption.onChange([&] { audioLatencyChange(); }); audioLatencyOption.onChange([&] { audioLatencyChange(); });
audioExclusiveToggle.setText("Exclusive").onToggle([&] { audioExclusiveToggle.setText("Exclusive").onToggle([&] {
settings["Audio/Exclusive"].setValue(audioExclusiveToggle.checked()); settings["Audio/Exclusive"].setValue(audioExclusiveToggle.checked());
program->updateAudioExclusive(); program.updateAudioExclusive();
}); });
audioBlockingToggle.setText("Synchronize").onToggle([&] { audioBlockingToggle.setText("Synchronize").onToggle([&] {
settings["Audio/Blocking"].setValue(audioBlockingToggle.checked()); settings["Audio/Blocking"].setValue(audioBlockingToggle.checked());
program->updateAudioBlocking(); program.updateAudioBlocking();
}); });
audioDynamicToggle.setText("Dynamic rate").onToggle([&] { audioDynamicToggle.setText("Dynamic rate").onToggle([&] {
settings["Audio/Dynamic"].setValue(audioDynamicToggle.checked()); settings["Audio/Dynamic"].setValue(audioDynamicToggle.checked());
program->updateAudioDynamic(); program.updateAudioDynamic();
}); });
inputLabel.setText("Input").setFont(Font().setBold()); inputLabel.setText("Input").setFont(Font().setBold());
inputLayout.setSize({2, 1}); inputLayout.setSize({2, 1});
inputDriverLabel.setText("Driver:"); inputDriverLabel.setText("Driver:");
inputDriverOption.onChange([&] { inputDriverOption.onChange([&] {
inputDriverUpdate.setEnabled(inputDriverOption.selected().text() != input.driverName()); inputDriverUpdate.setEnabled(inputDriverOption.selected().text() != input.driver());
}); });
inputDriverUpdate.setText("Change").onActivate([&] { inputDriverChange(); }); inputDriverUpdate.setText("Change").onActivate([&] { inputDriverChange(); });
//hide video format for simplicity, as it's not very useful just yet ... //this will hide the video format setting for simplicity, as it's not very useful just yet ...
videoLayout.setSize({2, 1}); //videoLayout.setSize({2, 1});
videoLayout.remove(videoFormatLabel); //videoLayout.remove(videoFormatLabel);
videoLayout.remove(videoPropertyLayout); //videoLayout.remove(videoPropertyLayout);
} }
// //
@ -73,9 +73,9 @@ auto DriverSettings::videoDriverChanged() -> void {
for(auto& driver : video.hasDrivers()) { for(auto& driver : video.hasDrivers()) {
ComboButtonItem item{&videoDriverOption}; ComboButtonItem item{&videoDriverOption};
item.setText(driver); item.setText(driver);
if(driver == video.driverName()) item.setSelected(); if(driver == video.driver()) item.setSelected();
} }
videoDriverActive.setText({"Active driver: ", video.driverName()}); videoDriverActive.setText({"Active driver: ", video.driver()});
videoDriverOption.doChange(); videoDriverOption.doChange();
videoFormatChanged(); videoFormatChanged();
videoExclusiveToggle.setChecked(video.exclusive()).setEnabled(video.hasExclusive()); videoExclusiveToggle.setChecked(video.exclusive()).setEnabled(video.hasExclusive());
@ -92,11 +92,11 @@ auto DriverSettings::videoDriverChange() -> void {
"It is highly recommended you unload your game first to be safe.\n" "It is highly recommended you unload your game first to be safe.\n"
"Do you wish to proceed with the video driver change now anyway?" "Do you wish to proceed with the video driver change now anyway?"
).setParent(*settingsWindow).question() == "Yes") { ).setParent(*settingsWindow).question() == "Yes") {
program->save(); program.save();
program->saveUndoState(); program.saveUndoState();
settings["Crashed"].setValue(true); settings["Crashed"].setValue(true);
settings.save(); settings.save();
program->updateVideoDriver(*settingsWindow); program.updateVideoDriver(settingsWindow);
settings["Crashed"].setValue(false); settings["Crashed"].setValue(false);
settings.save(); settings.save();
videoDriverChanged(); videoDriverChanged();
@ -127,9 +127,9 @@ auto DriverSettings::audioDriverChanged() -> void {
for(auto& driver : audio.hasDrivers()) { for(auto& driver : audio.hasDrivers()) {
ComboButtonItem item{&audioDriverOption}; ComboButtonItem item{&audioDriverOption};
item.setText(driver); item.setText(driver);
if(driver == audio.driverName()) item.setSelected(); if(driver == audio.driver()) item.setSelected();
} }
audioDriverActive.setText({"Active driver: ", audio.driverName()}); audioDriverActive.setText({"Active driver: ", audio.driver()});
audioDriverOption.doChange(); audioDriverOption.doChange();
audioDeviceChanged(); audioDeviceChanged();
audioFrequencyChanged(); audioFrequencyChanged();
@ -148,11 +148,11 @@ auto DriverSettings::audioDriverChange() -> void {
"It is highly recommended you unload your game first to be safe.\n" "It is highly recommended you unload your game first to be safe.\n"
"Do you wish to proceed with the audio driver change now anyway?" "Do you wish to proceed with the audio driver change now anyway?"
).setParent(*settingsWindow).question() == "Yes") { ).setParent(*settingsWindow).question() == "Yes") {
program->save(); program.save();
program->saveUndoState(); program.saveUndoState();
settings["Crashed"].setValue(true); settings["Crashed"].setValue(true);
settings.save(); settings.save();
program->updateAudioDriver(*settingsWindow); program.updateAudioDriver(settingsWindow);
settings["Crashed"].setValue(false); settings["Crashed"].setValue(false);
settings.save(); settings.save();
audioDriverChanged(); audioDriverChanged();
@ -173,7 +173,7 @@ auto DriverSettings::audioDeviceChanged() -> void {
auto DriverSettings::audioDeviceChange() -> void { auto DriverSettings::audioDeviceChange() -> void {
auto item = audioDeviceOption.selected(); auto item = audioDeviceOption.selected();
settings["Audio/Device"].setValue(item.text()); settings["Audio/Device"].setValue(item.text());
program->updateAudioDevice(); program.updateAudioDevice();
audioFrequencyChanged(); audioFrequencyChanged();
audioLatencyChanged(); audioLatencyChanged();
} }
@ -192,7 +192,7 @@ auto DriverSettings::audioFrequencyChanged() -> void {
auto DriverSettings::audioFrequencyChange() -> void { auto DriverSettings::audioFrequencyChange() -> void {
auto item = audioFrequencyOption.selected(); auto item = audioFrequencyOption.selected();
settings["Audio/Frequency"].setValue(item.text()); settings["Audio/Frequency"].setValue(item.text());
program->updateAudioFrequency(); program.updateAudioFrequency();
} }
auto DriverSettings::audioLatencyChanged() -> void { auto DriverSettings::audioLatencyChanged() -> void {
@ -209,7 +209,7 @@ auto DriverSettings::audioLatencyChanged() -> void {
auto DriverSettings::audioLatencyChange() -> void { auto DriverSettings::audioLatencyChange() -> void {
auto item = audioLatencyOption.selected(); auto item = audioLatencyOption.selected();
settings["Audio/Latency"].setValue(item.text()); settings["Audio/Latency"].setValue(item.text());
program->updateAudioLatency(); program.updateAudioLatency();
} }
// //
@ -219,9 +219,9 @@ auto DriverSettings::inputDriverChanged() -> void {
for(auto& driver : input.hasDrivers()) { for(auto& driver : input.hasDrivers()) {
ComboButtonItem item{&inputDriverOption}; ComboButtonItem item{&inputDriverOption};
item.setText(driver); item.setText(driver);
if(driver == input.driverName()) item.setSelected(); if(driver == input.driver()) item.setSelected();
} }
inputDriverActive.setText({"Active driver: ", input.driverName()}); inputDriverActive.setText({"Active driver: ", input.driver()});
inputDriverOption.doChange(); inputDriverOption.doChange();
layout.setGeometry(layout.geometry()); layout.setGeometry(layout.geometry());
} }
@ -234,11 +234,11 @@ auto DriverSettings::inputDriverChange() -> void {
"It is highly recommended you unload your game first to be safe.\n" "It is highly recommended you unload your game first to be safe.\n"
"Do you wish to proceed with the input driver change now anyway?" "Do you wish to proceed with the input driver change now anyway?"
).setParent(*settingsWindow).question() == "Yes") { ).setParent(*settingsWindow).question() == "Yes") {
program->save(); program.save();
program->saveUndoState(); program.saveUndoState();
settings["Crashed"].setValue(true); settings["Crashed"].setValue(true);
settings.save(); settings.save();
program->updateInputDriver(*settingsWindow); program.updateInputDriver(settingsWindow);
settings["Crashed"].setValue(false); settings["Crashed"].setValue(false);
settings.save(); settings.save();
inputDriverChanged(); inputDriverChanged();

View File

@ -1,6 +1,6 @@
ConfigurationSettings::ConfigurationSettings(TabFrame* parent) : TabFrameItem(parent) { auto EmulatorSettings::create() -> void {
setIcon(Icon::Action::Settings); setIcon(Icon::Action::Settings);
setText("Configuration"); setText("Emulator");
layout.setPadding(5); layout.setPadding(5);
@ -40,7 +40,7 @@ ConfigurationSettings::ConfigurationSettings(TabFrame* parent) : TabFrameItem(pa
Application::setScreenSaver(!suppressScreenSaver.checked()); Application::setScreenSaver(!suppressScreenSaver.checked());
}); });
hacksLabel.setText("Emulator Hacks").setFont(Font().setBold()); hacksLabel.setText("Hacks").setFont(Font().setBold());
fastPPUOption.setText("Fast PPU").setChecked(settings["Emulator/Hack/FastPPU"].boolean()).onToggle([&] { fastPPUOption.setText("Fast PPU").setChecked(settings["Emulator/Hack/FastPPU"].boolean()).onToggle([&] {
settings["Emulator/Hack/FastPPU"].setValue(fastPPUOption.checked()); settings["Emulator/Hack/FastPPU"].setValue(fastPPUOption.checked());
if(!fastPPUOption.checked()) { if(!fastPPUOption.checked()) {
@ -69,7 +69,7 @@ ConfigurationSettings::ConfigurationSettings(TabFrame* parent) : TabFrameItem(pa
hacksNote.setForegroundColor({224, 0, 0}).setText("Note: some hack setting changes do not take effect until after reloading games."); hacksNote.setForegroundColor({224, 0, 0}).setText("Note: some hack setting changes do not take effect until after reloading games.");
} }
auto ConfigurationSettings::updateConfiguration() -> void { auto EmulatorSettings::updateConfiguration() -> void {
emulator->configure("hacks/ppuFast/enable", fastPPUOption.checked()); emulator->configure("hacks/ppuFast/enable", fastPPUOption.checked());
emulator->configure("hacks/ppuFast/noSpriteLimit", noSpriteLimit.checked()); emulator->configure("hacks/ppuFast/noSpriteLimit", noSpriteLimit.checked());
emulator->configure("hacks/ppuFast/hiresMode7", hiresMode7.checked()); emulator->configure("hacks/ppuFast/hiresMode7", hiresMode7.checked());

View File

@ -1,4 +1,4 @@
HotkeySettings::HotkeySettings(TabFrame* parent) : TabFrameItem(parent) { auto HotkeySettings::create() -> void {
setIcon(Icon::Device::Keyboard); setIcon(Icon::Device::Keyboard);
setText("Hotkeys"); setText("Hotkeys");
@ -17,7 +17,7 @@ HotkeySettings::HotkeySettings(TabFrame* parent) : TabFrameItem(parent) {
}); });
clearButton.setText("Clear").onActivate([&] { clearButton.setText("Clear").onActivate([&] {
for(auto item : mappingList.batched()) { for(auto item : mappingList.batched()) {
inputManager->hotkeys[item.offset()].unbind(); inputManager.hotkeys[item.offset()].unbind();
} }
refreshMappings(); refreshMappings();
}); });
@ -29,7 +29,7 @@ auto HotkeySettings::reloadMappings() -> void {
.append(TableViewColumn().setText("Name")) .append(TableViewColumn().setText("Name"))
.append(TableViewColumn().setText("Mapping").setExpandable()) .append(TableViewColumn().setText("Mapping").setExpandable())
); );
for(auto& hotkey : inputManager->hotkeys) { for(auto& hotkey : inputManager.hotkeys) {
mappingList.append(TableViewItem() mappingList.append(TableViewItem()
.append(TableViewCell().setText(hotkey.name).setFont(Font().setBold()).setBackgroundColor({240, 240, 255})) .append(TableViewCell().setText(hotkey.name).setFont(Font().setBold()).setBackgroundColor({240, 240, 255}))
.append(TableViewCell()) .append(TableViewCell())
@ -41,29 +41,29 @@ auto HotkeySettings::reloadMappings() -> void {
auto HotkeySettings::refreshMappings() -> void { auto HotkeySettings::refreshMappings() -> void {
uint index = 0; uint index = 0;
for(auto& hotkey : inputManager->hotkeys) { for(auto& hotkey : inputManager.hotkeys) {
mappingList.item(index++).cell(1).setText(hotkey.displayName()); mappingList.item(index++).cell(1).setText(hotkey.displayName());
} }
mappingList.resizeColumns(); mappingList.resizeColumns();
} }
auto HotkeySettings::assignMapping() -> void { auto HotkeySettings::assignMapping() -> void {
inputManager->poll(); //clear any pending events first inputManager.poll(); //clear any pending events first
if(auto item = mappingList.selected()) { if(auto item = mappingList.selected()) {
activeMapping = inputManager->hotkeys[item.offset()]; activeMapping = inputManager.hotkeys[item.offset()];
settingsWindow->layout.setEnabled(false); settingsWindow.layout.setEnabled(false);
settingsWindow->statusBar.setText({"Press a key or button to map [", activeMapping->name, "] ..."}); settingsWindow.statusBar.setText({"Press a key or button to map [", activeMapping->name, "] ..."});
settingsWindow->setDismissable(false); settingsWindow.setDismissable(false);
} }
} }
auto HotkeySettings::cancelMapping() -> void { auto HotkeySettings::cancelMapping() -> void {
activeMapping.reset(); activeMapping.reset();
settingsWindow->statusBar.setText(); settingsWindow.statusBar.setText();
settingsWindow->layout.setEnabled(); settingsWindow.layout.setEnabled();
settingsWindow->doSize(); settingsWindow.doSize();
settingsWindow->setDismissable(true); settingsWindow.setDismissable(true);
} }
auto HotkeySettings::inputEvent(shared_pointer<HID::Device> device, uint group, uint input, int16 oldValue, int16 newValue) -> void { auto HotkeySettings::inputEvent(shared_pointer<HID::Device> device, uint group, uint input, int16 oldValue, int16 newValue) -> void {
@ -72,7 +72,7 @@ auto HotkeySettings::inputEvent(shared_pointer<HID::Device> device, uint group,
if(activeMapping->bind(device, group, input, oldValue, newValue)) { if(activeMapping->bind(device, group, input, oldValue, newValue)) {
activeMapping.reset(); activeMapping.reset();
settingsWindow->statusBar.setText("Mapping assigned."); settingsWindow.statusBar.setText("Mapping assigned.");
refreshMappings(); refreshMappings();
timer.onActivate([&] { timer.onActivate([&] {
timer.setEnabled(false); timer.setEnabled(false);

View File

@ -1,4 +1,4 @@
InputSettings::InputSettings(TabFrame* parent) : TabFrameItem(parent) { auto InputSettings::create() -> void {
setIcon(Icon::Device::Joypad); setIcon(Icon::Device::Joypad);
setText("Input"); setText("Input");
@ -16,8 +16,8 @@ InputSettings::InputSettings(TabFrame* parent) : TabFrameItem(parent) {
turboList.onChange([&] { turboList.onChange([&] {
uint frequency = turboList.selected().text().natural(); uint frequency = turboList.selected().text().natural();
settings["Input/Turbo/Frequency"].setValue(frequency); settings["Input/Turbo/Frequency"].setValue(frequency);
inputManager->turboCounter = 0; inputManager.turboCounter = 0;
inputManager->turboFrequency = frequency; inputManager.turboFrequency = frequency;
}); });
mappingList.setBatchable(); mappingList.setBatchable();
mappingList.onActivate([&] { if(assignButton.enabled()) assignButton.doActivate(); }); mappingList.onActivate([&] { if(assignButton.enabled()) assignButton.doActivate(); });
@ -58,7 +58,7 @@ auto InputSettings::updateControls() -> void {
} }
auto InputSettings::activePort() -> InputPort& { auto InputSettings::activePort() -> InputPort& {
return inputManager->ports[portList.selected().offset()]; return inputManager.ports[portList.selected().offset()];
} }
auto InputSettings::activeDevice() -> InputDevice& { auto InputSettings::activeDevice() -> InputDevice& {
@ -68,7 +68,7 @@ auto InputSettings::activeDevice() -> InputDevice& {
auto InputSettings::reloadPorts() -> void { auto InputSettings::reloadPorts() -> void {
portList.reset(); portList.reset();
for(auto& port : inputManager->ports) { for(auto& port : inputManager.ports) {
if(port.name == "Expansion Port") continue; if(port.name == "Expansion Port") continue;
portList.append(ComboButtonItem().setText(port.name)); portList.append(ComboButtonItem().setText(port.name));
} }
@ -113,28 +113,28 @@ auto InputSettings::refreshMappings() -> void {
} }
auto InputSettings::assignMapping() -> void { auto InputSettings::assignMapping() -> void {
inputManager->poll(); //clear any pending events first inputManager.poll(); //clear any pending events first
for(auto mapping : mappingList.batched()) { for(auto mapping : mappingList.batched()) {
activeMapping = activeDevice().mappings[mapping.offset()]; activeMapping = activeDevice().mappings[mapping.offset()];
settingsWindow->layout.setEnabled(false); settingsWindow.layout.setEnabled(false);
settingsWindow->statusBar.setText({"Press a key or button to map [", activeMapping->name, "] ..."}); settingsWindow.statusBar.setText({"Press a key or button to map [", activeMapping->name, "] ..."});
settingsWindow->setDismissable(false); settingsWindow.setDismissable(false);
} }
} }
auto InputSettings::cancelMapping() -> void { auto InputSettings::cancelMapping() -> void {
activeMapping.reset(); activeMapping.reset();
settingsWindow->statusBar.setText(); settingsWindow.statusBar.setText();
settingsWindow->layout.setEnabled(); settingsWindow.layout.setEnabled();
settingsWindow->doSize(); settingsWindow.doSize();
settingsWindow->setDismissable(true); settingsWindow.setDismissable(true);
} }
auto InputSettings::assignMouseInput(uint id) -> void { auto InputSettings::assignMouseInput(uint id) -> void {
if(auto mapping = mappingList.selected()) { if(auto mapping = mappingList.selected()) {
activeMapping = activeDevice().mappings[mapping.offset()]; activeMapping = activeDevice().mappings[mapping.offset()];
if(auto mouse = inputManager->findMouse()) { if(auto mouse = inputManager.findMouse()) {
if(activeMapping->isDigital()) { if(activeMapping->isDigital()) {
return inputEvent(mouse, HID::Mouse::GroupID::Button, id, 0, 1, true); return inputEvent(mouse, HID::Mouse::GroupID::Button, id, 0, 1, true);
} else if(activeMapping->isAnalog()) { } else if(activeMapping->isAnalog()) {
@ -150,7 +150,7 @@ auto InputSettings::inputEvent(shared_pointer<HID::Device> device, uint group, u
if(activeMapping->bind(device, group, input, oldValue, newValue)) { if(activeMapping->bind(device, group, input, oldValue, newValue)) {
activeMapping.reset(); activeMapping.reset();
settingsWindow->statusBar.setText("Mapping assigned."); settingsWindow.statusBar.setText("Mapping assigned.");
refreshMappings(); refreshMappings();
timer.onActivate([&] { timer.onActivate([&] {
timer.setEnabled(false); timer.setEnabled(false);

View File

@ -1,4 +1,4 @@
PathSettings::PathSettings(TabFrame* parent) : TabFrameItem(parent) { auto PathSettings::create() -> void {
setIcon(Icon::Emblem::Folder); setIcon(Icon::Emblem::Folder);
setText("Paths"); setText("Paths");

View File

@ -4,10 +4,17 @@
#include "input.cpp" #include "input.cpp"
#include "hotkeys.cpp" #include "hotkeys.cpp"
#include "paths.cpp" #include "paths.cpp"
#include "configuration.cpp" #include "emulator.cpp"
#include "drivers.cpp" #include "drivers.cpp"
Settings settings; Settings settings;
unique_pointer<SettingsWindow> settingsWindow; VideoSettings videoSettings;
AudioSettings audioSettings;
InputSettings inputSettings;
HotkeySettings hotkeySettings;
PathSettings pathSettings;
EmulatorSettings emulatorSettings;
DriverSettings driverSettings;
SettingsWindow settingsWindow;
Settings::Settings() { Settings::Settings() {
Markup::Node::operator=(BML::unserialize(string::read(locate("settings.bml")))); Markup::Node::operator=(BML::unserialize(string::read(locate("settings.bml"))));
@ -84,10 +91,15 @@ auto Settings::save() -> void {
file::write(locate("settings.bml"), BML::serialize(*this)); file::write(locate("settings.bml"), BML::serialize(*this));
} }
SettingsWindow::SettingsWindow() { auto SettingsWindow::create() -> void {
settingsWindow = this;
layout.setPadding(5); layout.setPadding(5);
panel.append(videoSettings);
panel.append(audioSettings);
panel.append(inputSettings);
panel.append(hotkeySettings);
panel.append(pathSettings);
panel.append(emulatorSettings);
panel.append(driverSettings);
statusBar.setFont(Font().setBold()); statusBar.setFont(Font().setBold());
setTitle("Settings"); setTitle("Settings");
@ -96,21 +108,21 @@ SettingsWindow::SettingsWindow() {
setDismissable(); setDismissable();
onSize([&] { onSize([&] {
input.mappingList.resizeColumns(); inputSettings.mappingList.resizeColumns();
hotkeys.mappingList.resizeColumns(); hotkeySettings.mappingList.resizeColumns();
}); });
onClose([&] { onClose([&] {
if(input.activeMapping) input.cancelMapping(); if(inputSettings.activeMapping) inputSettings.cancelMapping();
if(hotkeys.activeMapping) hotkeys.cancelMapping(); if(hotkeySettings.activeMapping) hotkeySettings.cancelMapping();
setVisible(false); setVisible(false);
}); });
} }
auto SettingsWindow::setVisible(bool visible) -> SettingsWindow& { auto SettingsWindow::setVisible(bool visible) -> SettingsWindow& {
if(visible) { if(visible) {
input.refreshMappings(); inputSettings.refreshMappings();
hotkeys.refreshMappings(); hotkeySettings.refreshMappings();
} }
return Window::setVisible(visible), *this; return Window::setVisible(visible), *this;
} }

View File

@ -4,7 +4,7 @@ struct Settings : Markup::Node {
}; };
struct VideoSettings : TabFrameItem { struct VideoSettings : TabFrameItem {
VideoSettings(TabFrame*); auto create() -> void;
public: public:
VerticalLayout layout{this}; VerticalLayout layout{this};
@ -24,7 +24,7 @@ public:
}; };
struct AudioSettings : TabFrameItem { struct AudioSettings : TabFrameItem {
AudioSettings(TabFrame*); auto create() -> void;
public: public:
VerticalLayout layout{this}; VerticalLayout layout{this};
@ -44,7 +44,7 @@ public:
}; };
struct InputSettings : TabFrameItem { struct InputSettings : TabFrameItem {
InputSettings(TabFrame*); auto create() -> void;
auto updateControls() -> void; auto updateControls() -> void;
auto activePort() -> InputPort&; auto activePort() -> InputPort&;
auto activeDevice() -> InputDevice&; auto activeDevice() -> InputDevice&;
@ -80,7 +80,7 @@ public:
}; };
struct HotkeySettings : TabFrameItem { struct HotkeySettings : TabFrameItem {
HotkeySettings(TabFrame*); auto create() -> void;
auto reloadMappings() -> void; auto reloadMappings() -> void;
auto refreshMappings() -> void; auto refreshMappings() -> void;
auto assignMapping() -> void; auto assignMapping() -> void;
@ -100,7 +100,7 @@ public:
}; };
struct PathSettings : TabFrameItem { struct PathSettings : TabFrameItem {
PathSettings(TabFrame*); auto create() -> void;
auto refreshPaths() -> void; auto refreshPaths() -> void;
public: public:
@ -136,8 +136,8 @@ public:
Button screenshotsReset{&layout, Size{80, 0}}; Button screenshotsReset{&layout, Size{80, 0}};
}; };
struct ConfigurationSettings : TabFrameItem { struct EmulatorSettings : TabFrameItem {
ConfigurationSettings(TabFrame*); auto create() -> void;
auto updateConfiguration() -> void; auto updateConfiguration() -> void;
public: public:
@ -155,6 +155,7 @@ public:
CheckLabel autoSaveStateOnUnload{&autoStateLayout, Size{0, 0}}; CheckLabel autoSaveStateOnUnload{&autoStateLayout, Size{0, 0}};
CheckLabel autoLoadStateOnLoad{&autoStateLayout, Size{0, 0}}; CheckLabel autoLoadStateOnLoad{&autoStateLayout, Size{0, 0}};
CheckLabel suppressScreenSaver{&layout, Size{~0, 0}}; CheckLabel suppressScreenSaver{&layout, Size{~0, 0}};
Widget optionsSpacer{&layout, Size{~0, 10}};
Label hacksLabel{&layout, Size{~0, 0}, 2}; Label hacksLabel{&layout, Size{~0, 0}, 2};
HorizontalLayout fastPPULayout{&layout, Size{~0, 0}}; HorizontalLayout fastPPULayout{&layout, Size{~0, 0}};
CheckLabel fastPPUOption{&fastPPULayout, Size{0, 0}}; CheckLabel fastPPUOption{&fastPPULayout, Size{0, 0}};
@ -169,7 +170,7 @@ public:
}; };
struct DriverSettings : TabFrameItem { struct DriverSettings : TabFrameItem {
DriverSettings(TabFrame*); auto create() -> void;
auto videoDriverChanged() -> void; auto videoDriverChanged() -> void;
auto videoDriverChange() -> void; auto videoDriverChange() -> void;
auto videoFormatChanged() -> void; auto videoFormatChanged() -> void;
@ -201,6 +202,7 @@ public:
CheckLabel videoExclusiveToggle{&videoToggleLayout, Size{0, 0}}; CheckLabel videoExclusiveToggle{&videoToggleLayout, Size{0, 0}};
CheckLabel videoBlockingToggle{&videoToggleLayout, Size{0, 0}}; CheckLabel videoBlockingToggle{&videoToggleLayout, Size{0, 0}};
CheckLabel videoFlushToggle{&videoToggleLayout, Size{0, 0}}; CheckLabel videoFlushToggle{&videoToggleLayout, Size{0, 0}};
Widget videoSpacer{&layout, Size{~0, 10}};
Label audioLabel{&layout, Size{~0, 0}, 2}; Label audioLabel{&layout, Size{~0, 0}, 2};
TableLayout audioLayout{&layout, Size{~0, 0}}; TableLayout audioLayout{&layout, Size{~0, 0}};
Label audioDriverLabel{&audioLayout, Size{0, 0}}; Label audioDriverLabel{&audioLayout, Size{0, 0}};
@ -219,6 +221,7 @@ public:
CheckLabel audioExclusiveToggle{&audioToggleLayout, Size{0, 0}}; CheckLabel audioExclusiveToggle{&audioToggleLayout, Size{0, 0}};
CheckLabel audioBlockingToggle{&audioToggleLayout, Size{0, 0}}; CheckLabel audioBlockingToggle{&audioToggleLayout, Size{0, 0}};
CheckLabel audioDynamicToggle{&audioToggleLayout, Size{0, 0}}; CheckLabel audioDynamicToggle{&audioToggleLayout, Size{0, 0}};
Widget audioSpacer{&layout, Size{~0, 10}};
Label inputLabel{&layout, Size{~0, 0}, 2}; Label inputLabel{&layout, Size{~0, 0}, 2};
TableLayout inputLayout{&layout, Size{~0, 0}}; TableLayout inputLayout{&layout, Size{~0, 0}};
Label inputDriverLabel{&inputLayout, Size{0, 0}}; Label inputDriverLabel{&inputLayout, Size{0, 0}};
@ -229,22 +232,22 @@ public:
}; };
struct SettingsWindow : Window { struct SettingsWindow : Window {
SettingsWindow(); auto create() -> void;
auto setVisible(bool visible = true) -> SettingsWindow&; auto setVisible(bool visible = true) -> SettingsWindow&;
auto show(uint index) -> void; auto show(uint index) -> void;
public: public:
VerticalLayout layout{this}; VerticalLayout layout{this};
TabFrame panel{&layout, Size{~0, ~0}}; TabFrame panel{&layout, Size{~0, ~0}};
VideoSettings video{&panel};
AudioSettings audio{&panel};
InputSettings input{&panel};
HotkeySettings hotkeys{&panel};
PathSettings paths{&panel};
ConfigurationSettings configuration{&panel};
DriverSettings drivers{&panel};
StatusBar statusBar{this}; StatusBar statusBar{this};
}; };
extern Settings settings; extern Settings settings;
extern unique_pointer<SettingsWindow> settingsWindow; extern VideoSettings videoSettings;
extern AudioSettings audioSettings;
extern InputSettings inputSettings;
extern HotkeySettings hotkeySettings;
extern PathSettings pathSettings;
extern EmulatorSettings emulatorSettings;
extern DriverSettings driverSettings;
extern SettingsWindow settingsWindow;

View File

@ -1,4 +1,4 @@
VideoSettings::VideoSettings(TabFrame* parent) : TabFrameItem(parent) { auto VideoSettings::create() -> void {
setIcon(Icon::Device::Display); setIcon(Icon::Device::Display);
setText("Video"); setText("Video");
@ -13,7 +13,7 @@ VideoSettings::VideoSettings(TabFrame* parent) : TabFrameItem(parent) {
string value = {luminanceSlider.position(), "%"}; string value = {luminanceSlider.position(), "%"};
settings["Video/Luminance"].setValue(value); settings["Video/Luminance"].setValue(value);
luminanceValue.setText(value); luminanceValue.setText(value);
program->updateVideoPalette(); program.updateVideoPalette();
}).doChange(); }).doChange();
saturationLabel.setText("Saturation:"); saturationLabel.setText("Saturation:");
saturationValue.setAlignment(0.5); saturationValue.setAlignment(0.5);
@ -21,7 +21,7 @@ VideoSettings::VideoSettings(TabFrame* parent) : TabFrameItem(parent) {
string value = {saturationSlider.position(), "%"}; string value = {saturationSlider.position(), "%"};
settings["Video/Saturation"].setValue(value); settings["Video/Saturation"].setValue(value);
saturationValue.setText(value); saturationValue.setText(value);
program->updateVideoPalette(); program.updateVideoPalette();
}).doChange(); }).doChange();
gammaLabel.setText("Gamma:"); gammaLabel.setText("Gamma:");
gammaValue.setAlignment(0.5); gammaValue.setAlignment(0.5);
@ -29,6 +29,6 @@ VideoSettings::VideoSettings(TabFrame* parent) : TabFrameItem(parent) {
string value = {100 + gammaSlider.position(), "%"}; string value = {100 + gammaSlider.position(), "%"};
settings["Video/Gamma"].setValue(value); settings["Video/Gamma"].setValue(value);
gammaValue.setText(value); gammaValue.setText(value);
program->updateVideoPalette(); program.updateVideoPalette();
}).doChange(); }).doChange();
} }

View File

@ -1,6 +1,4 @@
CheatDatabase::CheatDatabase() { auto CheatDatabase::create() -> void {
cheatDatabase = this;
layout.setPadding(5); layout.setPadding(5);
selectAllButton.setText("Select All").onActivate([&] { selectAllButton.setText("Select All").onActivate([&] {
for(auto item : cheatList.items()) item.setChecked(true); for(auto item : cheatList.items()) item.setChecked(true);
@ -44,7 +42,7 @@ auto CheatDatabase::findCheats() -> void {
auto CheatDatabase::addCheats() -> void { auto CheatDatabase::addCheats() -> void {
for(auto item : cheatList.items()) { for(auto item : cheatList.items()) {
if(item.checked()) { if(item.checked()) {
toolsWindow->cheatEditor.addCheat({item.text(), item.property("code"), false}); cheatEditor.addCheat({item.text(), item.property("code"), false});
} }
} }
setVisible(false); setVisible(false);
@ -52,9 +50,7 @@ auto CheatDatabase::addCheats() -> void {
// //
CheatWindow::CheatWindow() { auto CheatWindow::create() -> void {
cheatWindow = this;
layout.setPadding(5); layout.setPadding(5);
nameLabel.setText("Name:"); nameLabel.setText("Name:");
nameValue.onActivate([&] { if(acceptButton.enabled()) acceptButton.doActivate(); }); nameValue.onActivate([&] { if(acceptButton.enabled()) acceptButton.doActivate(); });
@ -93,16 +89,16 @@ auto CheatWindow::doChange() -> void {
auto CheatWindow::doAccept() -> void { auto CheatWindow::doAccept() -> void {
Cheat cheat = {nameValue.text().strip(), codeValue.text().strip(), enableOption.checked()}; Cheat cheat = {nameValue.text().strip(), codeValue.text().strip(), enableOption.checked()};
if(acceptButton.text() == "Add") { if(acceptButton.text() == "Add") {
toolsWindow->cheatEditor.addCheat(cheat); cheatEditor.addCheat(cheat);
} else { } else {
toolsWindow->cheatEditor.editCheat(cheat); cheatEditor.editCheat(cheat);
} }
setVisible(false); setVisible(false);
} }
// //
CheatEditor::CheatEditor(TabFrame* parent) : TabFrameItem(parent) { auto CheatEditor::create() -> void {
setIcon(Icon::Edit::Replace); setIcon(Icon::Edit::Replace);
setText("Cheat Editor"); setText("Cheat Editor");
@ -123,23 +119,23 @@ CheatEditor::CheatEditor(TabFrame* parent) : TabFrameItem(parent) {
} }
}); });
findCheatsButton.setText("Find Cheats ...").onActivate([&] { findCheatsButton.setText("Find Cheats ...").onActivate([&] {
cheatDatabase->findCheats(); cheatDatabase.findCheats();
}); });
enableCheats.setText("Enable Cheats").setChecked(settings["Emulator/Cheats/Enable"].boolean()).onToggle([&] { enableCheats.setText("Enable Cheats").setChecked(settings["Emulator/Cheats/Enable"].boolean()).onToggle([&] {
settings["Emulator/Cheats/Enable"].setValue(enableCheats.checked()); settings["Emulator/Cheats/Enable"].setValue(enableCheats.checked());
if(!enableCheats.checked()) { if(!enableCheats.checked()) {
program->showMessage("All cheat codes disabled"); program.showMessage("All cheat codes disabled");
} else { } else {
program->showMessage("Active cheat codes enabled"); program.showMessage("Active cheat codes enabled");
} }
synchronizeCodes(); synchronizeCodes();
}); });
addButton.setText("Add").onActivate([&] { addButton.setText("Add").onActivate([&] {
cheatWindow->show(); cheatWindow.show();
}); });
editButton.setText("Edit").onActivate([&] { editButton.setText("Edit").onActivate([&] {
if(auto item = cheatList.selected()) { if(auto item = cheatList.selected()) {
cheatWindow->show(cheats[item.offset()]); cheatWindow.show(cheats[item.offset()]);
} }
}); });
removeButton.setText("Remove").onActivate([&] { removeButton.setText("Remove").onActivate([&] {
@ -203,7 +199,7 @@ auto CheatEditor::removeCheats() -> void {
auto CheatEditor::loadCheats() -> void { auto CheatEditor::loadCheats() -> void {
cheats.reset(); cheats.reset();
auto location = program->cheatPath(); auto location = program.cheatPath();
auto document = BML::unserialize(string::read(location)); auto document = BML::unserialize(string::read(location));
for(auto cheat : document.find("cheat")) { for(auto cheat : document.find("cheat")) {
cheats.append({cheat["name"].text(), cheat["code"].text(), (bool)cheat["enable"]}); cheats.append({cheat["name"].text(), cheat["code"].text(), (bool)cheat["enable"]});
@ -223,7 +219,7 @@ auto CheatEditor::saveCheats() -> void {
document.append(" enable\n"); document.append(" enable\n");
document.append("\n"); document.append("\n");
} }
auto location = program->cheatPath(); auto location = program.cheatPath();
if(document) { if(document) {
file::write(location, document); file::write(location, document);
} else { } else {

View File

@ -1,4 +1,4 @@
ManifestViewer::ManifestViewer(TabFrame* parent) : TabFrameItem(parent) { auto ManifestViewer::create() -> void {
setIcon(Icon::Emblem::Text); setIcon(Icon::Emblem::Text);
setText("Manifest Viewer"); setText("Manifest Viewer");
@ -15,6 +15,6 @@ auto ManifestViewer::loadManifest() -> void {
} }
manifestView.setText(emulator->manifests().merge("\n")); manifestView.setText(emulator->manifests().merge("\n"));
verifiedIcon.setIcon(program->verified() ? Icon::Emblem::Program : Icon::Emblem::Binary); verifiedIcon.setIcon(program.verified() ? Icon::Emblem::Program : Icon::Emblem::Binary);
verifiedLabel.setText(program->verified() ? "Verified" : "Unverified"); verifiedLabel.setText(program.verified() ? "Verified" : "Unverified");
} }

View File

@ -1,6 +1,4 @@
StateWindow::StateWindow() { auto StateWindow::create() -> void {
stateWindow = this;
layout.setPadding(5); layout.setPadding(5);
nameLabel.setText("Name:"); nameLabel.setText("Name:");
nameValue.onActivate([&] { nameValue.onActivate([&] {
@ -48,7 +46,7 @@ auto StateWindow::doChange() -> void {
|| c == '|') valid = false; || c == '|') valid = false;
} }
if(auto input = nameValue.property("input")) { if(auto input = nameValue.property("input")) {
if(name != input && file::exists({program->statePath(), "managed/", name, ".bst"})) valid = false; if(name != input && file::exists({program.statePath(), "managed/", name, ".bst"})) valid = false;
} }
nameValue.setBackgroundColor(valid ? Color{} : Color{255, 224, 224}); nameValue.setBackgroundColor(valid ? Color{} : Color{255, 224, 224});
acceptButton.setEnabled(valid); acceptButton.setEnabled(valid);
@ -56,14 +54,14 @@ auto StateWindow::doChange() -> void {
auto StateWindow::doAccept() -> void { auto StateWindow::doAccept() -> void {
if(acceptButton.text() == "Add") { if(acceptButton.text() == "Add") {
toolsWindow->stateManager.createState(nameValue.text()); stateManager.createState(nameValue.text());
} else { } else {
toolsWindow->stateManager.modifyState(nameValue.text()); stateManager.modifyState(nameValue.text());
} }
setVisible(false); setVisible(false);
} }
StateManager::StateManager(TabFrame* parent) : TabFrameItem(parent) { auto StateManager::create() -> void {
setIcon(Icon::Application::FileManager); setIcon(Icon::Application::FileManager);
setText("State Manager"); setText("State Manager");
@ -82,22 +80,22 @@ StateManager::StateManager(TabFrame* parent) : TabFrameItem(parent) {
loadButton.setText("Load").onActivate([&] { loadButton.setText("Load").onActivate([&] {
if(auto item = stateList.selected()) { if(auto item = stateList.selected()) {
string filename = {"managed/", item.cell(0).text()}; string filename = {"managed/", item.cell(0).text()};
program->loadState(filename); program.loadState(filename);
} }
}); });
saveButton.setText("Save").onActivate([&] { saveButton.setText("Save").onActivate([&] {
if(auto item = stateList.selected()) { if(auto item = stateList.selected()) {
string filename = {"managed/", item.cell(0).text()}; string filename = {"managed/", item.cell(0).text()};
program->saveState(filename); program.saveState(filename);
item.cell(1).setText(chrono::local::datetime(program->stateTimestamp(filename))); item.cell(1).setText(chrono::local::datetime(program.stateTimestamp(filename)));
} }
}); });
addButton.setText("Add").onActivate([&] { addButton.setText("Add").onActivate([&] {
stateWindow->show(); stateWindow.show();
}); });
editButton.setText("Edit").onActivate([&] { editButton.setText("Edit").onActivate([&] {
if(auto item = stateList.selected()) { if(auto item = stateList.selected()) {
stateWindow->show(item.cell(0).text()); stateWindow.show(item.cell(0).text());
} }
}); });
removeButton.setText("Remove").onActivate([&] { removeButton.setText("Remove").onActivate([&] {
@ -111,17 +109,17 @@ auto StateManager::loadStates() -> void {
.append(TableViewColumn().setText("Name").setExpandable()) .append(TableViewColumn().setText("Name").setExpandable())
.append(TableViewColumn().setText("Date").setForegroundColor({160, 160, 160})) .append(TableViewColumn().setText("Date").setForegroundColor({160, 160, 160}))
); );
for(auto& filename : program->availableStates("managed/")) { for(auto& filename : program.availableStates("managed/")) {
stateList.append(TableViewItem() stateList.append(TableViewItem()
.append(TableViewCell().setText(string{filename}.trimLeft("managed/", 1L))) .append(TableViewCell().setText(string{filename}.trimLeft("managed/", 1L)))
.append(TableViewCell().setText(chrono::local::datetime(program->stateTimestamp(filename)))) .append(TableViewCell().setText(chrono::local::datetime(program.stateTimestamp(filename))))
); );
} }
stateList.resizeColumns().doChange(); stateList.resizeColumns().doChange();
} }
auto StateManager::createState(string name) -> void { auto StateManager::createState(string name) -> void {
program->saveState({"managed/", name}); program.saveState({"managed/", name});
loadStates(); loadStates();
for(auto& item : stateList.items()) { for(auto& item : stateList.items()) {
if(item.cell(0).text() == name) item.setSelected(); if(item.cell(0).text() == name) item.setSelected();
@ -134,7 +132,7 @@ auto StateManager::modifyState(string name) -> void {
string from = {"managed/", item.cell(0).text()}; string from = {"managed/", item.cell(0).text()};
string to = {"managed/", name}; string to = {"managed/", name};
if(from != to) { if(from != to) {
program->renameState(from, to); program.renameState(from, to);
loadStates(); loadStates();
for(auto& item : stateList.items()) { for(auto& item : stateList.items()) {
if(item.cell(0).text() == name) item.setSelected(); if(item.cell(0).text() == name) item.setSelected();
@ -149,7 +147,7 @@ auto StateManager::removeStates() -> void {
if(MessageDialog("Are you sure you want to permanently remove the selected state(s)?") if(MessageDialog("Are you sure you want to permanently remove the selected state(s)?")
.setParent(*toolsWindow).question() == "Yes") { .setParent(*toolsWindow).question() == "Yes") {
for(auto& item : batched) { for(auto& item : batched) {
program->removeState({"managed/", item.cell(0).text()}); program.removeState({"managed/", item.cell(0).text()});
} }
loadStates(); loadStates();
} }

View File

@ -2,15 +2,19 @@
#include "cheat-editor.cpp" #include "cheat-editor.cpp"
#include "state-manager.cpp" #include "state-manager.cpp"
#include "manifest-viewer.cpp" #include "manifest-viewer.cpp"
unique_pointer<CheatDatabase> cheatDatabase; CheatDatabase cheatDatabase;
unique_pointer<CheatWindow> cheatWindow; CheatWindow cheatWindow;
unique_pointer<StateWindow> stateWindow; CheatEditor cheatEditor;
unique_pointer<ToolsWindow> toolsWindow; StateWindow stateWindow;
StateManager stateManager;
ToolsWindow::ToolsWindow() { ManifestViewer manifestViewer;
toolsWindow = this; ToolsWindow toolsWindow;
auto ToolsWindow::create() -> void {
layout.setPadding(5); layout.setPadding(5);
panel.append(cheatEditor);
panel.append(stateManager);
panel.append(manifestViewer);
setTitle("Tools"); setTitle("Tools");
setSize({600, 400}); setSize({600, 400});
@ -30,15 +34,15 @@ ToolsWindow::ToolsWindow() {
auto ToolsWindow::setVisible(bool visible) -> ToolsWindow& { auto ToolsWindow::setVisible(bool visible) -> ToolsWindow& {
Window::setVisible(visible); Window::setVisible(visible);
if(!visible) { if(!visible) {
cheatDatabase->setVisible(false); cheatDatabase.setVisible(false);
cheatWindow->setVisible(false); cheatWindow.setVisible(false);
stateWindow->setVisible(false); stateWindow.setVisible(false);
} }
return *this; return *this;
} }
auto ToolsWindow::show(uint index) -> void { auto ToolsWindow::show(uint index) -> void {
panel.item(index)->setSelected(); panel.item(index).setSelected();
setVisible(); setVisible();
setFocused(); setFocused();
doSize(); doSize();

View File

@ -13,7 +13,7 @@ struct Cheat {
}; };
struct CheatDatabase : Window { struct CheatDatabase : Window {
CheatDatabase(); auto create() -> void;
auto findCheats() -> void; auto findCheats() -> void;
auto addCheats() -> void; auto addCheats() -> void;
@ -28,7 +28,7 @@ public:
}; };
struct CheatWindow : Window { struct CheatWindow : Window {
CheatWindow(); auto create() -> void;
auto show(Cheat cheat = {}) -> void; auto show(Cheat cheat = {}) -> void;
auto doChange() -> void; auto doChange() -> void;
auto doAccept() -> void; auto doAccept() -> void;
@ -49,7 +49,7 @@ public:
}; };
struct CheatEditor : TabFrameItem { struct CheatEditor : TabFrameItem {
CheatEditor(TabFrame*); auto create() -> void;
auto refresh() -> void; auto refresh() -> void;
auto addCheat(Cheat cheat) -> void; auto addCheat(Cheat cheat) -> void;
auto editCheat(Cheat cheat) -> void; auto editCheat(Cheat cheat) -> void;
@ -73,7 +73,7 @@ public:
}; };
struct StateWindow : Window { struct StateWindow : Window {
StateWindow(); auto create() -> void;
auto show(string name = {}) -> void; auto show(string name = {}) -> void;
auto doChange() -> void; auto doChange() -> void;
auto doAccept() -> void; auto doAccept() -> void;
@ -90,7 +90,7 @@ public:
}; };
struct StateManager : TabFrameItem { struct StateManager : TabFrameItem {
StateManager(TabFrame*); auto create() -> void;
auto loadStates() -> void; auto loadStates() -> void;
auto createState(string name) -> void; auto createState(string name) -> void;
auto modifyState(string name) -> void; auto modifyState(string name) -> void;
@ -109,7 +109,7 @@ public:
}; };
struct ManifestViewer : TabFrameItem { struct ManifestViewer : TabFrameItem {
ManifestViewer(TabFrame*); auto create() -> void;
auto loadManifest() -> void; auto loadManifest() -> void;
public: public:
@ -121,19 +121,19 @@ public:
}; };
struct ToolsWindow : Window { struct ToolsWindow : Window {
ToolsWindow(); auto create() -> void;
auto setVisible(bool visible = true) -> ToolsWindow&; auto setVisible(bool visible = true) -> ToolsWindow&;
auto show(uint index) -> void; auto show(uint index) -> void;
public: public:
VerticalLayout layout{this}; VerticalLayout layout{this};
TabFrame panel{&layout, Size{~0, ~0}}; TabFrame panel{&layout, Size{~0, ~0}};
CheatEditor cheatEditor{&panel};
StateManager stateManager{&panel};
ManifestViewer manifestViewer{&panel};
}; };
extern unique_pointer<CheatDatabase> cheatDatabase; extern CheatDatabase cheatDatabase;
extern unique_pointer<CheatWindow> cheatWindow; extern CheatWindow cheatWindow;
extern unique_pointer<StateWindow> stateWindow; extern CheatEditor cheatEditor;
extern unique_pointer<ToolsWindow> toolsWindow; extern StateWindow stateWindow;
extern StateManager stateManager;
extern ManifestViewer manifestViewer;
extern ToolsWindow toolsWindow;

View File

@ -27,9 +27,6 @@ auto pObject::setFocused() -> void {
auto pObject::setFont(const Font& font) -> void { auto pObject::setFont(const Font& font) -> void {
} }
auto pObject::setParent(mObject* parent, int offset) -> void {
}
auto pObject::setVisible(bool visible) -> void { auto pObject::setVisible(bool visible) -> void {
} }

View File

@ -16,7 +16,6 @@ struct pObject : mLock {
virtual auto setEnabled(bool enabled) -> void; virtual auto setEnabled(bool enabled) -> void;
virtual auto setFocused() -> void; virtual auto setFocused() -> void;
virtual auto setFont(const Font& font) -> void; virtual auto setFont(const Font& font) -> void;
virtual auto setParent(mObject* parent, int offset) -> void;
virtual auto setVisible(bool visible) -> void; virtual auto setVisible(bool visible) -> void;
mObject& reference; mObject& reference;

View File

@ -29,7 +29,7 @@ auto mMenu::actions() const -> vector<Action> {
auto mMenu::append(sAction action) -> type& { auto mMenu::append(sAction action) -> type& {
state.actions.append(action); state.actions.append(action);
action->setParent(this, actionCount() - 1); action->setParent(this, actionCount() - 1);
signal(append, *action); signal(append, action);
return *this; return *this;
} }
@ -38,7 +38,7 @@ auto mMenu::icon() const -> image {
} }
auto mMenu::remove(sAction action) -> type& { auto mMenu::remove(sAction action) -> type& {
signal(remove, *action); signal(remove, action);
state.actions.remove(action->offset()); state.actions.remove(action->offset());
for(auto n : range(action->offset(), actionCount())) { for(auto n : range(action->offset(), actionCount())) {
state.actions[n]->adjustOffset(-1); state.actions[n]->adjustOffset(-1);

View File

@ -40,7 +40,7 @@ auto mMenuBar::remove() -> type& {
auto mMenuBar::remove(sMenu menu) -> type& { auto mMenuBar::remove(sMenu menu) -> type& {
signed offset = menu->offset(); signed offset = menu->offset();
signal(remove, *menu); signal(remove, menu);
state.menus.remove(offset); state.menus.remove(offset);
for(auto n : range(offset, menuCount())) { for(auto n : range(offset, menuCount())) {
state.menus[n]->adjustOffset(-1); state.menus[n]->adjustOffset(-1);

View File

@ -298,7 +298,6 @@ auto mObject::setGroup(sGroup group) -> type& {
} }
auto mObject::setParent(mObject* parent, int offset) -> type& { auto mObject::setParent(mObject* parent, int offset) -> type& {
signal(setParent, parent, offset);
destruct(); destruct();
state.parent = parent; state.parent = parent;
state.offset = offset; state.offset = offset;

View File

@ -23,12 +23,12 @@ auto mComboButton::doChange() const -> void {
if(state.onChange) return state.onChange(); if(state.onChange) return state.onChange();
} }
auto mComboButton::item(unsigned position) const -> ComboButtonItem { auto mComboButton::item(uint position) const -> ComboButtonItem {
if(position < itemCount()) return state.items[position]; if(position < itemCount()) return state.items[position];
return {}; return {};
} }
auto mComboButton::itemCount() const -> unsigned { auto mComboButton::itemCount() const -> uint {
return state.items.size(); return state.items.size();
} }
@ -46,7 +46,7 @@ auto mComboButton::onChange(const function<void ()>& callback) -> type& {
auto mComboButton::remove(sComboButtonItem item) -> type& { auto mComboButton::remove(sComboButtonItem item) -> type& {
signal(remove, item); signal(remove, item);
state.items.remove(item->offset()); state.items.remove(item->offset());
for(auto n : range(item->offset(), itemCount())) { for(uint n : range(item->offset(), itemCount())) {
state.items[n]->adjustOffset(-1); state.items[n]->adjustOffset(-1);
} }
item->setParent(); item->setParent();
@ -54,9 +54,7 @@ auto mComboButton::remove(sComboButtonItem item) -> type& {
} }
auto mComboButton::reset() -> type& { auto mComboButton::reset() -> type& {
signal(reset); while(state.items) remove(state.items.last());
for(auto& item : state.items) item->setParent();
state.items.reset();
return *this; return *this;
} }
@ -67,8 +65,8 @@ auto mComboButton::selected() const -> ComboButtonItem {
return {}; return {};
} }
auto mComboButton::setParent(mObject* parent, signed offset) -> type& { auto mComboButton::setParent(mObject* parent, int offset) -> type& {
for(auto& item : state.items) item->destruct(); for(auto& item : reverse(state.items)) item->destruct();
mObject::setParent(parent, offset); mObject::setParent(parent, offset);
for(auto& item : state.items) item->setParent(this, item->offset()); for(auto& item : state.items) item->setParent(this, item->offset());
return *this; return *this;

View File

@ -27,9 +27,6 @@ auto pObject::setFocused() -> void {
auto pObject::setFont(const Font& font) -> void { auto pObject::setFont(const Font& font) -> void {
} }
auto pObject::setParent(mObject* parent, int offset) -> void {
}
auto pObject::setVisible(bool visible) -> void { auto pObject::setVisible(bool visible) -> void {
} }

View File

@ -16,7 +16,6 @@ struct pObject : mLock {
virtual auto setEnabled(bool enabled) -> void; virtual auto setEnabled(bool enabled) -> void;
virtual auto setFocused() -> void; virtual auto setFocused() -> void;
virtual auto setFont(const Font& font) -> void; virtual auto setFont(const Font& font) -> void;
virtual auto setParent(mObject* parent, int offset) -> void;
virtual auto setVisible(bool visible) -> void; virtual auto setVisible(bool visible) -> void;
mObject& reference; mObject& reference;

View File

@ -3,6 +3,7 @@
namespace hiro { namespace hiro {
auto pTabFrameItem::construct() -> void { auto pTabFrameItem::construct() -> void {
if(auto parent = _parent()) parent->_append();
if(auto& sizable = state().sizable) sizable->construct(); if(auto& sizable = state().sizable) sizable->construct();
} }

View File

@ -63,36 +63,6 @@ auto pTabFrame::destruct() -> void {
auto pTabFrame::append(sTabFrameItem item) -> void { auto pTabFrame::append(sTabFrameItem item) -> void {
lock(); lock();
Tab tab;
tab.child = gtk_fixed_new();
#if HIRO_GTK==2
tab.container = gtk_hbox_new(false, 0);
#elif HIRO_GTK==3
tab.container = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 0);
#endif
tab.image = gtk_image_new();
tab.title = gtk_label_new("");
gtk_misc_set_alignment(GTK_MISC(tab.title), 0.0, 0.5);
tab.close = gtk_button_new_with_label("\u00d7"); //Unicode multiplication sign (looks better than 'X')
gtk_button_set_focus_on_click(GTK_BUTTON(tab.close), false);
gtk_button_set_relief(GTK_BUTTON(tab.close), GTK_RELIEF_NONE);
pFont::setFont(tab.close, Font("sans", 9).setBold());
auto color = CreateColor({255, 0, 0});
gtk_widget_modify_fg(gtk_bin_get_child(GTK_BIN(tab.close)), GTK_STATE_PRELIGHT, &color);
tabs.append(tab);
gtk_widget_show(tab.child);
gtk_widget_show(tab.container);
gtk_widget_show(tab.image);
gtk_widget_show(tab.title);
gtk_widget_show(tab.close);
gtk_box_pack_start(GTK_BOX(tab.container), tab.image, false, false, 0);
gtk_box_pack_start(GTK_BOX(tab.container), tab.title, true, true, 0);
gtk_box_pack_start(GTK_BOX(tab.container), tab.close, false, false, 0);
g_signal_connect(G_OBJECT(tab.close), "clicked", G_CALLBACK(TabFrame_close), (gpointer)this);
gtk_notebook_append_page(GTK_NOTEBOOK(gtkWidget), tab.child, tab.container);
setFont(self().font(true)); setFont(self().font(true));
setItemMovable(item->offset(), item->movable()); setItemMovable(item->offset(), item->movable());
if(item->selected()) setItemSelected(item->offset()); if(item->selected()) setItemSelected(item->offset());
@ -210,6 +180,42 @@ auto pTabFrame::setNavigation(Navigation navigation) -> void {
setGeometry(self().geometry()); setGeometry(self().geometry());
} }
//called by pTabFrameItem::construct(), before pTabFrame::append()
//tab needs to be created early, so that pTabFrameItem child widgets calling pWidget::container() can find the tab
auto pTabFrame::_append() -> void {
lock();
Tab tab;
tab.child = gtk_fixed_new();
#if HIRO_GTK==2
tab.container = gtk_hbox_new(false, 0);
#elif HIRO_GTK==3
tab.container = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 0);
#endif
tab.image = gtk_image_new();
tab.title = gtk_label_new("");
gtk_misc_set_alignment(GTK_MISC(tab.title), 0.0, 0.5);
tab.close = gtk_button_new_with_label("\u00d7"); //Unicode multiplication sign (looks better than 'X')
gtk_button_set_focus_on_click(GTK_BUTTON(tab.close), false);
gtk_button_set_relief(GTK_BUTTON(tab.close), GTK_RELIEF_NONE);
pFont::setFont(tab.close, Font("sans", 9).setBold());
auto color = CreateColor({255, 0, 0});
gtk_widget_modify_fg(gtk_bin_get_child(GTK_BIN(tab.close)), GTK_STATE_PRELIGHT, &color);
tabs.append(tab);
gtk_widget_show(tab.child);
gtk_widget_show(tab.container);
gtk_widget_show(tab.image);
gtk_widget_show(tab.title);
gtk_widget_show(tab.close);
gtk_box_pack_start(GTK_BOX(tab.container), tab.image, false, false, 0);
gtk_box_pack_start(GTK_BOX(tab.container), tab.title, true, true, 0);
gtk_box_pack_start(GTK_BOX(tab.container), tab.close, false, false, 0);
g_signal_connect(G_OBJECT(tab.close), "clicked", G_CALLBACK(TabFrame_close), (gpointer)this);
gtk_notebook_append_page(GTK_NOTEBOOK(gtkWidget), tab.child, tab.container);
unlock();
}
auto pTabFrame::_synchronizeLayout() -> void { auto pTabFrame::_synchronizeLayout() -> void {
for(auto& item : state().items) { for(auto& item : state().items) {
if(auto& sizable = item->state.sizable) { if(auto& sizable = item->state.sizable) {

View File

@ -18,6 +18,7 @@ struct pTabFrame : pWidget {
auto setItemText(unsigned position, const string& text) -> void; auto setItemText(unsigned position, const string& text) -> void;
auto setNavigation(Navigation navigation) -> void; auto setNavigation(Navigation navigation) -> void;
auto _append() -> void;
auto _synchronizeLayout() -> void; auto _synchronizeLayout() -> void;
auto _synchronizeTab(unsigned position) -> void; auto _synchronizeTab(unsigned position) -> void;
auto _tabHeight() -> unsigned; auto _tabHeight() -> unsigned;

View File

@ -27,9 +27,6 @@ auto pObject::setFocused() -> void {
auto pObject::setFont(const Font& font) -> void { auto pObject::setFont(const Font& font) -> void {
} }
auto pObject::setParent(mObject* parent, int offset) -> void {
}
auto pObject::setVisible(bool visible) -> void { auto pObject::setVisible(bool visible) -> void {
} }

View File

@ -16,7 +16,6 @@ struct pObject : mLock {
virtual auto setEnabled(bool enabled) -> void; virtual auto setEnabled(bool enabled) -> void;
virtual auto setFocused() -> void; virtual auto setFocused() -> void;
virtual auto setFont(const Font& font) -> void; virtual auto setFont(const Font& font) -> void;
virtual auto setParent(mObject* parent, int offset) -> void;
virtual auto setVisible(bool visible) -> void; virtual auto setVisible(bool visible) -> void;
mObject& reference; mObject& reference;

View File

@ -3,6 +3,7 @@
namespace hiro { namespace hiro {
auto pTableViewColumn::construct() -> void { auto pTableViewColumn::construct() -> void {
if(auto header = _parent()) header->_setState();
} }
auto pTableViewColumn::destruct() -> void { auto pTableViewColumn::destruct() -> void {
@ -44,10 +45,6 @@ auto pTableViewColumn::setIcon(const image& icon) -> void {
//unsupported //unsupported
} }
auto pTableViewColumn::setParent(mObject* parent, int offset) -> void {
if(auto header = _parent()) header->_setState();
}
auto pTableViewColumn::setResizable(bool resizable) -> void { auto pTableViewColumn::setResizable(bool resizable) -> void {
_setState(); _setState();
} }

View File

@ -14,7 +14,6 @@ struct pTableViewColumn : pObject {
auto setForegroundColor(Color color) -> void; auto setForegroundColor(Color color) -> void;
auto setHorizontalAlignment(double alignment) -> void; auto setHorizontalAlignment(double alignment) -> void;
auto setIcon(const image& icon) -> void; auto setIcon(const image& icon) -> void;
auto setParent(mObject* parent, int offset) -> void override;
auto setResizable(bool resizable) -> void; auto setResizable(bool resizable) -> void;
auto setSortable(bool sortable) -> void; auto setSortable(bool sortable) -> void;
auto setText(const string& text) -> void; auto setText(const string& text) -> void;

View File

@ -33,9 +33,6 @@ auto pObject::setFont(const Font& font) -> void {
auto pObject::setGroup(sGroup group) -> void { auto pObject::setGroup(sGroup group) -> void {
} }
auto pObject::setParent(mObject* parent, int offset) -> void {
}
auto pObject::setVisible(bool visible) -> void { auto pObject::setVisible(bool visible) -> void {
} }

View File

@ -16,7 +16,6 @@ struct pObject : mLock {
virtual auto setFocused() -> void; virtual auto setFocused() -> void;
virtual auto setFont(const Font& font) -> void; virtual auto setFont(const Font& font) -> void;
virtual auto setGroup(sGroup group) -> void; virtual auto setGroup(sGroup group) -> void;
virtual auto setParent(mObject* parent, int offset) -> void;
virtual auto setVisible(bool visible) -> void; virtual auto setVisible(bool visible) -> void;
mObject& reference; mObject& reference;

View File

@ -41,144 +41,144 @@
namespace ruby { namespace ruby {
auto Audio::setExclusive(bool exclusive) -> bool { auto Audio::setExclusive(bool exclusive) -> bool {
if(driver->exclusive == exclusive) return true; if(instance->exclusive == exclusive) return true;
if(!driver->hasExclusive()) return false; if(!instance->hasExclusive()) return false;
if(!driver->setExclusive(driver->exclusive = exclusive)) return false; if(!instance->setExclusive(instance->exclusive = exclusive)) return false;
return true; return true;
} }
auto Audio::setContext(uintptr context) -> bool { auto Audio::setContext(uintptr context) -> bool {
if(driver->context == context) return true; if(instance->context == context) return true;
if(!driver->hasContext()) return false; if(!instance->hasContext()) return false;
if(!driver->setContext(driver->context = context)) return false; if(!instance->setContext(instance->context = context)) return false;
return true; return true;
} }
auto Audio::setDevice(string device) -> bool { auto Audio::setDevice(string device) -> bool {
if(driver->device == device) return true; if(instance->device == device) return true;
if(!driver->hasDevice(device)) return false; if(!instance->hasDevice(device)) return false;
if(!driver->setDevice(driver->device = device)) return false; if(!instance->setDevice(instance->device = device)) return false;
return true; return true;
} }
auto Audio::setBlocking(bool blocking) -> bool { auto Audio::setBlocking(bool blocking) -> bool {
if(driver->blocking == blocking) return true; if(instance->blocking == blocking) return true;
if(!driver->hasBlocking()) return false; if(!instance->hasBlocking()) return false;
if(!driver->setBlocking(driver->blocking = blocking)) return false; if(!instance->setBlocking(instance->blocking = blocking)) return false;
for(auto& resampler : resamplers) resampler.reset(driver->frequency); for(auto& resampler : resamplers) resampler.reset(instance->frequency);
return true; return true;
} }
auto Audio::setDynamic(bool dynamic) -> bool { auto Audio::setDynamic(bool dynamic) -> bool {
if(driver->dynamic == dynamic) return true; if(instance->dynamic == dynamic) return true;
if(!driver->hasDynamic()) return false; if(!instance->hasDynamic()) return false;
if(!driver->setDynamic(driver->dynamic = dynamic)) return false; if(!instance->setDynamic(instance->dynamic = dynamic)) return false;
return true; return true;
} }
auto Audio::setChannels(uint channels) -> bool { auto Audio::setChannels(uint channels) -> bool {
if(driver->channels == channels) return true; if(instance->channels == channels) return true;
if(!driver->hasChannels(channels)) return false; if(!instance->hasChannels(channels)) return false;
if(!driver->setChannels(driver->channels = channels)) return false; if(!instance->setChannels(instance->channels = channels)) return false;
resamplers.reset(); resamplers.reset();
resamplers.resize(channels); resamplers.resize(channels);
for(auto& resampler : resamplers) resampler.reset(driver->frequency); for(auto& resampler : resamplers) resampler.reset(instance->frequency);
return true; return true;
} }
auto Audio::setFrequency(uint frequency) -> bool { auto Audio::setFrequency(uint frequency) -> bool {
if(driver->frequency == frequency) return true; if(instance->frequency == frequency) return true;
if(!driver->hasFrequency(frequency)) return false; if(!instance->hasFrequency(frequency)) return false;
if(!driver->setFrequency(driver->frequency = frequency)) return false; if(!instance->setFrequency(instance->frequency = frequency)) return false;
for(auto& resampler : resamplers) resampler.reset(driver->frequency); for(auto& resampler : resamplers) resampler.reset(instance->frequency);
return true; return true;
} }
auto Audio::setLatency(uint latency) -> bool { auto Audio::setLatency(uint latency) -> bool {
if(driver->latency == latency) return true; if(instance->latency == latency) return true;
if(!driver->hasLatency(latency)) return false; if(!instance->hasLatency(latency)) return false;
if(!driver->setLatency(driver->latency = latency)) return false; if(!instance->setLatency(instance->latency = latency)) return false;
return true; return true;
} }
// //
auto Audio::clear() -> void { auto Audio::clear() -> void {
for(auto& resampler : resamplers) resampler.reset(driver->frequency); for(auto& resampler : resamplers) resampler.reset(instance->frequency);
return driver->clear(); return instance->clear();
} }
auto Audio::level() -> double { auto Audio::level() -> double {
return driver->level(); return instance->level();
} }
auto Audio::output(const double samples[]) -> void { auto Audio::output(const double samples[]) -> void {
if(!driver->dynamic) return driver->output(samples); if(!instance->dynamic) return instance->output(samples);
auto maxDelta = 0.005; auto maxDelta = 0.005;
double fillLevel = driver->level(); double fillLevel = instance->level();
double dynamicFrequency = ((1.0 - maxDelta) + 2.0 * fillLevel * maxDelta) * driver->frequency; double dynamicFrequency = ((1.0 - maxDelta) + 2.0 * fillLevel * maxDelta) * instance->frequency;
for(auto& resampler : resamplers) { for(auto& resampler : resamplers) {
resampler.setInputFrequency(dynamicFrequency); resampler.setInputFrequency(dynamicFrequency);
resampler.write(*samples++); resampler.write(*samples++);
} }
while(resamplers.first().pending()) { while(resamplers.first().pending()) {
double samples[driver->channels]; double samples[instance->channels];
for(uint n : range(driver->channels)) samples[n] = resamplers[n].read(); for(uint n : range(instance->channels)) samples[n] = resamplers[n].read();
driver->output(samples); instance->output(samples);
} }
} }
// //
auto Audio::create(string driver) -> bool { auto Audio::create(string driver) -> bool {
reset(); self.instance.reset();
if(!driver) driver = optimalDriver(); if(!driver) driver = optimalDriver();
#if defined(AUDIO_ALSA) #if defined(AUDIO_ALSA)
if(driver == "ALSA") self.driver = new AudioALSA(*this); if(driver == "ALSA") self.instance = new AudioALSA(*this);
#endif #endif
#if defined(AUDIO_AO) #if defined(AUDIO_AO)
if(driver == "libao") self.driver = new AudioAO(*this); if(driver == "libao") self.instance = new AudioAO(*this);
#endif #endif
#if defined(AUDIO_ASIO) #if defined(AUDIO_ASIO)
if(driver == "ASIO") self.driver = new AudioASIO(*this); if(driver == "ASIO") self.instance = new AudioASIO(*this);
#endif #endif
#if defined(AUDIO_DIRECTSOUND) #if defined(AUDIO_DIRECTSOUND)
if(driver == "DirectSound") self.driver = new AudioDirectSound(*this); if(driver == "DirectSound") self.instance = new AudioDirectSound(*this);
#endif #endif
#if defined(AUDIO_OPENAL) #if defined(AUDIO_OPENAL)
if(driver == "OpenAL") self.driver = new AudioOpenAL(*this); if(driver == "OpenAL") self.instance = new AudioOpenAL(*this);
#endif #endif
#if defined(AUDIO_OSS) #if defined(AUDIO_OSS)
if(driver == "OSS") self.driver = new AudioOSS(*this); if(driver == "OSS") self.instance = new AudioOSS(*this);
#endif #endif
#if defined(AUDIO_PULSEAUDIO) #if defined(AUDIO_PULSEAUDIO)
if(driver == "PulseAudio") self.driver = new AudioPulseAudio(*this); if(driver == "PulseAudio") self.instance = new AudioPulseAudio(*this);
#endif #endif
#if defined(AUDIO_PULSEAUDIOSIMPLE) #if defined(AUDIO_PULSEAUDIOSIMPLE)
if(driver == "PulseAudioSimple") self.driver = new AudioPulseAudioSimple(*this); if(driver == "PulseAudioSimple") self.instance = new AudioPulseAudioSimple(*this);
#endif #endif
#if defined(AUDIO_WASAPI) #if defined(AUDIO_WASAPI)
if(driver == "WASAPI") self.driver = new AudioWASAPI(*this); if(driver == "WASAPI") self.instance = new AudioWASAPI(*this);
#endif #endif
#if defined(AUDIO_XAUDIO2) #if defined(AUDIO_XAUDIO2)
if(driver == "XAudio2") self.driver = new AudioXAudio2(*this); if(driver == "XAudio2") self.instance = new AudioXAudio2(*this);
#endif #endif
if(!self.driver) self.driver = new AudioDriver(*this); if(!self.instance) self.instance = new AudioDriver(*this);
return self.driver->create(); return self.instance->create();
} }
auto Audio::hasDrivers() -> vector<string> { auto Audio::hasDrivers() -> vector<string> {

View File

@ -5,7 +5,7 @@ struct AudioDriver {
virtual ~AudioDriver() = default; virtual ~AudioDriver() = default;
virtual auto create() -> bool { return true; } virtual auto create() -> bool { return true; }
virtual auto driverName() -> string { return "None"; } virtual auto driver() -> string { return "None"; }
virtual auto ready() -> bool { return true; } virtual auto ready() -> bool { return true; }
virtual auto hasExclusive() -> bool { return false; } virtual auto hasExclusive() -> bool { return false; }
@ -55,35 +55,35 @@ struct Audio {
static auto optimalDriver() -> string; static auto optimalDriver() -> string;
static auto safestDriver() -> string; static auto safestDriver() -> string;
Audio() : self(*this) {} Audio() : self(*this) { reset(); }
explicit operator bool() const { return (bool)driver; } explicit operator bool() { return instance->driver() != "None"; }
auto reset() -> void { driver.reset(); } auto reset() -> void { instance = new AudioDriver(*this); }
auto create(string driver = "") -> bool; auto create(string driver = "") -> bool;
auto driverName() -> string { return driver->driverName(); } auto driver() -> string { return instance->driver(); }
auto ready() -> bool { return driver->ready(); } auto ready() -> bool { return instance->ready(); }
auto hasExclusive() -> bool { return driver->hasExclusive(); } auto hasExclusive() -> bool { return instance->hasExclusive(); }
auto hasContext() -> bool { return driver->hasContext(); } auto hasContext() -> bool { return instance->hasContext(); }
auto hasDevices() -> vector<string> { return driver->hasDevices(); } auto hasDevices() -> vector<string> { return instance->hasDevices(); }
auto hasBlocking() -> bool { return driver->hasBlocking(); } auto hasBlocking() -> bool { return instance->hasBlocking(); }
auto hasDynamic() -> bool { return driver->hasDynamic(); } auto hasDynamic() -> bool { return instance->hasDynamic(); }
auto hasChannels() -> vector<uint> { return driver->hasChannels(); } auto hasChannels() -> vector<uint> { return instance->hasChannels(); }
auto hasFrequencies() -> vector<uint> { return driver->hasFrequencies(); } auto hasFrequencies() -> vector<uint> { return instance->hasFrequencies(); }
auto hasLatencies() -> vector<uint> { return driver->hasLatencies(); } auto hasLatencies() -> vector<uint> { return instance->hasLatencies(); }
auto hasDevice(string device) -> bool { return driver->hasDevice(device); } auto hasDevice(string device) -> bool { return instance->hasDevice(device); }
auto hasChannels(uint channels) -> bool { return driver->hasChannels(channels); } auto hasChannels(uint channels) -> bool { return instance->hasChannels(channels); }
auto hasFrequency(uint frequency) -> bool { return driver->hasFrequency(frequency); } auto hasFrequency(uint frequency) -> bool { return instance->hasFrequency(frequency); }
auto hasLatency(uint latency) -> bool { return driver->hasLatency(latency); } auto hasLatency(uint latency) -> bool { return instance->hasLatency(latency); }
auto exclusive() -> bool { return driver->exclusive; } auto exclusive() -> bool { return instance->exclusive; }
auto context() -> uintptr { return driver->context; } auto context() -> uintptr { return instance->context; }
auto device() -> string { return driver->device; } auto device() -> string { return instance->device; }
auto blocking() -> bool { return driver->blocking; } auto blocking() -> bool { return instance->blocking; }
auto dynamic() -> bool { return driver->dynamic; } auto dynamic() -> bool { return instance->dynamic; }
auto channels() -> uint { return driver->channels; } auto channels() -> uint { return instance->channels; }
auto frequency() -> uint { return driver->frequency; } auto frequency() -> uint { return instance->frequency; }
auto latency() -> uint { return driver->latency; } auto latency() -> uint { return instance->latency; }
auto setExclusive(bool exclusive) -> bool; auto setExclusive(bool exclusive) -> bool;
auto setContext(uintptr context) -> bool; auto setContext(uintptr context) -> bool;
@ -100,6 +100,6 @@ struct Audio {
protected: protected:
Audio& self; Audio& self;
unique_pointer<AudioDriver> driver; unique_pointer<AudioDriver> instance;
vector<nall::DSP::Resampler::Cubic> resamplers; vector<nall::DSP::Resampler::Cubic> resamplers;
}; };

View File

@ -28,7 +28,7 @@ struct AudioOSS : AudioDriver {
return initialize(); return initialize();
} }
auto driverName() -> string override { return "OSS"; } auto driver() -> string override { return "OSS"; }
auto ready() -> bool override { return _fd >= 0; } auto ready() -> bool override { return _fd >= 0; }
auto hasBlocking() -> bool override { return true; } auto hasBlocking() -> bool override { return true; }

View File

@ -25,32 +25,32 @@
namespace ruby { namespace ruby {
auto Input::setContext(uintptr context) -> bool { auto Input::setContext(uintptr context) -> bool {
if(driver->context == context) return true; if(instance->context == context) return true;
if(!driver->hasContext()) return false; if(!instance->hasContext()) return false;
if(!driver->setContext(driver->context = context)) return false; if(!instance->setContext(instance->context = context)) return false;
return true; return true;
} }
// //
auto Input::acquired() -> bool { auto Input::acquired() -> bool {
return driver->acquired(); return instance->acquired();
} }
auto Input::acquire() -> bool { auto Input::acquire() -> bool {
return driver->acquire(); return instance->acquire();
} }
auto Input::release() -> bool { auto Input::release() -> bool {
return driver->release(); return instance->release();
} }
auto Input::poll() -> vector<shared_pointer<nall::HID::Device>> { auto Input::poll() -> vector<shared_pointer<nall::HID::Device>> {
return driver->poll(); return instance->poll();
} }
auto Input::rumble(uint64_t id, bool enable) -> bool { auto Input::rumble(uint64_t id, bool enable) -> bool {
return driver->rumble(id, enable); return instance->rumble(id, enable);
} }
// //
@ -66,36 +66,36 @@ auto Input::doChange(shared_pointer<HID::Device> device, uint group, uint input,
// //
auto Input::create(string driver) -> bool { auto Input::create(string driver) -> bool {
reset(); self.instance.reset();
if(!driver) driver = optimalDriver(); if(!driver) driver = optimalDriver();
#if defined(INPUT_WINDOWS) #if defined(INPUT_WINDOWS)
if(driver == "Windows") self.driver = new InputWindows(*this); if(driver == "Windows") self.instance = new InputWindows(*this);
#endif #endif
#if defined(INPUT_QUARTZ) #if defined(INPUT_QUARTZ)
if(driver == "Quartz") self.driver = new InputQuartz(*this); if(driver == "Quartz") self.instance = new InputQuartz(*this);
#endif #endif
#if defined(INPUT_CARBON) #if defined(INPUT_CARBON)
if(driver == "Carbon") self.driver = new InputCarbon(*this); if(driver == "Carbon") self.instance = new InputCarbon(*this);
#endif #endif
#if defined(INPUT_UDEV) #if defined(INPUT_UDEV)
if(driver == "udev") self.driver = new InputUdev(*this); if(driver == "udev") self.instance = new InputUdev(*this);
#endif #endif
#if defined(INPUT_SDL) #if defined(INPUT_SDL)
if(driver == "SDL") self.driver = new InputSDL(*this); if(driver == "SDL") self.instance = new InputSDL(*this);
#endif #endif
#if defined(INPUT_XLIB) #if defined(INPUT_XLIB)
if(driver == "Xlib") self.driver = new InputXlib(*this); if(driver == "Xlib") self.instance = new InputXlib(*this);
#endif #endif
if(!self.driver) self.driver = new InputDriver(*this); if(!self.instance) self.instance = new InputDriver(*this);
return self.driver->create(); return self.instance->create();
} }
auto Input::hasDrivers() -> vector<string> { auto Input::hasDrivers() -> vector<string> {

View File

@ -5,7 +5,7 @@ struct InputDriver {
virtual ~InputDriver() = default; virtual ~InputDriver() = default;
virtual auto create() -> bool { return true; } virtual auto create() -> bool { return true; }
virtual auto driverName() -> string { return "None"; } virtual auto driver() -> string { return "None"; }
virtual auto ready() -> bool { return true; } virtual auto ready() -> bool { return true; }
virtual auto hasContext() -> bool { return false; } virtual auto hasContext() -> bool { return false; }
@ -31,16 +31,16 @@ struct Input {
static auto optimalDriver() -> string; static auto optimalDriver() -> string;
static auto safestDriver() -> string; static auto safestDriver() -> string;
Input() : self(*this) {} Input() : self(*this) { reset(); }
explicit operator bool() const { return (bool)driver; } explicit operator bool() { return instance->driver() != "None"; }
auto reset() -> void { driver.reset(); } auto reset() -> void { instance = new InputDriver(*this); }
auto create(string driver = "") -> bool; auto create(string driver = "") -> bool;
auto driverName() -> string { return driver->driverName(); } auto driver() -> string { return instance->driver(); }
auto ready() -> bool { return driver->ready(); } auto ready() -> bool { return instance->ready(); }
auto hasContext() -> bool { return driver->hasContext(); } auto hasContext() -> bool { return instance->hasContext(); }
auto context() -> uintptr { return driver->context; } auto context() -> uintptr { return instance->context; }
auto setContext(uintptr context) -> bool; auto setContext(uintptr context) -> bool;
@ -55,6 +55,6 @@ struct Input {
protected: protected:
Input& self; Input& self;
unique_pointer<InputDriver> driver; unique_pointer<InputDriver> instance;
function<void (shared_pointer<nall::HID::Device> device, uint group, uint input, int16_t oldValue, int16_t newValue)> change; function<void (shared_pointer<nall::HID::Device> device, uint group, uint input, int16_t oldValue, int16_t newValue)> change;
}; };

View File

@ -16,7 +16,7 @@ struct InputSDL : InputDriver {
return initialize(); return initialize();
} }
auto driverName() -> string override { return "SDL"; } auto driver() -> string override { return "SDL"; }
auto ready() -> bool override { return isReady; } auto ready() -> bool override { return isReady; }
auto hasContext() -> bool override { return true; } auto hasContext() -> bool override { return true; }

View File

@ -32,7 +32,7 @@ struct VideoGLX2 : VideoDriver {
return initialize(); return initialize();
} }
auto driverName() -> string override { return "OpenGL2"; } auto driver() -> string override { return "OpenGL2"; }
auto ready() -> bool override { return _ready; } auto ready() -> bool override { return _ready; }
auto hasContext() -> bool override { return true; } auto hasContext() -> bool override { return true; }

View File

@ -37,74 +37,74 @@
namespace ruby { namespace ruby {
auto Video::setExclusive(bool exclusive) -> bool { auto Video::setExclusive(bool exclusive) -> bool {
if(driver->exclusive == exclusive) return true; if(instance->exclusive == exclusive) return true;
if(!driver->hasExclusive()) return false; if(!instance->hasExclusive()) return false;
if(!driver->setExclusive(driver->exclusive = exclusive)) return false; if(!instance->setExclusive(instance->exclusive = exclusive)) return false;
return true; return true;
} }
auto Video::setContext(uintptr context) -> bool { auto Video::setContext(uintptr context) -> bool {
if(driver->context == context) return true; if(instance->context == context) return true;
if(!driver->hasContext()) return false; if(!instance->hasContext()) return false;
if(!driver->setContext(driver->context = context)) return false; if(!instance->setContext(instance->context = context)) return false;
return true; return true;
} }
auto Video::setBlocking(bool blocking) -> bool { auto Video::setBlocking(bool blocking) -> bool {
if(driver->blocking == blocking) return true; if(instance->blocking == blocking) return true;
if(!driver->hasBlocking()) return false; if(!instance->hasBlocking()) return false;
if(!driver->setBlocking(driver->blocking = blocking)) return false; if(!instance->setBlocking(instance->blocking = blocking)) return false;
return true; return true;
} }
auto Video::setFlush(bool flush) -> bool { auto Video::setFlush(bool flush) -> bool {
if(driver->flush == flush) return true; if(instance->flush == flush) return true;
if(!driver->hasFlush()) return false; if(!instance->hasFlush()) return false;
if(!driver->setFlush(driver->flush = flush)) return false; if(!instance->setFlush(instance->flush = flush)) return false;
return true; return true;
} }
auto Video::setFormat(string format) -> bool { auto Video::setFormat(string format) -> bool {
if(driver->format == format) return true; if(instance->format == format) return true;
if(!driver->hasFormat(format)) return false; if(!instance->hasFormat(format)) return false;
if(!driver->setFormat(driver->format = format)) return false; if(!instance->setFormat(instance->format = format)) return false;
return true; return true;
} }
auto Video::setSmooth(bool smooth) -> bool { auto Video::setSmooth(bool smooth) -> bool {
if(driver->smooth == smooth) return true; if(instance->smooth == smooth) return true;
if(!driver->hasSmooth()) return false; if(!instance->hasSmooth()) return false;
if(!driver->setSmooth(driver->smooth = smooth)) return false; if(!instance->setSmooth(instance->smooth = smooth)) return false;
return true; return true;
} }
auto Video::setShader(string shader) -> bool { auto Video::setShader(string shader) -> bool {
if(driver->shader == shader) return true; if(instance->shader == shader) return true;
if(!driver->hasShader()) return false; if(!instance->hasShader()) return false;
if(!driver->setShader(driver->shader = shader)) return false; if(!instance->setShader(instance->shader = shader)) return false;
return true; return true;
} }
// //
auto Video::clear() -> void { auto Video::clear() -> void {
return driver->clear(); return instance->clear();
} }
auto Video::acquire(uint32_t*& data, uint& pitch, uint width, uint height) -> bool { auto Video::acquire(uint32_t*& data, uint& pitch, uint width, uint height) -> bool {
return driver->acquire(data, pitch, width, height); return instance->acquire(data, pitch, width, height);
} }
auto Video::release() -> void { auto Video::release() -> void {
return driver->release(); return instance->release();
} }
auto Video::output() -> void { auto Video::output() -> void {
return driver->output(); return instance->output();
} }
auto Video::poll() -> void { auto Video::poll() -> void {
return driver->poll(); return instance->poll();
} }
// //
@ -120,48 +120,48 @@ auto Video::doUpdate(uint width, uint height) -> void {
// //
auto Video::create(string driver) -> bool { auto Video::create(string driver) -> bool {
reset(); self.instance.reset();
if(!driver) driver = optimalDriver(); if(!driver) driver = optimalDriver();
#if defined(VIDEO_CGL) #if defined(VIDEO_CGL)
if(driver == "OpenGL") self.driver = new VideoCGL(*this); if(driver == "OpenGL") self.instance = new VideoCGL(*this);
#endif #endif
#if defined(VIDEO_DIRECT3D) #if defined(VIDEO_DIRECT3D)
if(driver == "Direct3D") self.driver = new VideoDirect3D(*this); if(driver == "Direct3D") self.instance = new VideoDirect3D(*this);
#endif #endif
#if defined(VIDEO_DIRECTDRAW) #if defined(VIDEO_DIRECTDRAW)
if(driver == "DirectDraw") self.driver = new VideoDirectDraw(*this); if(driver == "DirectDraw") self.instance = new VideoDirectDraw(*this);
#endif #endif
#if defined(VIDEO_GDI) #if defined(VIDEO_GDI)
if(driver == "GDI") self.driver = new VideoGDI(*this); if(driver == "GDI") self.instance = new VideoGDI(*this);
#endif #endif
#if defined(VIDEO_GLX) #if defined(VIDEO_GLX)
if(driver == "OpenGL") self.driver = new VideoGLX(*this); if(driver == "OpenGL") self.instance = new VideoGLX(*this);
#endif #endif
#if defined(VIDEO_GLX2) #if defined(VIDEO_GLX2)
if(driver == "OpenGL2") self.driver = new VideoGLX2(*this); if(driver == "OpenGL2") self.instance = new VideoGLX2(*this);
#endif #endif
#if defined(VIDEO_WGL) #if defined(VIDEO_WGL)
if(driver == "OpenGL") self.driver = new VideoWGL(*this); if(driver == "OpenGL") self.instance = new VideoWGL(*this);
#endif #endif
#if defined(VIDEO_XSHM) #if defined(VIDEO_XSHM)
if(driver == "XShm") self.driver = new VideoXShm(*this); if(driver == "XShm") self.instance = new VideoXShm(*this);
#endif #endif
#if defined(VIDEO_XVIDEO) #if defined(VIDEO_XVIDEO)
if(driver == "XVideo") self.driver = new VideoXVideo(*this); if(driver == "XVideo") self.instance = new VideoXVideo(*this);
#endif #endif
if(!self.driver) self.driver = new VideoDriver(*this); if(!self.instance) self.instance = new VideoDriver(*this);
return self.driver->create(); return self.instance->create();
} }
auto Video::hasDrivers() -> vector<string> { auto Video::hasDrivers() -> vector<string> {

View File

@ -5,7 +5,7 @@ struct VideoDriver {
virtual ~VideoDriver() = default; virtual ~VideoDriver() = default;
virtual auto create() -> bool { return true; } virtual auto create() -> bool { return true; }
virtual auto driverName() -> string { return "None"; } virtual auto driver() -> string { return "None"; }
virtual auto ready() -> bool { return true; } virtual auto ready() -> bool { return true; }
virtual auto hasExclusive() -> bool { return false; } virtual auto hasExclusive() -> bool { return false; }
@ -51,30 +51,30 @@ struct Video {
static auto optimalDriver() -> string; static auto optimalDriver() -> string;
static auto safestDriver() -> string; static auto safestDriver() -> string;
Video() : self(*this) {} Video() : self(*this) { reset(); }
explicit operator bool() const { return (bool)driver; } explicit operator bool() { return instance->driver() != "None"; }
auto reset() -> void { driver.reset(); } auto reset() -> void { instance = new VideoDriver(*this); }
auto create(string driver = "") -> bool; auto create(string driver = "") -> bool;
auto driverName() -> string { return driver->driverName(); } auto driver() -> string { return instance->driver(); }
auto ready() -> bool { return driver->ready(); } auto ready() -> bool { return instance->ready(); }
auto hasExclusive() -> bool { return driver->hasExclusive(); } auto hasExclusive() -> bool { return instance->hasExclusive(); }
auto hasContext() -> bool { return driver->hasContext(); } auto hasContext() -> bool { return instance->hasContext(); }
auto hasBlocking() -> bool { return driver->hasBlocking(); } auto hasBlocking() -> bool { return instance->hasBlocking(); }
auto hasFlush() -> bool { return driver->hasFlush(); } auto hasFlush() -> bool { return instance->hasFlush(); }
auto hasFormats() -> vector<string> { return driver->hasFormats(); } auto hasFormats() -> vector<string> { return instance->hasFormats(); }
auto hasSmooth() -> bool { return driver->hasSmooth(); } auto hasSmooth() -> bool { return instance->hasSmooth(); }
auto hasShader() -> bool { return driver->hasShader(); } auto hasShader() -> bool { return instance->hasShader(); }
auto hasFormat(string format) -> bool { return driver->hasFormat(format); } auto hasFormat(string format) -> bool { return instance->hasFormat(format); }
auto exclusive() -> bool { return driver->exclusive; } auto exclusive() -> bool { return instance->exclusive; }
auto context() -> uintptr { return driver->context; } auto context() -> uintptr { return instance->context; }
auto blocking() -> bool { return driver->blocking; } auto blocking() -> bool { return instance->blocking; }
auto flush() -> bool { return driver->flush; } auto flush() -> bool { return instance->flush; }
auto format() -> string { return driver->format; } auto format() -> string { return instance->format; }
auto smooth() -> bool { return driver->smooth; } auto smooth() -> bool { return instance->smooth; }
auto shader() -> string { return driver->shader; } auto shader() -> string { return instance->shader; }
auto setExclusive(bool exclusive) -> bool; auto setExclusive(bool exclusive) -> bool;
auto setContext(uintptr context) -> bool; auto setContext(uintptr context) -> bool;
@ -95,6 +95,6 @@ struct Video {
protected: protected:
Video& self; Video& self;
unique_pointer<VideoDriver> driver; unique_pointer<VideoDriver> instance;
function<void (uint, uint)> update; function<void (uint, uint)> update;
}; };

View File

@ -18,7 +18,7 @@ struct VideoXShm : VideoDriver {
return initialize(); return initialize();
} }
auto driverName() -> string override { return "XShm"; } auto driver() -> string override { return "XShm"; }
auto ready() -> bool override { return _ready; } auto ready() -> bool override { return _ready; }
auto hasContext() -> bool override { return true; } auto hasContext() -> bool override { return true; }