lsnes/gambatte_qt/src/gambattemenuhandler.cpp
2013-08-09 20:11:29 +03:00

896 lines
28 KiB
C++

/***************************************************************************
* Copyright (C) 2007 by Sindre Aamås *
* sinamas@users.sourceforge.net *
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License version 2 as *
* published by the Free Software Foundation. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License version 2 for more details. *
* *
* You should have received a copy of the GNU General Public License *
* version 2 along with this program; if not, write to the *
* Free Software Foundation, Inc., *
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
***************************************************************************/
#include "gambattemenuhandler.h"
#include "blitterconf.h"
#include "cheatdialog.h"
#include "gambattesource.h"
#include "mainwindow.h"
#include "miscdialog.h"
#include "palettedialog.h"
#include "sounddialog.h"
#include "videodialog.h"
#include <QActionGroup>
#include <QFileInfo>
#include <QSettings>
#include <QtGui>
#include <iostream>
namespace {
static QString const strippedName(QString const &fullFileName) {
return QFileInfo(fullFileName).fileName();
}
struct TmpPauser : private Uncopyable {
MainWindow &mw;
int const inc;
explicit TmpPauser(MainWindow &mw, int inc = 4)
: mw(mw), inc(inc)
{
mw.incPause(inc);
}
~TmpPauser() {
mw.decPause(inc);
}
};
}
FrameRateAdjuster::FrameTime::FrameTime(unsigned baseNum, unsigned baseDenom)
: index_(num_steps)
{
setBaseFrameTime(baseNum, baseDenom);
}
void FrameRateAdjuster::FrameTime::setBaseFrameTime(unsigned const baseNum, unsigned const baseDenom) {
frameTimes_[num_steps] = Rational(baseNum, baseDenom);
unsigned const bnum = baseNum * 0x10000ul / baseDenom;
for (std::size_t i = num_steps, num = bnum; i < num_steps * 2; ++i)
frameTimes_[i + 1] = Rational(num = num * 11 / 10, 0x10000);
for (std::size_t i = num_steps, num = bnum; i; --i)
frameTimes_[i - 1] = Rational(num = num * 10 / 11, 0x10000);
}
FrameRateAdjuster::FrameRateAdjuster(MiscDialog const &miscDialog, MainWindow &mw, QObject *parent)
: QObject(parent)
, frameTime_(miscDialog.baseFps().height(), miscDialog.baseFps().width())
, miscDialog_(miscDialog)
, mw_(mw)
, decFrameRateAction_(new QAction(tr("&Decrease Frame Rate"), &mw))
, incFrameRateAction_(new QAction(tr("&Increase Frame Rate"), &mw))
, resetFrameRateAction_(new QAction(tr("&Reset Frame Rate"), &mw))
, enabled_(true)
{
decFrameRateAction_->setShortcut(QString("Ctrl+D"));
incFrameRateAction_->setShortcut(QString("Ctrl+I"));
resetFrameRateAction_->setShortcut(QString("Ctrl+U"));
connect(decFrameRateAction_, SIGNAL(triggered()), this, SLOT(decFrameRate()));
connect(incFrameRateAction_, SIGNAL(triggered()), this, SLOT(incFrameRate()));
connect(resetFrameRateAction_, SIGNAL(triggered()), this, SLOT(resetFrameRate()));
connect(&miscDialog, SIGNAL(accepted()), this, SLOT(miscDialogChange()));
changed();
}
QList<QAction *> const FrameRateAdjuster::actions() {
QList<QAction *> l;
l.append(decFrameRateAction_);
l.append(incFrameRateAction_);
l.append(resetFrameRateAction_);
return l;
}
void FrameRateAdjuster::miscDialogChange() {
QSize const &baseFps = miscDialog_.baseFps();
frameTime_.setBaseFrameTime(baseFps.height(), baseFps.width());
changed();
}
void FrameRateAdjuster::setDisabled(bool disabled) {
enabled_ = !disabled;
changed();
}
void FrameRateAdjuster::decFrameRate() {
if (enabled_) {
frameTime_.inc();
changed();
}
}
void FrameRateAdjuster::incFrameRate() {
if (enabled_) {
frameTime_.dec();
changed();
}
}
void FrameRateAdjuster::resetFrameRate() {
if (enabled_) {
frameTime_.reset();
changed();
}
}
void FrameRateAdjuster::changed() {
incFrameRateAction_->setEnabled(enabled_ && frameTime_.decPossible());
decFrameRateAction_->setEnabled(enabled_ && frameTime_.incPossible());
resetFrameRateAction_->setEnabled(enabled_ && frameTime_.resetPossible());
FrameTime::Rational const &ft = enabled_ ? frameTime_.get() : frameTime_.base();
mw_.setFrameTime(ft.num, ft.denom);
}
WindowSizeMenu::WindowSizeMenu(MainWindow &mw, VideoDialog const &vd)
: mw_(mw)
, menu_(new QMenu(tr("&Window Size"), &mw))
, group_(new QActionGroup(menu_))
, maxSize_(QApplication::desktop()->screen()->size())
{
fillMenu(vd.sourceSize(), vd.scalingMethod());
setCheckedSize(QSettings().value("video/windowSize", QSize()).toSize());
connect(group_, SIGNAL(triggered(QAction *)), this, SLOT(triggered()));
QSize const &size = checkedSize();
mw_.setWindowSize(size);
if (size.isEmpty())
mw_.resize(QSettings().value("mainwindow/size", QSize(160, 144)).toSize());
}
WindowSizeMenu::~WindowSizeMenu() {
QSettings settings;
settings.setValue("video/windowSize", checkedSize());
}
void WindowSizeMenu::videoDialogChange(VideoDialog const &vd) {
QSize const &oldSize = checkedSize();
disconnect(group_, SIGNAL(triggered(QAction *)), this, SLOT(triggered()));
menu_->clear();
delete group_;
group_ = new QActionGroup(menu_);
fillMenu(vd.sourceSize(), vd.scalingMethod());
setCheckedSize(oldSize);
connect(group_, SIGNAL(triggered(QAction *)), this, SLOT(triggered()));
QSize const &newSize = checkedSize();
if (newSize != oldSize)
mw_.setWindowSize(newSize);
}
void WindowSizeMenu::triggered() {
mw_.setWindowSize(checkedSize());
}
void WindowSizeMenu::fillMenu(QSize const &sourceSize, ScalingMethod const scalingMethod) {
QSize const aspectRatio(160, 144);
QSize const basesz(scalingMethod == scaling_integer ? sourceSize : aspectRatio);
QSize sz(basesz);
while (sz.width() <= maxSize_.width() && sz.height() <= maxSize_.height()) {
if (sz.width() >= sourceSize.width() && sz.height() >= sourceSize.height()) {
QAction *a = menu_->addAction(
'&' + QString::number(sz.width()) + 'x' + QString::number(sz.height()));
a->setData(sz);
a->setCheckable(true);
group_->addAction(a);
}
sz += basesz;
}
QAction *a = menu_->addAction(tr("&Variable"));
a->setData(QSize());
a->setCheckable(true);
group_->addAction(a);
}
void WindowSizeMenu::setCheckedSize(QSize const &size) {
QList<QAction *> const &actions = group_->actions();
foreach (QAction *a, actions) {
if (a->data() == size) {
a->setChecked(true);
return;
}
}
if (!group_->checkedAction())
actions.front()->setChecked(true);
}
QSize const WindowSizeMenu::checkedSize() const {
return group_->checkedAction() ? group_->checkedAction()->data().toSize() : QSize();
}
static QString const settingsPath() {
QString path = QSettings(QSettings::IniFormat, QSettings::UserScope,
QCoreApplication::organizationName(), QCoreApplication::applicationName()).fileName();
path.truncate(path.lastIndexOf('/'));
return path;
}
static QString const toCmdString(QAction const *a) {
QString text = a->text().toLower();
text.replace('&', QString());
text.replace(' ', '-');
return text;
}
static char toCmdChar(QAction const *a) {
return a->shortcut().count() == 1
? (a->shortcut()[0] - Qt::Key_A + 'a') & 0xff
: 0;
}
static QAction * findCmdStringAction(QList<QAction *> const &l, QString const &cmdstr) {
foreach (QAction *a, l) {
if (cmdstr == toCmdString(a))
return a;
}
return 0;
}
static QAction * findCmdCharAction(QList<QAction *> const &l, char const c) {
foreach (QAction *a, l) {
if (c == toCmdChar(a))
return a;
}
return 0;
}
static void printUsage(char const *const arg0, QList<QAction *> const &actions) {
std::cout << "Usage: " << arg0 << " [OPTION]... [romfile]\n";
foreach (QAction const *const a, actions) {
if (a->isCheckable() && a->isEnabled()) {
std::string const &text = toCmdString(a).toStdString();
char const c = toCmdChar(a);
std::cout << " "
<< (c ? '-' + std::string(1, c) + ", " : std::string(" "))
<< "--" << text << "[=0]\n";
}
}
}
GambatteMenuHandler::GambatteMenuHandler(MainWindow &mw,
GambatteSource &source,
int const argc,
char const *const argv[])
: mw_(mw)
, source_(source)
, soundDialog_(new SoundDialog(mw, &mw))
, videoDialog_(new VideoDialog(mw, source.generateVideoSourceInfos(),
QString("Video filter:"), &mw))
, miscDialog_(new MiscDialog(settingsPath() + "/saves", &mw))
, cheatDialog_(new CheatDialog(settingsPath() + "/cheats.ini", &mw))
, recentFileActs_()
, pauseAction_()
, syncFrameRateAction_()
, gbaCgbAction_()
, forceDmgAction_()
, fsAct_()
, recentMenu_()
, globalPaletteDialog_()
, romPaletteDialog_()
, stateSlotGroup_(new QActionGroup(&mw))
, windowSizeMenu_(mw, *videoDialog_)
, pauseInc_(4)
{
mw.setWindowTitle("Gambatte");
source.inputDialog()->setParent(&mw, source.inputDialog()->windowFlags());
{
QString const &settingspath = settingsPath();
QString const &palpath = settingspath + "/palettes";
QDir::root().mkpath(settingspath + "/saves");
QDir::root().mkpath(palpath);
globalPaletteDialog_ = new PaletteDialog(palpath, 0, &mw);
romPaletteDialog_ = new PaletteDialog(palpath, globalPaletteDialog_, &mw);
connect(globalPaletteDialog_, SIGNAL(accepted()), this, SLOT(globalPaletteChange()));
connect(romPaletteDialog_, SIGNAL(accepted()), this, SLOT(romPaletteChange()));
}
QActionGroup *const romLoadedActions = new QActionGroup(&mw);
romLoadedActions->setExclusive(false);
{
for (int i = 0; i < max_recent_files; ++i) {
recentFileActs_[i] = new QAction(&mw);
recentFileActs_[i]->setVisible(false);
connect(recentFileActs_[i], SIGNAL(triggered()), this, SLOT(openRecentFile()));
}
QMenu *fileMenu = mw.menuBar()->addMenu(tr("&File"));
fileMenu->addAction(tr("&Open..."), this, SLOT(open()), tr("Ctrl+O"));
recentMenu_ = fileMenu->addMenu(tr("Open Re&cent"));
for (int i = 0; i < max_recent_files; ++i)
recentMenu_->addAction(recentFileActs_[i]);
fileMenu->addSeparator();
romLoadedActions->addAction(fileMenu->addAction(tr("&Reset"), this, SLOT(reset()), tr("Ctrl+R")));
fileMenu->addSeparator();
romLoadedActions->addAction(fileMenu->addAction(tr("Save State &As..."), this, SLOT(saveStateAs())));
romLoadedActions->addAction(fileMenu->addAction(tr("Load State &From..."), this, SLOT(loadStateFrom())));
fileMenu->addSeparator();
romLoadedActions->addAction(fileMenu->addAction(tr("&Save State"),
this, SLOT(saveState()), QString("Ctrl+S")));
romLoadedActions->addAction(fileMenu->addAction(tr("&Load State"),
this, SLOT(loadState()), QString("Ctrl+L")));
{
QMenu *const stateSlotMenu = fileMenu->addMenu(tr("S&elect State Slot"));
stateSlotMenu->setEnabled(false);
stateSlotMenu->addAction(tr("&Previous"), this, SLOT(prevStateSlot()), QString("Ctrl+Z"));
stateSlotMenu->addAction(tr("&Next"), this, SLOT(nextStateSlot()), QString("Ctrl+X"));
stateSlotMenu->addSeparator();
for (int i = 0; i < 10; ++i) {
int const no = i == 9 ? 0 : i + 1;
QString const &strno = QString::number(no);
QAction *action = stateSlotMenu->addAction(
"Slot &" + strno, this, SLOT(selectStateSlot()), strno);
action->setCheckable(true);
action->setData(no);
stateSlotGroup_->addAction(action);
}
connect(this, SIGNAL(romLoaded(bool)), stateSlotMenu, SLOT(setEnabled(bool)));
}
fileMenu->addSeparator();
fileMenu->addAction(tr("&Quit"), qApp, SLOT(closeAllWindows()), tr("Ctrl+Q"));
updateRecentFileActions();
}
FrameRateAdjuster *const frameRateAdjuster = new FrameRateAdjuster(*miscDialog_, mw, this);
QList<QAction *> cmdactions;
{
QMenu *const playm = mw.menuBar()->addMenu(tr("&Play"));
romLoadedActions->addAction(pauseAction_ = playm->addAction(
tr("&Pause"), this, SLOT(pauseChange()), QString("Ctrl+P")));
pauseAction_->setCheckable(true);
romLoadedActions->addAction(playm->addAction(tr("Frame &Step"),
this, SLOT(frameStep()), QString("Ctrl+.")));
playm->addSeparator();
syncFrameRateAction_ = playm->addAction(tr("&Sync Frame Rate to Refresh Rate"));
syncFrameRateAction_->setCheckable(true);
connect(syncFrameRateAction_, SIGNAL(triggered(bool)),
frameRateAdjuster, SLOT(setDisabled(bool)));
connect(syncFrameRateAction_, SIGNAL(triggered(bool)),
&mw, SLOT(setSyncToRefreshRate(bool)));
foreach (QAction *action, frameRateAdjuster->actions())
playm->addAction(romLoadedActions->addAction(action));
cmdactions += playm->actions();
}
QMenu *const settingsm = mw.menuBar()->addMenu(tr("&Settings"));
settingsm->addAction(tr("&Input..."), this, SLOT(execInputDialog()));
settingsm->addAction(tr("&Miscellaneous..."), this, SLOT(execMiscDialog()));
settingsm->addAction(tr("&Sound..."), this, SLOT(execSoundDialog()));
settingsm->addAction(tr("&Video..."), this, SLOT(execVideoDialog()));
settingsm->addSeparator();
settingsm->addMenu(windowSizeMenu_.menu());
settingsm->addSeparator();
gbaCgbAction_ = settingsm->addAction(tr("GB&A CGB Mode"));
gbaCgbAction_->setCheckable(true);
gbaCgbAction_->setChecked(QSettings().value("gbacgb", false).toBool());
forceDmgAction_ = settingsm->addAction(tr("Force &DMG Mode"));
forceDmgAction_->setCheckable(true);
{
QMenu *const palm = settingsm->addMenu(tr("DMG &Palette"));
palm->addAction(tr("&Global..."), this, SLOT(execGlobalPaletteDialog()));
QAction *romPaletteAct = palm->addAction(tr("Current &ROM..."), this, SLOT(execRomPaletteDialog()));
romPaletteAct->setEnabled(false);
connect(this, SIGNAL(dmgRomLoaded(bool)), romPaletteAct, SLOT(setEnabled(bool)));
}
settingsm->addSeparator();
fsAct_ = settingsm->addAction(tr("&Full Screen"), this, SLOT(toggleFullScreen()), tr("Ctrl+F"));
fsAct_->setCheckable(true);
cmdactions += settingsm->actions();
romLoadedActions->addAction(mw.menuBar()->addMenu(tr("&Tools"))->addAction(tr("&Cheats..."),
cheatDialog_, SLOT(exec())));
romLoadedActions->setEnabled(false);
mw.menuBar()->addSeparator();
QMenu *const helpMenu = mw.menuBar()->addMenu(tr("&Help"));
helpMenu->addAction(tr("&About"), this, SLOT(about()));
mw.addActions(mw.menuBar()->actions());
{
QAction *escAct = new QAction(&mw);
escAct->setShortcut(tr("Esc"));
connect(escAct, SIGNAL(triggered()), this, SLOT(escPressed()));
mw.addAction(escAct);
}
mw.setSamplesPerFrame(35112);
connect(&source, SIGNAL(setTurbo(bool)), &mw, SLOT(setFastForward(bool)));
connect(&source, SIGNAL(togglePause()), pauseAction_, SLOT(trigger()));
connect(&source, SIGNAL(frameStep()), this, SLOT(frameStep()));
connect(&source, SIGNAL(decFrameRate()), frameRateAdjuster, SLOT(decFrameRate()));
connect(&source, SIGNAL(incFrameRate()), frameRateAdjuster, SLOT(incFrameRate()));
connect(&source, SIGNAL(resetFrameRate()), frameRateAdjuster, SLOT(resetFrameRate()));
connect(&source, SIGNAL(prevStateSlot()), this, SLOT(prevStateSlot()));
connect(&source, SIGNAL(nextStateSlot()), this, SLOT(nextStateSlot()));
connect(&source, SIGNAL(saveStateSignal()), this, SLOT(saveState()));
connect(&source, SIGNAL(loadStateSignal()), this, SLOT(loadState()));
connect(&source, SIGNAL(quit()), qApp, SLOT(closeAllWindows()));
connect(videoDialog_, SIGNAL(accepted()), this, SLOT(videoDialogChange()));
connect(soundDialog_, SIGNAL(accepted()), this, SLOT(soundDialogChange()));
connect(miscDialog_, SIGNAL(accepted()), this, SLOT(miscDialogChange()));
connect(cheatDialog_, SIGNAL(accepted()), this, SLOT(cheatDialogChange()));
connect(&mw, SIGNAL(videoBlitterFailure()), this, SLOT(videoBlitterFailure()));
connect(&mw, SIGNAL(audioEngineFailure()), this, SLOT(audioEngineFailure()));
connect(&mw, SIGNAL(closing()), this, SLOT(saveWindowSizeIfNotFullScreen()));
connect(&mw, SIGNAL(dwmCompositionChange()), this, SLOT(reconsiderSyncFrameRateActionEnable()));
connect(this, SIGNAL(romLoaded(bool)), romLoadedActions, SLOT(setEnabled(bool)));
connect(this, SIGNAL(romLoaded(bool)), stateSlotGroup_->actions().at(0), SLOT(setChecked(bool)));
mw.setAspectRatio(QSize(160, 144));
videoDialogChange();
soundDialogChange();
miscDialogChange();
bool unknownCmd = false;
for (int i = 1; i < argc; ++i) {
if (argv[i][0] == '-' && argv[i][1]) {
QString const argstr(argv[i] + 2);
if (QAction *a = argv[i][1] == '-'
? findCmdStringAction(cmdactions, argstr.left(argstr.lastIndexOf('=')))
: findCmdCharAction(cmdactions, argv[i][1])) {
if (argstr.endsWith("=0") == a->isChecked() && a->isEnabled())
a->trigger();
} else
unknownCmd = true;
}
}
if (unknownCmd)
printUsage(argv[0], cmdactions);
for (int i = 1; i < argc; ++i) {
if (argv[i][0] != '-') {
if (fsAct_->isChecked())
mw.menuBar()->hide();
loadFile(QFileInfo(QString(argv[i])).absoluteFilePath());
break;
}
}
}
GambatteMenuHandler::~GambatteMenuHandler() {
QSettings settings;
settings.setValue("gbacgb", gbaCgbAction_->isChecked());
}
void GambatteMenuHandler::updateRecentFileActions() {
QSettings settings;
QStringList files = settings.value("recentFileList").toStringList();
int const numRecentFiles = qMin(files.size(), static_cast<int>(max_recent_files));
for (int i = 0; i < numRecentFiles; ++i) {
QString const &text = tr("&%1 %2").arg(i + 1).arg(strippedName(files[i]));
recentFileActs_[i]->setText(text);
recentFileActs_[i]->setData(files[i]);
recentFileActs_[i]->setVisible(true);
}
for (int j = numRecentFiles; j < max_recent_files; ++j)
recentFileActs_[j]->setVisible(false);
recentMenu_->setEnabled(numRecentFiles > 0);
}
void GambatteMenuHandler::setCurrentFile(QString const &fileName) {
QSettings settings;
QStringList files = settings.value("recentFileList").toStringList();
files.removeAll(fileName);
files.prepend(fileName);
while (files.size() > max_recent_files)
files.removeLast();
settings.setValue("recentFileList", files);
updateRecentFileActions();
}
void GambatteMenuHandler::loadFile(QString const &fileName) {
TmpPauser tmpPauser(mw_, 4);
pauseAction_->setChecked(false);
pauseChange();
mw_.waitUntilPaused();
if (gambatte::LoadRes const error =
source_.load(fileName.toLocal8Bit().constData(),
gbaCgbAction_->isChecked() * gambatte::GB::GBA_CGB
+ forceDmgAction_->isChecked() * gambatte::GB::FORCE_DMG
+ miscDialog_->multicartCompat() * gambatte::GB::MULTICART_COMPAT)) {
mw_.stop();
emit dmgRomLoaded(false);
emit romLoaded(false);
QMessageBox::critical(
&mw_,
tr("File Load Error"),
(tr("Failed to load file\n")
+ fileName + ".\n\n"
+ gambatte::to_string(error).c_str() + '.'));
return;
}
QString const &romTitle = QString::fromStdString(source_.romTitle()).trimmed();
cheatDialog_->setGameName(romTitle.isEmpty() ? QFileInfo(fileName).completeBaseName() : romTitle);
cheatDialogChange();
if (!source_.isCgb()) {
romPaletteDialog_->setSettingsFile(
QFileInfo(fileName).completeBaseName() + ".pal",
romTitle);
setDmgPaletteColors();
}
gambatte::PakInfo const &pak = source_.pakInfo();
std::cout << romTitle.toStdString() << '\n'
<< "GamePak type: " << pak.mbc()
<< " rambanks: " << pak.rambanks()
<< " rombanks: " << pak.rombanks() << '\n'
<< "header checksum: " << (pak.headerChecksumOk() ? "ok" : "bad") << '\n'
<< "cgb: " << source_.isCgb() << std::endl;
mw_.setWindowTitle(strippedName(fileName) + (pak.headerChecksumOk() ? "" : " [bad]") + " - Gambatte");
setCurrentFile(fileName);
emit romLoaded(true);
emit dmgRomLoaded(!source_.isCgb());
mw_.resetAudio();
mw_.run();
}
void GambatteMenuHandler::open() {
TmpPauser tmpPauser(mw_, 4);
mw_.waitUntilPaused();
QString const &fileName = QFileDialog::getOpenFileName(
&mw_, tr("Open"), recentFileActs_[0]->data().toString(),
tr("Game Boy ROM Images (*.dmg *.gb *.gbc *.sgb *.zip *.gz);;All Files (*)"));
if (!fileName.isEmpty())
loadFile(fileName);
// giving back focus after getOpenFileName seems to fail at times, which
// can be problematic with current exclusive mode handling.
mw_.setFocus();
}
void GambatteMenuHandler::openRecentFile() {
if (QAction const *action = qobject_cast<QAction *>(sender()))
loadFile(action->data().toString());
}
void GambatteMenuHandler::about() {
TmpPauser tmpPauser(mw_, pauseInc_);
QMessageBox::about(
&mw_,
"About Gambatte",
"<h3>Gambatte Qt"
#ifdef GAMBATTE_QT_VERSION_STR
" (" GAMBATTE_QT_VERSION_STR ")"
#endif
"</h3>"
"<p>"
"<b>Homepage:</b> "
"<a href=\"https://github.com/sinamas/gambatte\">"
"https://github.com/sinamas/gambatte"
"</a>"
"</p>"
"<p>"
"Gambatte is an open-source Game Boy Color emulator written for fun "
"and made available in the hope that it will be useful. It is based "
"on some stupid amount of hardware accuracy tests."
"</p>"
);
}
void GambatteMenuHandler::globalPaletteChange() {
romPaletteDialog_->externalChange();
setDmgPaletteColors();
}
void GambatteMenuHandler::romPaletteChange() {
globalPaletteDialog_->externalChange();
setDmgPaletteColors();
}
namespace {
struct SetDmgPaletteColorFun {
GambatteSource &source; int palnum; int colornum; unsigned long rgb32;
void operator()() const { source.setDmgPaletteColor(palnum, colornum, rgb32); }
};
struct SetVideoSourceFun {
GambatteSource &source; std::size_t sourceIndex;
void operator()() const { source.setVideoSource(sourceIndex); }
};
struct SetSaveDirFun {
GambatteSource &source; QString path;
void operator()() const { source.setSavedir(path.toLocal8Bit().constData()); }
};
} // anon ns
void GambatteMenuHandler::setDmgPaletteColors() {
for (int palnum = 0; palnum < 3; ++palnum)
for (int colornum = 0; colornum < 4; ++colornum) {
SetDmgPaletteColorFun fun = { source_, palnum, colornum,
romPaletteDialog_->color(palnum, colornum) };
mw_.callInWorkerThread(fun);
}
}
void GambatteMenuHandler::videoDialogChange() {
{
SetVideoSourceFun fun = { source_, videoDialog_->sourceIndex() };
mw_.callInWorkerThread(fun);
}
applySettings(mw_, *videoDialog_);
windowSizeMenu_.videoDialogChange(*videoDialog_);
reconsiderSyncFrameRateActionEnable();
}
void GambatteMenuHandler::soundDialogChange() {
applySettings(mw_, *soundDialog_);
}
void GambatteMenuHandler::miscDialogChange() {
SetSaveDirFun const setSaveDirFun = { source_, miscDialog_->savePath() };
mw_.callInWorkerThread(setSaveDirFun);
mw_.setDwmTripleBuffer(miscDialog_->dwmTripleBuf());
mw_.setFastForwardSpeed(miscDialog_->turboSpeed());
mw_.setPauseOnFocusOut(miscDialog_->pauseOnFocusOut() ? 2 : 0);
pauseInc_ = miscDialog_->pauseOnDialogs() ? 4 : 0;
}
void GambatteMenuHandler::cheatDialogChange() {
std::string gameGenieCodes;
std::string gameSharkCodes;
foreach (QString const &s, cheatDialog_->cheats().split(';', QString::SkipEmptyParts)) {
if (s.contains('-')) {
gameGenieCodes += s.toStdString() + ';';
} else
gameSharkCodes += s.toStdString() + ';';
}
source_.setGameGenie(gameGenieCodes);
source_.setGameShark(gameSharkCodes);
}
void GambatteMenuHandler::reconsiderSyncFrameRateActionEnable() {
if (mw_.blitterConf(videoDialog_->blitterNo()).maxSwapInterval()
&& !MainWindow::isDwmCompositionEnabled()) {
syncFrameRateAction_->setEnabled(true);
} else {
if (syncFrameRateAction_->isChecked())
syncFrameRateAction_->trigger();
syncFrameRateAction_->setEnabled(false);
}
}
void GambatteMenuHandler::execGlobalPaletteDialog() {
TmpPauser tmpPauser(mw_, pauseInc_);
globalPaletteDialog_->exec();
}
void GambatteMenuHandler::execRomPaletteDialog() {
TmpPauser tmpPauser(mw_, pauseInc_);
romPaletteDialog_->exec();
}
void GambatteMenuHandler::execInputDialog() {
TmpPauser tmpPauser(mw_, pauseInc_);
source_.inputDialog()->exec();
}
void GambatteMenuHandler::execSoundDialog() {
TmpPauser tmpPauser(mw_, pauseInc_);
soundDialog_->exec();
}
void GambatteMenuHandler::execVideoDialog() {
TmpPauser tmpPauser(mw_, pauseInc_);
videoDialog_->exec();
}
void GambatteMenuHandler::execMiscDialog() {
TmpPauser tmpPauser(mw_, pauseInc_);
miscDialog_->exec();
}
void GambatteMenuHandler::prevStateSlot() {
stateSlotGroup_->actions().at(source_.currentState() < 2
? source_.currentState() + 8
: source_.currentState() - 2)->trigger();
}
void GambatteMenuHandler::nextStateSlot() {
stateSlotGroup_->actions().at(source_.currentState())->trigger();
}
namespace {
struct SelectStateFun {
GambatteSource &source; int i;
void operator()() const { source.selectState(i); }
};
struct SaveStateFun {
GambatteSource &source;
MainWindow::FrameBuffer fb;
void operator()() const {
source.saveState(MainWindow::FrameBuffer::Locked(fb).get());
}
};
struct LoadStateFun {
GambatteSource &source;
void operator()() const { source.loadState(); }
};
struct SaveStateAsFun {
GambatteSource &source;
MainWindow::FrameBuffer fb;
QString fileName;
void operator()() const {
source.saveState(MainWindow::FrameBuffer::Locked(fb).get(),
fileName.toLocal8Bit().constData());
}
};
struct LoadStateFromFun {
GambatteSource &source;
QString fileName;
void operator()() const {
source.loadState(fileName.toLocal8Bit().constData());
}
};
struct ResetFun {
GambatteSource &source;
void operator()() const { source.reset(); }
};
} // anon ns
void GambatteMenuHandler::selectStateSlot() {
if (QAction *action = stateSlotGroup_->checkedAction()) {
SelectStateFun fun = { source_, action->data().toInt() };
mw_.callInWorkerThread(fun);
}
}
void GambatteMenuHandler::saveState() {
SaveStateFun fun = { source_, MainWindow::FrameBuffer(mw_) };
mw_.callInWorkerThread(fun);
}
void GambatteMenuHandler::loadState() {
LoadStateFun fun = { source_ };
mw_.callInWorkerThread(fun);
}
void GambatteMenuHandler::saveStateAs() {
TmpPauser tmpPauser(mw_, 4);
mw_.waitUntilPaused();
QString const &fileName = QFileDialog::getSaveFileName(
&mw_, tr("Save State"), QString(),
tr("Gambatte Quick Save Files (*.gqs);;All Files (*)"));
if (!fileName.isEmpty()) {
SaveStateAsFun fun = { source_, MainWindow::FrameBuffer(mw_), fileName };
mw_.callInWorkerThread(fun);
}
}
void GambatteMenuHandler::loadStateFrom() {
TmpPauser tmpPauser(mw_, 4);
mw_.waitUntilPaused();
QString const &fileName = QFileDialog::getOpenFileName(
&mw_, tr("Load State"), QString(),
tr("Gambatte Quick Save Files (*.gqs);;All Files (*)"));
if (!fileName.isEmpty()) {
LoadStateFromFun fun = { source_, fileName };
mw_.callInWorkerThread(fun);
}
}
void GambatteMenuHandler::reset() {
ResetFun fun = { source_ };
mw_.callInWorkerThread(fun);
}
void GambatteMenuHandler::pauseChange() {
if (pauseAction_->isChecked())
mw_.pause();
else
mw_.unpause();
}
void GambatteMenuHandler::frameStep() {
if (pauseAction_->isChecked())
mw_.frameStep();
else
pauseAction_->trigger();
}
void GambatteMenuHandler::escPressed() {
#ifdef Q_WS_MAC
if (fsAct_->isChecked())
fsAct_->trigger();
#else
mw_.menuBar()->setVisible(!mw_.menuBar()->isVisible());
if (!mw_.menuBar()->isVisible())
mw_.hideCursor();
#endif
}
void GambatteMenuHandler::videoBlitterFailure() {
TmpPauser tmpPauser(mw_, pauseInc_);
QMessageBox::critical(&mw_, tr("Video engine failure"),
tr("Failed to update video output. This may be fixed by changing the video engine settings."));
videoDialog_->exec();
}
void GambatteMenuHandler::audioEngineFailure() {
TmpPauser tmpPauser(mw_, pauseInc_);
QMessageBox::critical(&mw_, tr("Sound engine failure"),
tr("Failed to output audio. This may be fixed by changing the sound settings."));
soundDialog_->exec();
}
void GambatteMenuHandler::toggleFullScreen() {
saveWindowSizeIfNotFullScreen();
mw_.toggleFullScreen();
}
void GambatteMenuHandler::saveWindowSizeIfNotFullScreen() {
if (!mw_.isFullScreen()) {
QSettings settings;
settings.setValue("mainwindow/size", mw_.size());
}
}