mirror of https://github.com/bsnes-emu/bsnes.git
Update to v103r10 release.
byuu says: Changelog: - tomoko: video scaling options are now resolutions in the configuration file, eg "640x480", "960x720", "1280x960" - tomoko: main window is now always resizable instead of fixed width (also supports maximizing) - tomoko: added support for non-integral scaling in windowed mode - tomoko: made the quick/managed state messaging more consistent - tomoko: hide "Find Codes ..." button from the cheat editor window if the cheat database is not present - tomoko: per-game cheats.bml file now goes into the higan/ subfolder instead of the root folder So the way the new video system works is you have the following options on the video settings panel: Windowed mode: { Aspect correction, Integral scaling, Adaptive } Fullscreen mode: { Aspect correction, Integral scaling } (and one day, hopefully Exclusive will be added here) Whenever you adjust the overscan masking, or you change any of the windowed or fullscreen mode settings, or you choose a different video scale from the main menu, or you load a new game, or you unload a game, or you rotate the display of an emulated system, the resizeViewport logic will be invoked. This logic will remember the last option you chose for video scale, and base the new window size on that value as an upper limit of the new window size. If you are in windowed mode and have adaptive enabled, it will shrink the window to fit the contents of the emulated system's video output. Otherwise, if you are not in integral scaling mode, it will scale the video as large as possible to fit into the video scaled size you have selected. Otherwise, it will perform an integral scale and center the video inside of the viewport. If you are in fullscreen mode, it's much the same, only there is no adaptive mode. A major problem with Xorg is that it's basically impossible to change the resizability attribute of a window post-creation. You can do it, but all kinds of crazy issues start popping up. Like if you toggle fullscreen, then you'll find that the window won't grow past a certain fairly small size that it's already at, and cannot be shrunk. And the multipliers will stop expanding the window as large as they should. And sometimes the UI elements won't be placed in the correct position, or the video will draw over them. It's a big mess. So I have to keep the main window always resizable. Also, note that this is not a limitation of hiro. It's just totally broken in Xorg itself. No amount of fiddling has ever allowed this to work reliably for me on either GTK+ 2 or Qt 4. So what this means is ... the adaptive mode window is also resizable. What happens here is, whenever you drag the corners of the main window to resize it, or toggle the maximize window button, higan will bypass the video scale resizing code and instead act as though the adaptive scaling mode were disabled. So if integral scaling is checked, it'll begin scaling in integral mode. Otherwise, it'll begin scaling in non-integral mode. And because of this flexibility, it no longer made sense for the video scale menu to be a radio box. I know, it sucks to not see what the active selection is anymore, but ... say you set the scale to small, then you accidentally resized the window a little, but want it snapped back to the proper small resolution dimensions. If it were a radio item, you couldn't reselect the same option again, because it's already active and events don't propagate in said case. By turning them into regular menu options, the video scale menu can be used to restore window sizing. Errata: On Windows, the main window blinks a few times on first load. The fix for that is a safeguard in the video settings code, roughly like so ... but note you'd need to make a few other changes for this to work against v103r10: auto VideoSettings::updateViewport(bool firstRun) -> void { settings["Video/Overscan/Horizontal"].setValue(horizontalMaskSlider.position()); settings["Video/Overscan/Vertical"].setValue(verticalMaskSlider.position()); settings["Video/Windowed/AspectCorrection"].setValue(windowedModeAspectCorrection.checked()); settings["Video/Windowed/IntegralScaling"].setValue(windowedModeIntegralScaling.checked()); settings["Video/Windowed/AdaptiveSizing"].setValue(windowedModeAdaptiveSizing.checked()); settings["Video/Fullscreen/AspectCorrection"].setValue(fullscreenModeAspectCorrection.checked()); settings["Video/Fullscreen/IntegralScaling"].setValue(fullscreenModeIntegralScaling.checked()); horizontalMaskValue.setText({horizontalMaskSlider.position()}); verticalMaskValue.setText({verticalMaskSlider.position()}); if(!firstRun) presentation->resizeViewport(); } That'll get it down to one blink, as with v103 official. Not sure I can eliminate that one extra blink. I forgot to remove the setResizable toggle on fullscreen mode exit. On Windows, the main window will end up unresizable after toggling fullscreen. I missed that one because like I said, toggling resizability is totally broken on Xorg. You can fix that with the below change: auto Presentation::toggleFullScreen() -> void { if(!fullScreen()) { menuBar.setVisible(false); statusBar.setVisible(false); //setResizable(true); setFullScreen(true); if(!input->acquired()) input->acquire(); } else { if(input->acquired()) input->release(); setFullScreen(false); //setResizable(false); menuBar.setVisible(true); statusBar.setVisible(settings["UserInterface/ShowStatusBar"].boolean()); } resizeViewport(); } Windows is stealing focus on calls to resizeViewport(), so we need to deal with that somehow ... I'm not really concerned about the behavior of shrinking the viewport below the smallest multiplier for a given system. It might make sense to snap it to the window size and forego all other scaling, but honestly ... meh. I don't really care. Nobody sane is going to play like that.
This commit is contained in:
parent
7af270aa59
commit
cbbf5ec114
|
@ -12,7 +12,7 @@ using namespace nall;
|
||||||
|
|
||||||
namespace Emulator {
|
namespace Emulator {
|
||||||
static const string Name = "higan";
|
static const string Name = "higan";
|
||||||
static const string Version = "103.09";
|
static const string Version = "103.10";
|
||||||
static const string Author = "byuu";
|
static const string Author = "byuu";
|
||||||
static const string License = "GPLv3";
|
static const string License = "GPLv3";
|
||||||
static const string Website = "http://byuu.org/";
|
static const string Website = "http://byuu.org/";
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
//DSP clock (~24576khz) / 12 (~2048khz) is fed into the SMP
|
//DSP clock (~24576khz) / 12 (~2048khz) is fed into the SMP
|
||||||
//from here, the wait states value is really a clock divider of {2, 4, 8, 16}
|
//from here, the wait states value is really a clock divider of {2, 4, 8, 16}
|
||||||
//because dividers of 8 and 16 are not evenly divislbe into 12, the SMP glitches
|
//due to an unknown hardware issue, clock dividers of 8 and 16 are glitchy
|
||||||
//in these two cases, the SMP ends up consuming 10 and 20 cycles instead
|
//the SMP ends up consuming 10 and 20 clocks per opcode cycle instead
|
||||||
//this causes unpredictable behavior on real hardware
|
//this causes unpredictable behavior on real hardware
|
||||||
//sometimes the SMP will run far slower than expected
|
//sometimes the SMP will run far slower than expected
|
||||||
//other times (and more likely), the SMP will deadlock until the system is reset
|
//other times (and more likely), the SMP will deadlock until the system is reset
|
||||||
|
|
|
@ -30,14 +30,15 @@ Settings::Settings() {
|
||||||
set("Video/Overscan/Vertical", 8);
|
set("Video/Overscan/Vertical", 8);
|
||||||
|
|
||||||
set("Video/Windowed/AspectCorrection", true);
|
set("Video/Windowed/AspectCorrection", true);
|
||||||
set("Video/Windowed/Adaptive", false);
|
set("Video/Windowed/IntegralScaling", true);
|
||||||
set("Video/Windowed/Multiplier", "Small");
|
set("Video/Windowed/AdaptiveSizing", false);
|
||||||
set("Video/Windowed/Multiplier/Small", 2);
|
set("Video/Windowed/Scale", "Small");
|
||||||
set("Video/Windowed/Multiplier/Medium", 3);
|
set("Video/Windowed/Scale/Small", "640x480");
|
||||||
set("Video/Windowed/Multiplier/Large", 4);
|
set("Video/Windowed/Scale/Medium", "960x720");
|
||||||
|
set("Video/Windowed/Scale/Large", "1280x960");
|
||||||
|
|
||||||
set("Video/Fullscreen/AspectCorrection", true);
|
set("Video/Fullscreen/AspectCorrection", true);
|
||||||
set("Video/Fullscreen/Adaptive", false);
|
set("Video/Fullscreen/IntegralScaling", true);
|
||||||
|
|
||||||
set("Audio/Driver", ruby::Audio::optimalDriver());
|
set("Audio/Driver", ruby::Audio::optimalDriver());
|
||||||
set("Audio/Device", "");
|
set("Audio/Device", "");
|
||||||
|
|
|
@ -37,7 +37,7 @@ auto InputManager::appendHotkeys() -> void {
|
||||||
hotkey->name = "Decrement Quick State";
|
hotkey->name = "Decrement Quick State";
|
||||||
hotkey->press = [&] {
|
hotkey->press = [&] {
|
||||||
if(--quickStateSlot < 1) quickStateSlot = 5;
|
if(--quickStateSlot < 1) quickStateSlot = 5;
|
||||||
program->showMessage({"Selected quick slot ", quickStateSlot});
|
program->showMessage({"Selected quick state slot ", quickStateSlot});
|
||||||
};
|
};
|
||||||
hotkeys.append(hotkey);
|
hotkeys.append(hotkey);
|
||||||
}
|
}
|
||||||
|
@ -46,7 +46,7 @@ auto InputManager::appendHotkeys() -> void {
|
||||||
hotkey->name = "Increment Quick State";
|
hotkey->name = "Increment Quick State";
|
||||||
hotkey->press = [&] {
|
hotkey->press = [&] {
|
||||||
if(++quickStateSlot > 5) quickStateSlot = 1;
|
if(++quickStateSlot > 5) quickStateSlot = 1;
|
||||||
program->showMessage({"Selected quick slot ", quickStateSlot});
|
program->showMessage({"Selected quick state slot ", quickStateSlot});
|
||||||
};
|
};
|
||||||
hotkeys.append(hotkey);
|
hotkeys.append(hotkey);
|
||||||
}
|
}
|
||||||
|
|
|
@ -47,19 +47,16 @@ Presentation::Presentation() {
|
||||||
|
|
||||||
settingsMenu.setText("Settings");
|
settingsMenu.setText("Settings");
|
||||||
videoScaleMenu.setText("Video Scale");
|
videoScaleMenu.setText("Video Scale");
|
||||||
if(settings["Video/Windowed/Multiplier"].text() == "Small") videoScaleSmall.setChecked();
|
|
||||||
if(settings["Video/Windowed/Multiplier"].text() == "Medium") videoScaleMedium.setChecked();
|
|
||||||
if(settings["Video/Windowed/Multiplier"].text() == "Large") videoScaleLarge.setChecked();
|
|
||||||
videoScaleSmall.setText("Small").onActivate([&] {
|
videoScaleSmall.setText("Small").onActivate([&] {
|
||||||
settings["Video/Windowed/Multiplier"].setValue("Small");
|
settings["Video/Windowed/Scale"].setValue("Small");
|
||||||
resizeViewport();
|
resizeViewport();
|
||||||
});
|
});
|
||||||
videoScaleMedium.setText("Medium").onActivate([&] {
|
videoScaleMedium.setText("Medium").onActivate([&] {
|
||||||
settings["Video/Windowed/Multiplier"].setValue("Medium");
|
settings["Video/Windowed/Scale"].setValue("Medium");
|
||||||
resizeViewport();
|
resizeViewport();
|
||||||
});
|
});
|
||||||
videoScaleLarge.setText("Large").onActivate([&] {
|
videoScaleLarge.setText("Large").onActivate([&] {
|
||||||
settings["Video/Windowed/Multiplier"].setValue("Large");
|
settings["Video/Windowed/Scale"].setValue("Large");
|
||||||
resizeViewport();
|
resizeViewport();
|
||||||
});
|
});
|
||||||
videoEmulationMenu.setText("Video Emulation");
|
videoEmulationMenu.setText("Video Emulation");
|
||||||
|
@ -122,13 +119,13 @@ Presentation::Presentation() {
|
||||||
});
|
});
|
||||||
|
|
||||||
toolsMenu.setText("Tools").setVisible(false);
|
toolsMenu.setText("Tools").setVisible(false);
|
||||||
saveStateMenu.setText("Save Quickstate");
|
saveQuickStateMenu.setText("Save Quick State");
|
||||||
saveSlot1.setText("Slot 1").onActivate([&] { program->saveState(1); });
|
saveSlot1.setText("Slot 1").onActivate([&] { program->saveState(1); });
|
||||||
saveSlot2.setText("Slot 2").onActivate([&] { program->saveState(2); });
|
saveSlot2.setText("Slot 2").onActivate([&] { program->saveState(2); });
|
||||||
saveSlot3.setText("Slot 3").onActivate([&] { program->saveState(3); });
|
saveSlot3.setText("Slot 3").onActivate([&] { program->saveState(3); });
|
||||||
saveSlot4.setText("Slot 4").onActivate([&] { program->saveState(4); });
|
saveSlot4.setText("Slot 4").onActivate([&] { program->saveState(4); });
|
||||||
saveSlot5.setText("Slot 5").onActivate([&] { program->saveState(5); });
|
saveSlot5.setText("Slot 5").onActivate([&] { program->saveState(5); });
|
||||||
loadStateMenu.setText("Load Quickstate");
|
loadQuickStateMenu.setText("Load Quick State");
|
||||||
loadSlot1.setText("Slot 1").onActivate([&] { program->loadState(1); });
|
loadSlot1.setText("Slot 1").onActivate([&] { program->loadState(1); });
|
||||||
loadSlot2.setText("Slot 2").onActivate([&] { program->loadState(2); });
|
loadSlot2.setText("Slot 2").onActivate([&] { program->loadState(2); });
|
||||||
loadSlot3.setText("Slot 3").onActivate([&] { program->loadState(3); });
|
loadSlot3.setText("Slot 3").onActivate([&] { program->loadState(3); });
|
||||||
|
@ -155,10 +152,15 @@ Presentation::Presentation() {
|
||||||
program->loadMedium();
|
program->loadMedium();
|
||||||
});
|
});
|
||||||
|
|
||||||
onClose([&] { program->quit(); });
|
onSize([&] {
|
||||||
|
resizeViewport(true);
|
||||||
|
});
|
||||||
|
|
||||||
|
onClose([&] {
|
||||||
|
program->quit();
|
||||||
|
});
|
||||||
|
|
||||||
setTitle({"higan v", Emulator::Version});
|
setTitle({"higan v", Emulator::Version});
|
||||||
setResizable(false);
|
|
||||||
setBackgroundColor({0, 0, 0});
|
setBackgroundColor({0, 0, 0});
|
||||||
resizeViewport();
|
resizeViewport();
|
||||||
setCentered();
|
setCentered();
|
||||||
|
@ -235,10 +237,16 @@ auto Presentation::clearViewport() -> void {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
auto Presentation::resizeViewport() -> void {
|
//onSize is true only for events generated from window resizing
|
||||||
|
//it will suppress automatic viewport scaling, and disable adaptive scaling
|
||||||
|
//it does this so that the main window can always be resizable
|
||||||
|
auto Presentation::resizeViewport(bool onSize) -> void {
|
||||||
//clear video area before resizing to avoid seeing distorted video momentarily
|
//clear video area before resizing to avoid seeing distorted video momentarily
|
||||||
clearViewport();
|
clearViewport();
|
||||||
|
|
||||||
|
uint viewportWidth = geometry().width();
|
||||||
|
uint viewportHeight = geometry().height();
|
||||||
|
|
||||||
double emulatorWidth = 320;
|
double emulatorWidth = 320;
|
||||||
double emulatorHeight = 240;
|
double emulatorHeight = 240;
|
||||||
double aspectCorrection = 1.0;
|
double aspectCorrection = 1.0;
|
||||||
|
@ -257,30 +265,37 @@ auto Presentation::resizeViewport() -> void {
|
||||||
|
|
||||||
if(!fullScreen()) {
|
if(!fullScreen()) {
|
||||||
if(settings["Video/Windowed/AspectCorrection"].boolean()) emulatorWidth *= aspectCorrection;
|
if(settings["Video/Windowed/AspectCorrection"].boolean()) emulatorWidth *= aspectCorrection;
|
||||||
uint viewportMultiplier = 2;
|
|
||||||
if(settings["Video/Windowed/Multiplier"].text() == "Small") viewportMultiplier = settings["Video/Windowed/Multiplier/Small"].natural();
|
if(!onSize) {
|
||||||
if(settings["Video/Windowed/Multiplier"].text() == "Medium") viewportMultiplier = settings["Video/Windowed/Multiplier/Medium"].natural();
|
string viewportScale = "640x480";
|
||||||
if(settings["Video/Windowed/Multiplier"].text() == "Large") viewportMultiplier = settings["Video/Windowed/Multiplier/Large"].natural();
|
if(settings["Video/Windowed/Scale"].text() == "Small") viewportScale = settings["Video/Windowed/Scale/Small"].text();
|
||||||
uint viewportWidth = 320 * viewportMultiplier;
|
if(settings["Video/Windowed/Scale"].text() == "Medium") viewportScale = settings["Video/Windowed/Scale/Medium"].text();
|
||||||
uint viewportHeight = 240 * viewportMultiplier;
|
if(settings["Video/Windowed/Scale"].text() == "Large") viewportScale = settings["Video/Windowed/Scale/Large"].text();
|
||||||
uint multiplier = min(viewportWidth / emulatorWidth, viewportHeight / emulatorHeight);
|
auto resolution = viewportScale.isplit("x", 1L);
|
||||||
if(!settings["Video/Windowed/Adaptive"].boolean()) {
|
viewportWidth = resolution(0).natural();
|
||||||
|
viewportHeight = resolution(1).natural();
|
||||||
|
}
|
||||||
|
|
||||||
|
if(settings["Video/Windowed/AdaptiveSizing"].boolean() && !onSize) {
|
||||||
|
uint multiplier = min(viewportWidth / emulatorWidth, viewportHeight / emulatorHeight);
|
||||||
emulatorWidth *= multiplier;
|
emulatorWidth *= multiplier;
|
||||||
emulatorHeight *= multiplier;
|
emulatorHeight *= multiplier;
|
||||||
setSize({viewportWidth, viewportHeight});
|
setSize({viewportWidth = emulatorWidth, viewportHeight = emulatorHeight});
|
||||||
viewport.setGeometry({
|
} else if(settings["Video/Windowed/IntegralScaling"].boolean()) {
|
||||||
(viewportWidth - emulatorWidth) / 2, (viewportHeight - emulatorHeight) / 2,
|
uint multiplier = min(viewportWidth / emulatorWidth, viewportHeight / emulatorHeight);
|
||||||
emulatorWidth, emulatorHeight
|
emulatorWidth *= multiplier;
|
||||||
});
|
emulatorHeight *= multiplier;
|
||||||
|
if(!onSize) setSize({viewportWidth, viewportHeight});
|
||||||
} else {
|
} else {
|
||||||
setSize({emulatorWidth * multiplier, emulatorHeight * multiplier});
|
double multiplier = min(viewportWidth / emulatorWidth, viewportHeight / emulatorHeight);
|
||||||
viewport.setGeometry({0, 0, emulatorWidth * multiplier, emulatorHeight * multiplier});
|
emulatorWidth *= multiplier;
|
||||||
|
emulatorHeight *= multiplier;
|
||||||
|
if(!onSize) setSize({viewportWidth, viewportHeight});
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if(settings["Video/Fullscreen/AspectCorrection"].boolean()) emulatorWidth *= aspectCorrection;
|
if(settings["Video/Fullscreen/AspectCorrection"].boolean()) emulatorWidth *= aspectCorrection;
|
||||||
uint viewportWidth = geometry().width();
|
|
||||||
uint viewportHeight = geometry().height();
|
if(settings["Video/Fullscreen/IntegralScaling"].boolean()) {
|
||||||
if(!settings["Video/Fullscreen/Adaptive"].boolean()) {
|
|
||||||
uint multiplier = min(viewportWidth / emulatorWidth, viewportHeight / emulatorHeight);
|
uint multiplier = min(viewportWidth / emulatorWidth, viewportHeight / emulatorHeight);
|
||||||
emulatorWidth *= multiplier;
|
emulatorWidth *= multiplier;
|
||||||
emulatorHeight *= multiplier;
|
emulatorHeight *= multiplier;
|
||||||
|
@ -289,12 +304,13 @@ auto Presentation::resizeViewport() -> void {
|
||||||
emulatorWidth *= multiplier;
|
emulatorWidth *= multiplier;
|
||||||
emulatorHeight *= multiplier;
|
emulatorHeight *= multiplier;
|
||||||
}
|
}
|
||||||
viewport.setGeometry({
|
|
||||||
(viewportWidth - emulatorWidth) / 2, (viewportHeight - emulatorHeight) / 2,
|
|
||||||
emulatorWidth, emulatorHeight
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
viewport.setGeometry({
|
||||||
|
(viewportWidth - emulatorWidth) / 2, (viewportHeight - emulatorHeight) / 2,
|
||||||
|
emulatorWidth, emulatorHeight
|
||||||
|
});
|
||||||
|
|
||||||
//clear video area again to ensure entire viewport area has been painted in
|
//clear video area again to ensure entire viewport area has been painted in
|
||||||
clearViewport();
|
clearViewport();
|
||||||
}
|
}
|
||||||
|
|
|
@ -12,7 +12,7 @@ struct Presentation : Window {
|
||||||
Presentation();
|
Presentation();
|
||||||
auto updateEmulator() -> void;
|
auto updateEmulator() -> void;
|
||||||
auto clearViewport() -> void;
|
auto clearViewport() -> void;
|
||||||
auto resizeViewport() -> void;
|
auto resizeViewport(bool onSize = false) -> void;
|
||||||
auto toggleFullScreen() -> void;
|
auto toggleFullScreen() -> void;
|
||||||
auto loadShaders() -> void;
|
auto loadShaders() -> void;
|
||||||
|
|
||||||
|
@ -27,10 +27,10 @@ struct Presentation : Window {
|
||||||
MenuItem unloadSystem{&systemMenu};
|
MenuItem unloadSystem{&systemMenu};
|
||||||
Menu settingsMenu{&menuBar};
|
Menu settingsMenu{&menuBar};
|
||||||
Menu videoScaleMenu{&settingsMenu};
|
Menu videoScaleMenu{&settingsMenu};
|
||||||
MenuRadioItem videoScaleSmall{&videoScaleMenu};
|
MenuItem videoScaleSmall{&videoScaleMenu};
|
||||||
MenuRadioItem videoScaleMedium{&videoScaleMenu};
|
MenuItem videoScaleMedium{&videoScaleMenu};
|
||||||
MenuRadioItem videoScaleLarge{&videoScaleMenu};
|
MenuItem videoScaleLarge{&videoScaleMenu};
|
||||||
Group videoScales{&videoScaleSmall, &videoScaleMedium, &videoScaleLarge};
|
//Group videoScales{&videoScaleSmall, &videoScaleMedium, &videoScaleLarge};
|
||||||
Menu videoEmulationMenu{&settingsMenu};
|
Menu videoEmulationMenu{&settingsMenu};
|
||||||
MenuCheckItem blurEmulation{&videoEmulationMenu};
|
MenuCheckItem blurEmulation{&videoEmulationMenu};
|
||||||
MenuCheckItem colorEmulation{&videoEmulationMenu};
|
MenuCheckItem colorEmulation{&videoEmulationMenu};
|
||||||
|
@ -48,18 +48,18 @@ struct Presentation : Window {
|
||||||
MenuSeparator showConfigurationSeparator{&settingsMenu};
|
MenuSeparator showConfigurationSeparator{&settingsMenu};
|
||||||
MenuItem showConfiguration{&settingsMenu};
|
MenuItem showConfiguration{&settingsMenu};
|
||||||
Menu toolsMenu{&menuBar};
|
Menu toolsMenu{&menuBar};
|
||||||
Menu saveStateMenu{&toolsMenu};
|
Menu saveQuickStateMenu{&toolsMenu};
|
||||||
MenuItem saveSlot1{&saveStateMenu};
|
MenuItem saveSlot1{&saveQuickStateMenu};
|
||||||
MenuItem saveSlot2{&saveStateMenu};
|
MenuItem saveSlot2{&saveQuickStateMenu};
|
||||||
MenuItem saveSlot3{&saveStateMenu};
|
MenuItem saveSlot3{&saveQuickStateMenu};
|
||||||
MenuItem saveSlot4{&saveStateMenu};
|
MenuItem saveSlot4{&saveQuickStateMenu};
|
||||||
MenuItem saveSlot5{&saveStateMenu};
|
MenuItem saveSlot5{&saveQuickStateMenu};
|
||||||
Menu loadStateMenu{&toolsMenu};
|
Menu loadQuickStateMenu{&toolsMenu};
|
||||||
MenuItem loadSlot1{&loadStateMenu};
|
MenuItem loadSlot1{&loadQuickStateMenu};
|
||||||
MenuItem loadSlot2{&loadStateMenu};
|
MenuItem loadSlot2{&loadQuickStateMenu};
|
||||||
MenuItem loadSlot3{&loadStateMenu};
|
MenuItem loadSlot3{&loadQuickStateMenu};
|
||||||
MenuItem loadSlot4{&loadStateMenu};
|
MenuItem loadSlot4{&loadQuickStateMenu};
|
||||||
MenuItem loadSlot5{&loadStateMenu};
|
MenuItem loadSlot5{&loadQuickStateMenu};
|
||||||
MenuSeparator toolsMenuSeparator{&toolsMenu};
|
MenuSeparator toolsMenuSeparator{&toolsMenu};
|
||||||
MenuItem cheatEditor{&toolsMenu};
|
MenuItem cheatEditor{&toolsMenu};
|
||||||
MenuItem stateManager{&toolsMenu};
|
MenuItem stateManager{&toolsMenu};
|
||||||
|
|
|
@ -14,7 +14,7 @@ auto Program::loadState(uint slot, bool managed) -> bool {
|
||||||
if(memory.size() == 0) return showMessage({"Slot ", slot, " ", type, " state does not exist"}), false;
|
if(memory.size() == 0) return showMessage({"Slot ", slot, " ", type, " state does not exist"}), false;
|
||||||
serializer s(memory.data(), memory.size());
|
serializer s(memory.data(), memory.size());
|
||||||
if(emulator->unserialize(s) == false) return showMessage({"Slot ", slot, " ", type, " state incompatible"}), false;
|
if(emulator->unserialize(s) == false) return showMessage({"Slot ", slot, " ", type, " state incompatible"}), false;
|
||||||
return showMessage({"Loaded from ", type, " slot ", slot}), true;
|
return showMessage({"Loaded ", type, " state from slot ", slot}), true;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto Program::saveState(uint slot, bool managed) -> bool {
|
auto Program::saveState(uint slot, bool managed) -> bool {
|
||||||
|
@ -22,10 +22,10 @@ auto Program::saveState(uint slot, bool managed) -> bool {
|
||||||
string type = managed ? "managed" : "quick";
|
string type = managed ? "managed" : "quick";
|
||||||
auto location = stateName(slot, managed);
|
auto location = stateName(slot, managed);
|
||||||
serializer s = emulator->serialize();
|
serializer s = emulator->serialize();
|
||||||
if(s.size() == 0) return showMessage({"Failed to save state to slot ", slot}), false;
|
if(s.size() == 0) return showMessage({"Failed to save ", type, " state to slot ", slot}), false;
|
||||||
directory::create(Location::path(location));
|
directory::create(Location::path(location));
|
||||||
if(file::write(location, s.data(), s.size()) == false) {
|
if(file::write(location, s.data(), s.size()) == false) {
|
||||||
return showMessage({"Unable to write to ", type, " slot ", slot}), false;
|
return showMessage({"Unable to write ", type, " state to slot ", slot}), false;
|
||||||
}
|
}
|
||||||
return showMessage({"Saved to ", type, " slot ", slot}), true;
|
return showMessage({"Saved ", type, " state to slot ", slot}), true;
|
||||||
}
|
}
|
||||||
|
|
|
@ -27,11 +27,12 @@ struct VideoSettings : TabFrameItem {
|
||||||
Label windowedModeLabel{&layout, Size{~0, 0}, 2};
|
Label windowedModeLabel{&layout, Size{~0, 0}, 2};
|
||||||
HorizontalLayout windowedModeLayout{&layout, Size{~0, 0}};
|
HorizontalLayout windowedModeLayout{&layout, Size{~0, 0}};
|
||||||
CheckLabel windowedModeAspectCorrection{&windowedModeLayout, Size{0, 0}};
|
CheckLabel windowedModeAspectCorrection{&windowedModeLayout, Size{0, 0}};
|
||||||
CheckLabel windowedModeAdaptive{&windowedModeLayout, Size{0, 0}};
|
CheckLabel windowedModeIntegralScaling{&windowedModeLayout, Size{0, 0}};
|
||||||
|
CheckLabel windowedModeAdaptiveSizing{&windowedModeLayout, Size{0, 0}};
|
||||||
Label fullscreenModeLabel{&layout, Size{~0, 0}, 2};
|
Label fullscreenModeLabel{&layout, Size{~0, 0}, 2};
|
||||||
HorizontalLayout fullscreenModeLayout{&layout, Size{~0, 0}};
|
HorizontalLayout fullscreenModeLayout{&layout, Size{~0, 0}};
|
||||||
CheckLabel fullscreenModeAspectCorrection{&fullscreenModeLayout, Size{0, 0}};
|
CheckLabel fullscreenModeAspectCorrection{&fullscreenModeLayout, Size{0, 0}};
|
||||||
CheckLabel fullscreenModeAdaptive{&fullscreenModeLayout, Size{0, 0}};
|
CheckLabel fullscreenModeIntegralScaling{&fullscreenModeLayout, Size{0, 0}};
|
||||||
|
|
||||||
auto updateColor() -> void;
|
auto updateColor() -> void;
|
||||||
auto updateOverscan() -> void;
|
auto updateOverscan() -> void;
|
||||||
|
|
|
@ -24,12 +24,13 @@ VideoSettings::VideoSettings(TabFrame* parent) : TabFrameItem(parent) {
|
||||||
verticalMaskSlider.setLength(25).setPosition(settings["Video/Overscan/Vertical"].natural()).onChange([&] { updateOverscan(); });
|
verticalMaskSlider.setLength(25).setPosition(settings["Video/Overscan/Vertical"].natural()).onChange([&] { updateOverscan(); });
|
||||||
|
|
||||||
windowedModeLabel.setFont(Font().setBold()).setText("Windowed Mode");
|
windowedModeLabel.setFont(Font().setBold()).setText("Windowed Mode");
|
||||||
windowedModeAspectCorrection.setText("Correct aspect ratio").setChecked(settings["Video/Windowed/AspectCorrection"].boolean()).onToggle([&] { updateViewport(); });
|
windowedModeAspectCorrection.setText("Aspect correction").setChecked(settings["Video/Windowed/AspectCorrection"].boolean()).onToggle([&] { updateViewport(); });
|
||||||
windowedModeAdaptive.setText("Resize window to viewport").setChecked(settings["Video/Windowed/Adaptive"].boolean()).onToggle([&] { updateViewport(); });
|
windowedModeIntegralScaling.setText("Integral scaling").setChecked(settings["Video/Windowed/IntegralScaling"].boolean()).onToggle([&] { updateViewport(); });
|
||||||
|
windowedModeAdaptiveSizing.setText("Adaptive sizing").setChecked(settings["Video/Windowed/AdaptiveSizing"].boolean()).onToggle([&] { updateViewport(); });
|
||||||
|
|
||||||
fullscreenModeLabel.setFont(Font().setBold()).setText("Fullscreen Mode");
|
fullscreenModeLabel.setFont(Font().setBold()).setText("Fullscreen Mode");
|
||||||
fullscreenModeAspectCorrection.setText("Correct aspect ratio").setChecked(settings["Video/Fullscreen/AspectCorrection"].boolean()).onToggle([&] { updateViewport(); });
|
fullscreenModeAspectCorrection.setText("Aspect correction").setChecked(settings["Video/Fullscreen/AspectCorrection"].boolean()).onToggle([&] { updateViewport(); });
|
||||||
fullscreenModeAdaptive.setText("Resize viewport to window").setChecked(settings["Video/Fullscreen/Adaptive"].boolean()).onToggle([&] { updateViewport(); });
|
fullscreenModeIntegralScaling.setText("Integral scaling").setChecked(settings["Video/Fullscreen/IntegralScaling"].boolean()).onToggle([&] { updateViewport(); });
|
||||||
|
|
||||||
updateColor();
|
updateColor();
|
||||||
updateOverscan();
|
updateOverscan();
|
||||||
|
@ -56,8 +57,9 @@ auto VideoSettings::updateOverscan() -> void {
|
||||||
|
|
||||||
auto VideoSettings::updateViewport() -> void {
|
auto VideoSettings::updateViewport() -> void {
|
||||||
settings["Video/Windowed/AspectCorrection"].setValue(windowedModeAspectCorrection.checked());
|
settings["Video/Windowed/AspectCorrection"].setValue(windowedModeAspectCorrection.checked());
|
||||||
settings["Video/Windowed/Adaptive"].setValue(windowedModeAdaptive.checked());
|
settings["Video/Windowed/IntegralScaling"].setValue(windowedModeIntegralScaling.checked());
|
||||||
|
settings["Video/Windowed/AdaptiveSizing"].setValue(windowedModeAdaptiveSizing.checked());
|
||||||
settings["Video/Fullscreen/AspectCorrection"].setValue(fullscreenModeAspectCorrection.checked());
|
settings["Video/Fullscreen/AspectCorrection"].setValue(fullscreenModeAspectCorrection.checked());
|
||||||
settings["Video/Fullscreen/Adaptive"].setValue(fullscreenModeAdaptive.checked());
|
settings["Video/Fullscreen/IntegralScaling"].setValue(fullscreenModeIntegralScaling.checked());
|
||||||
presentation->resizeViewport();
|
presentation->resizeViewport();
|
||||||
}
|
}
|
||||||
|
|
|
@ -27,6 +27,9 @@ CheatEditor::CheatEditor(TabFrame* parent) : TabFrameItem(parent) {
|
||||||
findCodesButton.setText("Find Codes ...").onActivate([&] { cheatDatabase->findCodes(); });
|
findCodesButton.setText("Find Codes ...").onActivate([&] { cheatDatabase->findCodes(); });
|
||||||
resetButton.setText("Reset").onActivate([&] { doReset(); });
|
resetButton.setText("Reset").onActivate([&] { doReset(); });
|
||||||
eraseButton.setText("Erase").onActivate([&] { doErase(); });
|
eraseButton.setText("Erase").onActivate([&] { doErase(); });
|
||||||
|
|
||||||
|
//do not display "Find Codes" button if there is no cheat database to look up codes in
|
||||||
|
if(!file::exists(locate("cheats.bml"))) findCodesButton.setVisible(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
auto CheatEditor::doChangeSelected() -> void {
|
auto CheatEditor::doChangeSelected() -> void {
|
||||||
|
@ -128,7 +131,7 @@ auto CheatEditor::addCode(const string& code, const string& description, bool en
|
||||||
|
|
||||||
auto CheatEditor::loadCheats() -> void {
|
auto CheatEditor::loadCheats() -> void {
|
||||||
doReset(true);
|
doReset(true);
|
||||||
auto contents = string::read({program->mediumPaths(1), "cheats.bml"});
|
auto contents = string::read({program->mediumPaths(1), "higan/cheats.bml"});
|
||||||
auto document = BML::unserialize(contents);
|
auto document = BML::unserialize(contents);
|
||||||
for(auto cheat : document["cartridge"].find("cheat")) {
|
for(auto cheat : document["cartridge"].find("cheat")) {
|
||||||
if(!addCode(cheat["code"].text(), cheat["description"].text(), (bool)cheat["enabled"])) break;
|
if(!addCode(cheat["code"].text(), cheat["description"].text(), (bool)cheat["enabled"])) break;
|
||||||
|
@ -149,9 +152,10 @@ auto CheatEditor::saveCheats() -> void {
|
||||||
count++;
|
count++;
|
||||||
}
|
}
|
||||||
if(count) {
|
if(count) {
|
||||||
file::write({program->mediumPaths(1), "cheats.bml"}, document);
|
directory::create({program->mediumPaths(1), "higan/"});
|
||||||
|
file::write({program->mediumPaths(1), "higan/cheats.bml"}, document);
|
||||||
} else {
|
} else {
|
||||||
file::remove({program->mediumPaths(1), "cheats.bml"});
|
file::remove({program->mediumPaths(1), "higan/cheats.bml"});
|
||||||
}
|
}
|
||||||
doReset(true);
|
doReset(true);
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue