mirror of
https://github.com/hrydgard/ppsspp.git
synced 2024-11-26 15:00:34 +00:00
355 lines
9.4 KiB
C++
355 lines
9.4 KiB
C++
#pragma once
|
|
|
|
#include <queue>
|
|
#include <mutex>
|
|
#include <string>
|
|
|
|
#include <QtCore>
|
|
#include <QMenuBar>
|
|
#include <QMainWindow>
|
|
#include <QActionGroup>
|
|
|
|
#include "ppsspp_config.h"
|
|
#include "Common/System/System.h"
|
|
#include "Common/System/NativeApp.h"
|
|
#if PPSSPP_PLATFORM(WINDOWS)
|
|
#include "Common/Log/ConsoleListener.h"
|
|
#endif
|
|
#include "Core/Core.h"
|
|
#include "Core/Config.h"
|
|
#include "Core/System.h"
|
|
#include "Qt/QtMain.h"
|
|
|
|
extern bool g_TakeScreenshot;
|
|
|
|
class MenuAction;
|
|
class MenuTree;
|
|
|
|
enum {
|
|
FB_NON_BUFFERED_MODE = 0,
|
|
FB_BUFFERED_MODE = 1,
|
|
};
|
|
|
|
// hacky, should probably use qt signals or something, but whatever..
|
|
enum class MainWindowMsg {
|
|
BOOT_DONE,
|
|
WINDOW_TITLE_CHANGED,
|
|
};
|
|
|
|
class MainWindow : public QMainWindow
|
|
{
|
|
Q_OBJECT
|
|
|
|
public:
|
|
explicit MainWindow(QWidget *parent = nullptr, bool fullscreen = false);
|
|
~MainWindow() { };
|
|
|
|
CoreState GetNextState() { return nextState; }
|
|
|
|
void updateMenuGroupInt(QActionGroup *group, int value);
|
|
|
|
void updateMenus();
|
|
|
|
void Notify(MainWindowMsg msg) {
|
|
std::unique_lock<std::mutex> lock(msgMutex_);
|
|
msgQueue_.push(msg);
|
|
}
|
|
|
|
void SetWindowTitleAsync(std::string title) {
|
|
std::unique_lock<std::mutex> lock(titleMutex_);
|
|
newWindowTitle_ = title;
|
|
Notify(MainWindowMsg::WINDOW_TITLE_CHANGED);
|
|
}
|
|
|
|
protected:
|
|
void changeEvent(QEvent *e)
|
|
{
|
|
QMainWindow::changeEvent(e);
|
|
// Does not work on Linux for Qt5.2 or Qt5.3 (Qt bug)
|
|
if(e->type() == QEvent::WindowStateChange)
|
|
Core_NotifyWindowHidden(isMinimized());
|
|
}
|
|
|
|
void closeEvent(QCloseEvent *) { exitAct(); }
|
|
|
|
signals:
|
|
void retranslate();
|
|
void updateMenu();
|
|
|
|
public slots:
|
|
void newFrame();
|
|
|
|
private slots:
|
|
// File
|
|
void loadAct();
|
|
void closeAct();
|
|
void openmsAct();
|
|
void saveStateGroup_triggered(QAction *action) { g_Config.iCurrentStateSlot = action->data().toInt(); }
|
|
void qlstateAct();
|
|
void qsstateAct();
|
|
void lstateAct();
|
|
void sstateAct();
|
|
void recordDisplayAct();
|
|
void useLosslessVideoCodecAct();
|
|
void useOutputBufferAct();
|
|
void recordAudioAct();
|
|
void exitAct();
|
|
|
|
// Emulation
|
|
void runAct();
|
|
void pauseAct();
|
|
void stopAct();
|
|
void resetAct();
|
|
void switchUMDAct();
|
|
void displayRotationGroup_triggered(QAction *action) { g_Config.iInternalScreenRotation = action->data().toInt(); }
|
|
|
|
// Debug
|
|
void breakonloadAct();
|
|
void ignoreIllegalAct() { g_Config.bIgnoreBadMemAccess = !g_Config.bIgnoreBadMemAccess; }
|
|
void lmapAct();
|
|
void smapAct();
|
|
void lsymAct();
|
|
void ssymAct();
|
|
void resetTableAct();
|
|
void dumpNextAct();
|
|
void takeScreen() { g_TakeScreenshot = true; }
|
|
void consoleAct();
|
|
|
|
// Game settings
|
|
void languageAct() { System_PostUIMessage(UIMessage::SHOW_LANGUAGE_SCREEN); }
|
|
void controlMappingAct() { System_PostUIMessage(UIMessage::SHOW_CONTROL_MAPPING); }
|
|
void displayLayoutEditorAct() { System_PostUIMessage(UIMessage::SHOW_DISPLAY_LAYOUT_EDITOR); }
|
|
void moreSettingsAct() { System_PostUIMessage(UIMessage::SHOW_SETTINGS); }
|
|
|
|
void bufferRenderAct() {
|
|
System_PostUIMessage(UIMessage::GPU_RENDER_RESIZED);
|
|
System_PostUIMessage(UIMessage::GPU_CONFIG_CHANGED);
|
|
}
|
|
void linearAct() { g_Config.iTexFiltering = (g_Config.iTexFiltering != 0) ? 0 : 3; }
|
|
|
|
void renderingResolutionGroup_triggered(QAction *action) {
|
|
g_Config.iInternalResolution = action->data().toInt();
|
|
System_PostUIMessage(UIMessage::GPU_RENDER_RESIZED);
|
|
}
|
|
void windowGroup_triggered(QAction *action) { SetWindowScale(action->data().toInt()); }
|
|
|
|
void autoframeskipAct() {
|
|
g_Config.bAutoFrameSkip = !g_Config.bAutoFrameSkip;
|
|
if (g_Config.bSkipBufferEffects) {
|
|
g_Config.bSkipBufferEffects = false;
|
|
System_PostUIMessage(UIMessage::GPU_CONFIG_CHANGED);
|
|
}
|
|
}
|
|
void frameSkippingGroup_triggered(QAction *action) { g_Config.iFrameSkip = action->data().toInt(); }
|
|
void frameSkippingTypeGroup_triggered(QAction *action) { g_Config.iFrameSkipType = action->data().toInt(); }
|
|
void textureFilteringGroup_triggered(QAction *action) { g_Config.iTexFiltering = action->data().toInt(); }
|
|
void screenScalingFilterGroup_triggered(QAction *action) { g_Config.iDisplayFilter = action->data().toInt(); }
|
|
void textureScalingLevelGroup_triggered(QAction *action) {
|
|
g_Config.iTexScalingLevel = action->data().toInt();
|
|
System_PostUIMessage(UIMessage::GPU_CONFIG_CHANGED);
|
|
}
|
|
void textureScalingTypeGroup_triggered(QAction *action) {
|
|
g_Config.iTexScalingType = action->data().toInt();
|
|
System_PostUIMessage(UIMessage::GPU_CONFIG_CHANGED);
|
|
}
|
|
void deposterizeAct() {
|
|
g_Config.bTexDeposterize = !g_Config.bTexDeposterize;
|
|
System_PostUIMessage(UIMessage::GPU_CONFIG_CHANGED);
|
|
}
|
|
void transformAct() {
|
|
g_Config.bHardwareTransform = !g_Config.bHardwareTransform;
|
|
System_PostUIMessage(UIMessage::GPU_CONFIG_CHANGED);
|
|
}
|
|
void frameskipAct() { g_Config.iFrameSkip = !g_Config.iFrameSkip; }
|
|
void frameskipTypeAct() { g_Config.iFrameSkipType = !g_Config.iFrameSkipType; }
|
|
|
|
// Sound
|
|
void audioAct() {
|
|
g_Config.bEnableSound = !g_Config.bEnableSound;
|
|
}
|
|
|
|
// Cheats
|
|
void cheatsAct() { g_Config.bEnableCheats = !g_Config.bEnableCheats; }
|
|
|
|
// Chat
|
|
void chatAct() {
|
|
if (GetUIState() == UISTATE_INGAME) {
|
|
System_PostUIMessage(UIMessage::SHOW_CHAT_SCREEN);
|
|
}
|
|
}
|
|
|
|
void fullscrAct();
|
|
void raiseTopMost();
|
|
|
|
// Help
|
|
void websiteAct();
|
|
void forumAct();
|
|
void goldAct();
|
|
void gitAct();
|
|
void discordAct();
|
|
void aboutAct();
|
|
|
|
// Others
|
|
void langChanged(QAction *action) { loadLanguage(action->data().toString(), true); }
|
|
|
|
private:
|
|
void bootDone();
|
|
void SetWindowScale(int zoom);
|
|
void SetGameTitle(QString text);
|
|
void SetFullScreen(bool fullscreen);
|
|
void loadLanguage(const QString &language, bool retranslate);
|
|
void createMenus();
|
|
|
|
QTranslator translator;
|
|
QString currentLanguage;
|
|
|
|
CoreState nextState;
|
|
GlobalUIState lastUIState;
|
|
|
|
QActionGroup *windowGroup,
|
|
*textureScalingLevelGroup, *textureScalingTypeGroup,
|
|
*screenScalingFilterGroup, *textureFilteringGroup,
|
|
*frameSkippingTypeGroup, *frameSkippingGroup,
|
|
*renderingResolutionGroup,
|
|
*displayRotationGroup, *saveStateGroup;
|
|
|
|
std::queue<MainWindowMsg> msgQueue_;
|
|
std::mutex msgMutex_;
|
|
|
|
std::string newWindowTitle_;
|
|
std::mutex titleMutex_;
|
|
};
|
|
|
|
class MenuAction : public QAction
|
|
{
|
|
Q_OBJECT
|
|
|
|
public:
|
|
// Add to QMenu
|
|
MenuAction(QWidget* parent, const char *callback, const char *text, QKeySequence key = 0) :
|
|
QAction(parent), _text(text)
|
|
{
|
|
if (key != (QKeySequence)0) {
|
|
this->setShortcut(key);
|
|
parent->addAction(this); // So we don't lose the shortcut when menubar is hidden
|
|
}
|
|
connect(this, SIGNAL(triggered()), parent, callback);
|
|
connect(parent, SIGNAL(retranslate()), this, SLOT(retranslate()));
|
|
connect(parent, SIGNAL(updateMenu()), this, SLOT(update()));
|
|
}
|
|
// Add to QActionGroup
|
|
MenuAction(QWidget* parent, QActionGroup* group, QVariant data, QString text, QKeySequence key = 0) :
|
|
QAction(parent)
|
|
{
|
|
this->setCheckable(true);
|
|
this->setData(data);
|
|
this->setText(text); // Not translatable, yet
|
|
if (key != (QKeySequence)0) {
|
|
this->setShortcut(key);
|
|
parent->addAction(this); // So we don't lose the shortcut when menubar is hidden
|
|
}
|
|
group->addAction(this);
|
|
}
|
|
// Event which causes it to be checked
|
|
void addEventChecked(bool* event) {
|
|
this->setCheckable(true);
|
|
_eventCheck = event;
|
|
}
|
|
// TODO: Possibly handle compares
|
|
void addEventChecked(int* event) {
|
|
this->setCheckable(true);
|
|
_eventCheck = (bool*)event;
|
|
}
|
|
// Event which causes it to be unchecked
|
|
void addEventUnchecked(bool* event) {
|
|
this->setCheckable(true);
|
|
_eventUncheck = event;
|
|
}
|
|
// UI State which causes it to be enabled
|
|
void addEnableState(int state) {
|
|
_enabledFunc = nullptr;
|
|
_stateEnable = state;
|
|
_stateDisable = -1;
|
|
}
|
|
void addDisableState(int state) {
|
|
_enabledFunc = nullptr;
|
|
_stateEnable = -1;
|
|
_stateDisable = state;
|
|
}
|
|
void SetEnabledFunc(std::function<bool()> func) {
|
|
_enabledFunc = func;
|
|
_stateEnable = -1;
|
|
_stateDisable = -1;
|
|
}
|
|
public slots:
|
|
void retranslate() {
|
|
setText(qApp->translate("MainWindow", _text));
|
|
}
|
|
void update() {
|
|
if (_eventCheck)
|
|
setChecked(*_eventCheck);
|
|
if (_eventUncheck)
|
|
setChecked(!*_eventUncheck);
|
|
if (_stateEnable >= 0)
|
|
setEnabled(GetUIState() == _stateEnable);
|
|
if (_stateDisable >= 0)
|
|
setEnabled(GetUIState() != _stateDisable);
|
|
if (_enabledFunc)
|
|
setEnabled(_enabledFunc());
|
|
}
|
|
private:
|
|
const char *_text;
|
|
bool *_eventCheck = nullptr;
|
|
bool *_eventUncheck = nullptr;
|
|
int _stateEnable = -1;
|
|
int _stateDisable = -1;
|
|
std::function<bool()> _enabledFunc;
|
|
};
|
|
|
|
class MenuActionGroup : public QActionGroup
|
|
{
|
|
Q_OBJECT
|
|
public:
|
|
MenuActionGroup(QWidget* parent, QMenu* menu, const char* callback, QStringList nameList,
|
|
QList<int> valueList, QList<int> keyList = QList<int>()) :
|
|
QActionGroup(parent)
|
|
{
|
|
QListIterator<int> i(valueList);
|
|
QListIterator<int> k(keyList);
|
|
foreach(QString name, nameList) {
|
|
new MenuAction(parent, this, i.next(), name, keyList.size() ? k.next() : 0);
|
|
}
|
|
connect(this, SIGNAL(triggered(QAction *)), parent, callback);
|
|
menu->addActions(this->actions());
|
|
}
|
|
};
|
|
|
|
class MenuTree : public QMenu
|
|
{
|
|
Q_OBJECT
|
|
public:
|
|
MenuTree(QWidget* parent, QMenuBar* menu, const char *text) :
|
|
QMenu(parent), _text(text)
|
|
{
|
|
menu->addMenu(this);
|
|
connect(parent, SIGNAL(retranslate()), this, SLOT(retranslate()));
|
|
}
|
|
MenuTree(QWidget* parent, QMenu* menu, const char *text) :
|
|
QMenu(parent), _text(text)
|
|
{
|
|
menu->addMenu(this);
|
|
connect(parent, SIGNAL(retranslate()), this, SLOT(retranslate()));
|
|
}
|
|
MenuAction* add(MenuAction* action)
|
|
{
|
|
addAction(action);
|
|
return action;
|
|
}
|
|
public slots:
|
|
void retranslate() {
|
|
setTitle(qApp->translate("MainWindow", _text));
|
|
}
|
|
private:
|
|
const char *_text;
|
|
};
|