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().select(locale);
emulator = new SuperFamicom::Interface;
new Program(arguments);
program.create(arguments);
Application::run();
}

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -1,7 +1,7 @@
auto Program::updateAudioDriver(Window parent) -> void {
auto changed = (bool)audio;
audio.create(settings["Audio/Driver"].text());
audio.setContext(presentation->viewport.handle());
audio.setContext(presentation.viewport.handle());
audio.setChannels(2);
if(changed) {
settings["Audio/Device"].setValue(audio.device());
@ -54,7 +54,7 @@ auto Program::updateAudioFrequency() -> void {
}
audio.setFrequency(settings["Audio/Frequency"].real());
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();
}
Emulator::audio.setFrequency(frequency);

View File

@ -3,14 +3,14 @@ auto Program::load() -> void {
if(auto configuration = string::read(locate("configuration.bml"))) {
emulator->configure(configuration);
settingsWindow->configuration.updateConfiguration();
emulatorSettings.updateConfiguration();
}
if(!emulator->load()) return;
gameQueue = {};
screenshot = {};
frameAdvance = false;
if(!verified() && settingsWindow->configuration.warnOnUnverifiedGames.checked()) {
if(!verified() && emulatorSettings.warnOnUnverifiedGames.checked()) {
auto response = MessageDialog(
"Warning: this game image is unverified.\n"
"Running it *may* be a security risk.\n\n"
@ -21,37 +21,37 @@ auto Program::load() -> void {
return showMessage("Game loading cancelled");
}
if(response == "Always") {
settingsWindow->configuration.warnOnUnverifiedGames.setChecked(false).doToggle();
emulatorSettings.warnOnUnverifiedGames.setChecked(false).doToggle();
}
}
hackCompatibility();
emulator->power();
if(settingsWindow->configuration.autoLoadStateOnLoad.checked()) {
program->loadState("quick/undo");
if(emulatorSettings.autoLoadStateOnLoad.checked()) {
program.loadState("quick/undo");
}
showMessage({
verified() ? "Verified game loaded" : "Game loaded",
appliedPatch() ? " and patch applied" : ""
});
presentation->setTitle(emulator->titles().merge(" + "));
presentation->resetSystem.setEnabled(true);
presentation->unloadGame.setEnabled(true);
presentation->toolsMenu.setVisible(true);
presentation->updateStateMenus();
presentation->speedNormal.setChecked();
presentation->pauseEmulation.setChecked(false);
presentation->updateStatusIcon();
presentation->resizeViewport();
toolsWindow->cheatEditor.loadCheats();
toolsWindow->stateManager.loadStates();
toolsWindow->manifestViewer.loadManifest();
presentation.setTitle(emulator->titles().merge(" + "));
presentation.resetSystem.setEnabled(true);
presentation.unloadGame.setEnabled(true);
presentation.toolsMenu.setVisible(true);
presentation.updateStateMenus();
presentation.speedNormal.setChecked();
presentation.pauseEmulation.setChecked(false);
presentation.updateStatusIcon();
presentation.resizeViewport();
cheatEditor.loadCheats();
stateManager.loadStates();
manifestViewer.loadManifest();
string locations = superFamicom.location;
if(auto& location = gameBoy.location) locations.append("|", location);
if(auto& location = bsMemory.location) locations.append("|", location);
if(auto& location = sufamiTurboA.location) locations.append("|", location);
if(auto& location = sufamiTurboB.location) locations.append("|", location);
presentation->addRecentGame(locations);
presentation.addRecentGame(locations);
updateVideoPalette();
updateAudioEffects();
@ -283,9 +283,9 @@ auto Program::reset() -> void {
auto Program::unload() -> void {
if(!emulator->loaded()) return;
toolsWindow->cheatEditor.saveCheats();
toolsWindow->setVisible(false);
if(settingsWindow->configuration.autoSaveStateOnUnload.checked()) {
cheatEditor.saveCheats();
toolsWindow.setVisible(false);
if(emulatorSettings.autoSaveStateOnUnload.checked()) {
saveUndoState();
}
if(auto configuration = emulator->configuration()) {
@ -298,12 +298,12 @@ auto Program::unload() -> void {
bsMemory = {};
sufamiTurboA = {};
sufamiTurboB = {};
presentation->setTitle({"bsnes v", Emulator::Version});
presentation->resetSystem.setEnabled(false);
presentation->unloadGame.setEnabled(false);
presentation->toolsMenu.setVisible(false);
presentation->updateStatusIcon();
presentation->clearViewport();
presentation.setTitle({"bsnes v", Emulator::Version});
presentation.resetSystem.setEnabled(false);
presentation.unloadGame.setEnabled(false);
presentation.toolsMenu.setVisible(false);
presentation.updateStatusIcon();
presentation.clearViewport();
}
//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 {
bool fastPPU = settingsWindow->configuration.fastPPUOption.checked();
bool fastPPUNoSpriteLimit = settingsWindow->configuration.noSpriteLimit.checked();
bool fastPPUHiresMode7 = settingsWindow->configuration.hiresMode7.checked();
bool fastDSP = settingsWindow->configuration.fastDSPOption.checked();
bool fastPPU = emulatorSettings.fastPPUOption.checked();
bool fastPPUNoSpriteLimit = emulatorSettings.noSpriteLimit.checked();
bool fastPPUHiresMode7 = emulatorSettings.hiresMode7.checked();
bool fastDSP = emulatorSettings.fastDSPOption.checked();
auto label = superFamicom.label;
if(label == "AIR STRIKE PATROL" || label == "DESERT FIGHTER") fastPPU = false;
if(label == "KOUSHIEN_2") 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/No Sprite Limit", fastPPUNoSpriteLimit);
emulator->set("Fast PPU/Hires Mode 7", fastPPUHiresMode7);
@ -33,7 +34,7 @@ auto Program::hackPatchMemory(vector<uint8_t>& data) -> void {
auto Program::hackOverclockSuperFX() -> void {
//todo: implement a better way of detecting SuperFX games
//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;
auto label = superFamicom.label;

View File

@ -1,13 +1,13 @@
auto Program::updateInputDriver(Window parent) -> void {
auto changed = (bool)input;
input.create(settings["Input/Driver"].text());
input.setContext(presentation->viewport.handle());
input.setContext(presentation.viewport.handle());
if(changed) {
}
inputManager->initialize();
settingsWindow->input.reloadPorts();
settingsWindow->hotkeys.reloadMappings();
inputManager.initialize();
inputSettings.reloadPorts();
hotkeySettings.reloadMappings();
if(!input.ready()) {
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",
"Would you like to view the online documentation for more information?"
}).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;
pitch >>= 2;
if(presentation->overscanCropping.checked()) {
if(presentation.overscanCropping.checked()) {
if(height == 240) data += 8 * pitch, height -= 16;
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();
}
inputManager->frame();
inputManager.frame();
if(frameAdvance) {
frameAdvance = false;
presentation->pauseEmulation.setChecked();
presentation.pauseEmulation.setChecked();
}
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 {
if(focused() || settingsWindow->configuration.allowInput().checked()) {
inputManager->poll();
if(auto mapping = inputManager->mapping(port, device, input)) {
if(focused() || emulatorSettings.allowInput().checked()) {
inputManager.poll();
if(auto mapping = inputManager.mapping(port, device, input)) {
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 {
if(focused() || settingsWindow->configuration.allowInput().checked() || !enable) {
if(auto mapping = inputManager->mapping(port, device, input)) {
if(focused() || emulatorSettings.allowInput().checked() || !enable) {
if(auto mapping = inputManager.mapping(port, device, input)) {
return mapping->rumble(enable);
}
}

View File

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

View File

@ -2,7 +2,7 @@ struct Program : Emulator::Platform {
Application::Namespace tr{"Program"};
//program.cpp
Program(vector<string> arguments);
auto create(vector<string> arguments) -> void;
auto main() -> void;
auto quit() -> void;
@ -147,4 +147,4 @@ public:
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());
}
if(filename.beginsWith("quick/")) presentation->updateStateMenus();
if(filename.beginsWith("quick/")) presentation.updateStateMenus();
return showMessage({"Saved [", prefix, "]"}), true;
}

View File

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

View File

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

View File

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

View File

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

View File

@ -1,6 +1,6 @@
ConfigurationSettings::ConfigurationSettings(TabFrame* parent) : TabFrameItem(parent) {
auto EmulatorSettings::create() -> void {
setIcon(Icon::Action::Settings);
setText("Configuration");
setText("Emulator");
layout.setPadding(5);
@ -40,7 +40,7 @@ ConfigurationSettings::ConfigurationSettings(TabFrame* parent) : TabFrameItem(pa
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([&] {
settings["Emulator/Hack/FastPPU"].setValue(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.");
}
auto ConfigurationSettings::updateConfiguration() -> void {
auto EmulatorSettings::updateConfiguration() -> void {
emulator->configure("hacks/ppuFast/enable", fastPPUOption.checked());
emulator->configure("hacks/ppuFast/noSpriteLimit", noSpriteLimit.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);
setText("Hotkeys");
@ -17,7 +17,7 @@ HotkeySettings::HotkeySettings(TabFrame* parent) : TabFrameItem(parent) {
});
clearButton.setText("Clear").onActivate([&] {
for(auto item : mappingList.batched()) {
inputManager->hotkeys[item.offset()].unbind();
inputManager.hotkeys[item.offset()].unbind();
}
refreshMappings();
});
@ -29,7 +29,7 @@ auto HotkeySettings::reloadMappings() -> void {
.append(TableViewColumn().setText("Name"))
.append(TableViewColumn().setText("Mapping").setExpandable())
);
for(auto& hotkey : inputManager->hotkeys) {
for(auto& hotkey : inputManager.hotkeys) {
mappingList.append(TableViewItem()
.append(TableViewCell().setText(hotkey.name).setFont(Font().setBold()).setBackgroundColor({240, 240, 255}))
.append(TableViewCell())
@ -41,29 +41,29 @@ auto HotkeySettings::reloadMappings() -> void {
auto HotkeySettings::refreshMappings() -> void {
uint index = 0;
for(auto& hotkey : inputManager->hotkeys) {
for(auto& hotkey : inputManager.hotkeys) {
mappingList.item(index++).cell(1).setText(hotkey.displayName());
}
mappingList.resizeColumns();
}
auto HotkeySettings::assignMapping() -> void {
inputManager->poll(); //clear any pending events first
inputManager.poll(); //clear any pending events first
if(auto item = mappingList.selected()) {
activeMapping = inputManager->hotkeys[item.offset()];
settingsWindow->layout.setEnabled(false);
settingsWindow->statusBar.setText({"Press a key or button to map [", activeMapping->name, "] ..."});
settingsWindow->setDismissable(false);
activeMapping = inputManager.hotkeys[item.offset()];
settingsWindow.layout.setEnabled(false);
settingsWindow.statusBar.setText({"Press a key or button to map [", activeMapping->name, "] ..."});
settingsWindow.setDismissable(false);
}
}
auto HotkeySettings::cancelMapping() -> void {
activeMapping.reset();
settingsWindow->statusBar.setText();
settingsWindow->layout.setEnabled();
settingsWindow->doSize();
settingsWindow->setDismissable(true);
settingsWindow.statusBar.setText();
settingsWindow.layout.setEnabled();
settingsWindow.doSize();
settingsWindow.setDismissable(true);
}
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)) {
activeMapping.reset();
settingsWindow->statusBar.setText("Mapping assigned.");
settingsWindow.statusBar.setText("Mapping assigned.");
refreshMappings();
timer.onActivate([&] {
timer.setEnabled(false);

View File

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

View File

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

View File

@ -4,10 +4,17 @@
#include "input.cpp"
#include "hotkeys.cpp"
#include "paths.cpp"
#include "configuration.cpp"
#include "emulator.cpp"
#include "drivers.cpp"
Settings settings;
unique_pointer<SettingsWindow> settingsWindow;
VideoSettings videoSettings;
AudioSettings audioSettings;
InputSettings inputSettings;
HotkeySettings hotkeySettings;
PathSettings pathSettings;
EmulatorSettings emulatorSettings;
DriverSettings driverSettings;
SettingsWindow settingsWindow;
Settings::Settings() {
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));
}
SettingsWindow::SettingsWindow() {
settingsWindow = this;
auto SettingsWindow::create() -> void {
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());
setTitle("Settings");
@ -96,21 +108,21 @@ SettingsWindow::SettingsWindow() {
setDismissable();
onSize([&] {
input.mappingList.resizeColumns();
hotkeys.mappingList.resizeColumns();
inputSettings.mappingList.resizeColumns();
hotkeySettings.mappingList.resizeColumns();
});
onClose([&] {
if(input.activeMapping) input.cancelMapping();
if(hotkeys.activeMapping) hotkeys.cancelMapping();
if(inputSettings.activeMapping) inputSettings.cancelMapping();
if(hotkeySettings.activeMapping) hotkeySettings.cancelMapping();
setVisible(false);
});
}
auto SettingsWindow::setVisible(bool visible) -> SettingsWindow& {
if(visible) {
input.refreshMappings();
hotkeys.refreshMappings();
inputSettings.refreshMappings();
hotkeySettings.refreshMappings();
}
return Window::setVisible(visible), *this;
}

View File

@ -4,7 +4,7 @@ struct Settings : Markup::Node {
};
struct VideoSettings : TabFrameItem {
VideoSettings(TabFrame*);
auto create() -> void;
public:
VerticalLayout layout{this};
@ -24,7 +24,7 @@ public:
};
struct AudioSettings : TabFrameItem {
AudioSettings(TabFrame*);
auto create() -> void;
public:
VerticalLayout layout{this};
@ -44,7 +44,7 @@ public:
};
struct InputSettings : TabFrameItem {
InputSettings(TabFrame*);
auto create() -> void;
auto updateControls() -> void;
auto activePort() -> InputPort&;
auto activeDevice() -> InputDevice&;
@ -80,7 +80,7 @@ public:
};
struct HotkeySettings : TabFrameItem {
HotkeySettings(TabFrame*);
auto create() -> void;
auto reloadMappings() -> void;
auto refreshMappings() -> void;
auto assignMapping() -> void;
@ -100,7 +100,7 @@ public:
};
struct PathSettings : TabFrameItem {
PathSettings(TabFrame*);
auto create() -> void;
auto refreshPaths() -> void;
public:
@ -136,8 +136,8 @@ public:
Button screenshotsReset{&layout, Size{80, 0}};
};
struct ConfigurationSettings : TabFrameItem {
ConfigurationSettings(TabFrame*);
struct EmulatorSettings : TabFrameItem {
auto create() -> void;
auto updateConfiguration() -> void;
public:
@ -155,6 +155,7 @@ public:
CheckLabel autoSaveStateOnUnload{&autoStateLayout, Size{0, 0}};
CheckLabel autoLoadStateOnLoad{&autoStateLayout, Size{0, 0}};
CheckLabel suppressScreenSaver{&layout, Size{~0, 0}};
Widget optionsSpacer{&layout, Size{~0, 10}};
Label hacksLabel{&layout, Size{~0, 0}, 2};
HorizontalLayout fastPPULayout{&layout, Size{~0, 0}};
CheckLabel fastPPUOption{&fastPPULayout, Size{0, 0}};
@ -169,7 +170,7 @@ public:
};
struct DriverSettings : TabFrameItem {
DriverSettings(TabFrame*);
auto create() -> void;
auto videoDriverChanged() -> void;
auto videoDriverChange() -> void;
auto videoFormatChanged() -> void;
@ -201,6 +202,7 @@ public:
CheckLabel videoExclusiveToggle{&videoToggleLayout, Size{0, 0}};
CheckLabel videoBlockingToggle{&videoToggleLayout, Size{0, 0}};
CheckLabel videoFlushToggle{&videoToggleLayout, Size{0, 0}};
Widget videoSpacer{&layout, Size{~0, 10}};
Label audioLabel{&layout, Size{~0, 0}, 2};
TableLayout audioLayout{&layout, Size{~0, 0}};
Label audioDriverLabel{&audioLayout, Size{0, 0}};
@ -219,6 +221,7 @@ public:
CheckLabel audioExclusiveToggle{&audioToggleLayout, Size{0, 0}};
CheckLabel audioBlockingToggle{&audioToggleLayout, Size{0, 0}};
CheckLabel audioDynamicToggle{&audioToggleLayout, Size{0, 0}};
Widget audioSpacer{&layout, Size{~0, 10}};
Label inputLabel{&layout, Size{~0, 0}, 2};
TableLayout inputLayout{&layout, Size{~0, 0}};
Label inputDriverLabel{&inputLayout, Size{0, 0}};
@ -229,22 +232,22 @@ public:
};
struct SettingsWindow : Window {
SettingsWindow();
auto create() -> void;
auto setVisible(bool visible = true) -> SettingsWindow&;
auto show(uint index) -> void;
public:
VerticalLayout layout{this};
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};
};
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);
setText("Video");
@ -13,7 +13,7 @@ VideoSettings::VideoSettings(TabFrame* parent) : TabFrameItem(parent) {
string value = {luminanceSlider.position(), "%"};
settings["Video/Luminance"].setValue(value);
luminanceValue.setText(value);
program->updateVideoPalette();
program.updateVideoPalette();
}).doChange();
saturationLabel.setText("Saturation:");
saturationValue.setAlignment(0.5);
@ -21,7 +21,7 @@ VideoSettings::VideoSettings(TabFrame* parent) : TabFrameItem(parent) {
string value = {saturationSlider.position(), "%"};
settings["Video/Saturation"].setValue(value);
saturationValue.setText(value);
program->updateVideoPalette();
program.updateVideoPalette();
}).doChange();
gammaLabel.setText("Gamma:");
gammaValue.setAlignment(0.5);
@ -29,6 +29,6 @@ VideoSettings::VideoSettings(TabFrame* parent) : TabFrameItem(parent) {
string value = {100 + gammaSlider.position(), "%"};
settings["Video/Gamma"].setValue(value);
gammaValue.setText(value);
program->updateVideoPalette();
program.updateVideoPalette();
}).doChange();
}

View File

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

View File

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

View File

@ -1,6 +1,4 @@
StateWindow::StateWindow() {
stateWindow = this;
auto StateWindow::create() -> void {
layout.setPadding(5);
nameLabel.setText("Name:");
nameValue.onActivate([&] {
@ -48,7 +46,7 @@ auto StateWindow::doChange() -> void {
|| c == '|') valid = false;
}
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});
acceptButton.setEnabled(valid);
@ -56,14 +54,14 @@ auto StateWindow::doChange() -> void {
auto StateWindow::doAccept() -> void {
if(acceptButton.text() == "Add") {
toolsWindow->stateManager.createState(nameValue.text());
stateManager.createState(nameValue.text());
} else {
toolsWindow->stateManager.modifyState(nameValue.text());
stateManager.modifyState(nameValue.text());
}
setVisible(false);
}
StateManager::StateManager(TabFrame* parent) : TabFrameItem(parent) {
auto StateManager::create() -> void {
setIcon(Icon::Application::FileManager);
setText("State Manager");
@ -82,22 +80,22 @@ StateManager::StateManager(TabFrame* parent) : TabFrameItem(parent) {
loadButton.setText("Load").onActivate([&] {
if(auto item = stateList.selected()) {
string filename = {"managed/", item.cell(0).text()};
program->loadState(filename);
program.loadState(filename);
}
});
saveButton.setText("Save").onActivate([&] {
if(auto item = stateList.selected()) {
string filename = {"managed/", item.cell(0).text()};
program->saveState(filename);
item.cell(1).setText(chrono::local::datetime(program->stateTimestamp(filename)));
program.saveState(filename);
item.cell(1).setText(chrono::local::datetime(program.stateTimestamp(filename)));
}
});
addButton.setText("Add").onActivate([&] {
stateWindow->show();
stateWindow.show();
});
editButton.setText("Edit").onActivate([&] {
if(auto item = stateList.selected()) {
stateWindow->show(item.cell(0).text());
stateWindow.show(item.cell(0).text());
}
});
removeButton.setText("Remove").onActivate([&] {
@ -111,17 +109,17 @@ auto StateManager::loadStates() -> void {
.append(TableViewColumn().setText("Name").setExpandable())
.append(TableViewColumn().setText("Date").setForegroundColor({160, 160, 160}))
);
for(auto& filename : program->availableStates("managed/")) {
for(auto& filename : program.availableStates("managed/")) {
stateList.append(TableViewItem()
.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();
}
auto StateManager::createState(string name) -> void {
program->saveState({"managed/", name});
program.saveState({"managed/", name});
loadStates();
for(auto& item : stateList.items()) {
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 to = {"managed/", name};
if(from != to) {
program->renameState(from, to);
program.renameState(from, to);
loadStates();
for(auto& item : stateList.items()) {
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)?")
.setParent(*toolsWindow).question() == "Yes") {
for(auto& item : batched) {
program->removeState({"managed/", item.cell(0).text()});
program.removeState({"managed/", item.cell(0).text()});
}
loadStates();
}

View File

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

View File

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

View File

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

View File

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

View File

@ -40,7 +40,7 @@ auto mMenuBar::remove() -> type& {
auto mMenuBar::remove(sMenu menu) -> type& {
signed offset = menu->offset();
signal(remove, *menu);
signal(remove, menu);
state.menus.remove(offset);
for(auto n : range(offset, menuCount())) {
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& {
signal(setParent, parent, offset);
destruct();
state.parent = parent;
state.offset = offset;

View File

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

View File

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

View File

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

View File

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

View File

@ -63,36 +63,6 @@ auto pTabFrame::destruct() -> void {
auto pTabFrame::append(sTabFrameItem item) -> 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);
setFont(self().font(true));
setItemMovable(item->offset(), item->movable());
if(item->selected()) setItemSelected(item->offset());
@ -210,6 +180,42 @@ auto pTabFrame::setNavigation(Navigation navigation) -> void {
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 {
for(auto& item : state().items) {
if(auto& sizable = item->state.sizable) {

View File

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

View File

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

View File

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

View File

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

View File

@ -14,7 +14,6 @@ struct pTableViewColumn : pObject {
auto setForegroundColor(Color color) -> void;
auto setHorizontalAlignment(double alignment) -> void;
auto setIcon(const image& icon) -> void;
auto setParent(mObject* parent, int offset) -> void override;
auto setResizable(bool resizable) -> void;
auto setSortable(bool sortable) -> 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::setParent(mObject* parent, int offset) -> void {
}
auto pObject::setVisible(bool visible) -> void {
}

View File

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

View File

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

View File

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

View File

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

View File

@ -25,32 +25,32 @@
namespace ruby {
auto Input::setContext(uintptr context) -> bool {
if(driver->context == context) return true;
if(!driver->hasContext()) return false;
if(!driver->setContext(driver->context = context)) return false;
if(instance->context == context) return true;
if(!instance->hasContext()) return false;
if(!instance->setContext(instance->context = context)) return false;
return true;
}
//
auto Input::acquired() -> bool {
return driver->acquired();
return instance->acquired();
}
auto Input::acquire() -> bool {
return driver->acquire();
return instance->acquire();
}
auto Input::release() -> bool {
return driver->release();
return instance->release();
}
auto Input::poll() -> vector<shared_pointer<nall::HID::Device>> {
return driver->poll();
return instance->poll();
}
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 {
reset();
self.instance.reset();
if(!driver) driver = optimalDriver();
#if defined(INPUT_WINDOWS)
if(driver == "Windows") self.driver = new InputWindows(*this);
if(driver == "Windows") self.instance = new InputWindows(*this);
#endif
#if defined(INPUT_QUARTZ)
if(driver == "Quartz") self.driver = new InputQuartz(*this);
if(driver == "Quartz") self.instance = new InputQuartz(*this);
#endif
#if defined(INPUT_CARBON)
if(driver == "Carbon") self.driver = new InputCarbon(*this);
if(driver == "Carbon") self.instance = new InputCarbon(*this);
#endif
#if defined(INPUT_UDEV)
if(driver == "udev") self.driver = new InputUdev(*this);
if(driver == "udev") self.instance = new InputUdev(*this);
#endif
#if defined(INPUT_SDL)
if(driver == "SDL") self.driver = new InputSDL(*this);
if(driver == "SDL") self.instance = new InputSDL(*this);
#endif
#if defined(INPUT_XLIB)
if(driver == "Xlib") self.driver = new InputXlib(*this);
if(driver == "Xlib") self.instance = new InputXlib(*this);
#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> {

View File

@ -5,7 +5,7 @@ struct InputDriver {
virtual ~InputDriver() = default;
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 hasContext() -> bool { return false; }
@ -31,16 +31,16 @@ struct Input {
static auto optimalDriver() -> string;
static auto safestDriver() -> string;
Input() : self(*this) {}
explicit operator bool() const { return (bool)driver; }
auto reset() -> void { driver.reset(); }
Input() : self(*this) { reset(); }
explicit operator bool() { return instance->driver() != "None"; }
auto reset() -> void { instance = new InputDriver(*this); }
auto create(string driver = "") -> bool;
auto driverName() -> string { return driver->driverName(); }
auto ready() -> bool { return driver->ready(); }
auto driver() -> string { return instance->driver(); }
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;
@ -55,6 +55,6 @@ struct Input {
protected:
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;
};

View File

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

View File

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

View File

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

View File

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

View File

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