ppsspp/Qt/mainwindow.h

353 lines
9.3 KiB
C
Raw Normal View History

#pragma once
#include <queue>
#include <mutex>
#include <string>
#include <QtCore>
#include <QMenuBar>
#include <QMainWindow>
#include <QActionGroup>
#include "Common/System/System.h"
#include "Common/System/NativeApp.h"
#include "ConsoleListener.h"
#include "Core/Core.h"
#include "Core/Config.h"
#include "Core/System.h"
#include "Qt/QtMain.h"
extern bool g_TakeScreenshot;
class MenuAction;
class MenuTree;
2020-04-14 01:24:30 +00:00
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
{
2013-11-19 11:02:43 +00:00
Q_OBJECT
public:
explicit MainWindow(QWidget *parent = nullptr, bool fullscreen = false);
~MainWindow() { };
CoreState GetNextState() { return nextState; }
2013-02-19 20:59:53 +00:00
2020-04-17 23:46:11 +00:00
void updateMenuGroupInt(QActionGroup *group, int value);
void updateMenus();
2013-02-19 20:59:53 +00:00
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);
}
2013-02-19 20:59:53 +00:00
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();
2013-02-19 20:59:53 +00:00
public slots:
void newFrame();
private slots:
2013-02-19 20:59:53 +00:00
// 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();
2013-02-19 20:59:53 +00:00
// Emulation
void runAct();
void pauseAct();
void stopAct();
void resetAct();
void switchUMDAct();
void displayRotationGroup_triggered(QAction *action) { g_Config.iInternalScreenRotation = action->data().toInt(); }
2013-02-19 20:59:53 +00:00
// 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("language screen", ""); }
void controlMappingAct() { System_PostUIMessage("control mapping", ""); }
void displayLayoutEditorAct() { System_PostUIMessage("display layout editor", ""); }
void moreSettingsAct() { System_PostUIMessage("settings", ""); }
2018-06-09 23:35:13 +00:00
void bufferRenderAct() {
System_PostUIMessage("gpu_renderResized", "");
System_PostUIMessage("gpu_configChanged", "");
2018-06-09 23:35:13 +00:00
}
void linearAct() { g_Config.iTexFiltering = (g_Config.iTexFiltering != 0) ? 0 : 3; }
2020-04-12 22:48:19 +00:00
void renderingResolutionGroup_triggered(QAction *action) {
g_Config.iInternalResolution = action->data().toInt();
2023-07-06 16:39:13 +00:00
System_PostUIMessage("gpu_renderResized", "");
2020-04-12 22:48:19 +00:00
}
void windowGroup_triggered(QAction *action) { SetWindowScale(action->data().toInt()); }
2020-04-12 22:48:19 +00:00
void autoframeskipAct() {
g_Config.bAutoFrameSkip = !g_Config.bAutoFrameSkip;
2022-11-06 19:01:03 +00:00
if (g_Config.bSkipBufferEffects) {
g_Config.bSkipBufferEffects = false;
System_PostUIMessage("gpu_configChanged", "");
2020-04-13 11:40:47 +00:00
}
2020-04-12 22:48:19 +00:00
}
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(); }
2023-04-05 07:32:39 +00:00
void screenScalingFilterGroup_triggered(QAction *action) { g_Config.iDisplayFilter = action->data().toInt(); }
2020-04-12 22:48:19 +00:00
void textureScalingLevelGroup_triggered(QAction *action) {
g_Config.iTexScalingLevel = action->data().toInt();
System_PostUIMessage("gpu_configChanged", "");
2020-04-12 22:48:19 +00:00
}
void textureScalingTypeGroup_triggered(QAction *action) {
g_Config.iTexScalingType = action->data().toInt();
System_PostUIMessage("gpu_configChanged", "");
2020-04-12 22:48:19 +00:00
}
void deposterizeAct() {
g_Config.bTexDeposterize = !g_Config.bTexDeposterize;
System_PostUIMessage("gpu_configChanged", "");
2020-04-12 22:48:19 +00:00
}
void transformAct() {
g_Config.bHardwareTransform = !g_Config.bHardwareTransform;
System_PostUIMessage("gpu_configChanged", "");
}
void vertexCacheAct() { g_Config.bVertexCache = !g_Config.bVertexCache; }
void frameskipAct() { g_Config.iFrameSkip = !g_Config.iFrameSkip; }
void frameskipTypeAct() { g_Config.iFrameSkipType = !g_Config.iFrameSkipType; }
2013-02-19 20:59:53 +00:00
// Sound
2020-04-12 22:48:19 +00:00
void audioAct() {
g_Config.bEnableSound = !g_Config.bEnableSound;
}
// Cheats
void cheatsAct() { g_Config.bEnableCheats = !g_Config.bEnableCheats; }
// Chat
2021-02-17 18:30:52 +00:00
void chatAct() {
2021-09-15 12:32:54 +00:00
if (GetUIState() == UISTATE_INGAME) {
System_PostUIMessage("chat screen", "");
2021-09-15 12:32:54 +00:00
}
2021-02-17 18:30:52 +00:00
}
void fullscrAct();
void raiseTopMost();
2013-02-19 20:59:53 +00:00
// Help
void websiteAct();
2014-07-10 12:41:26 +00:00
void forumAct();
void goldAct();
void gitAct();
void discordAct();
void aboutAct();
2013-02-19 20:59:53 +00:00
// Others
void langChanged(QAction *action) { loadLanguage(action->data().toString(), true); }
2013-02-06 17:49:20 +00:00
private:
void bootDone();
void SetWindowScale(int zoom);
2013-02-19 20:59:53 +00:00
void SetGameTitle(QString text);
void SetFullScreen(bool fullscreen);
void loadLanguage(const QString &language, bool retranslate);
void createMenus();
2013-02-06 17:49:20 +00:00
QTranslator translator;
QString currentLanguage;
CoreState nextState;
2013-04-20 10:43:55 +00:00
GlobalUIState lastUIState;
2020-04-12 22:48:19 +00:00
QActionGroup *windowGroup,
*textureScalingLevelGroup, *textureScalingTypeGroup,
*screenScalingFilterGroup, *textureFilteringGroup,
*frameSkippingTypeGroup, *frameSkippingGroup,
2022-11-06 19:01:03 +00:00
*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
2014-02-15 09:47:14 +00:00
MenuAction(QWidget* parent, const char *callback, const char *text, QKeySequence key = 0) :
2021-09-15 12:32:54 +00:00
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) :
2021-09-15 12:32:54 +00:00
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;
}
2020-04-13 11:40:47 +00:00
// 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) {
2021-09-15 12:32:54 +00:00
_enabledFunc = nullptr;
_stateEnable = state;
2021-09-15 12:32:54 +00:00
_stateDisable = -1;
}
void addDisableState(int state) {
2021-09-15 12:32:54 +00:00
_enabledFunc = nullptr;
_stateEnable = -1;
_stateDisable = state;
}
2021-09-15 12:32:54 +00:00
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);
2020-04-13 11:40:47 +00:00
if (_eventUncheck)
2020-04-14 01:24:30 +00:00
setChecked(!*_eventUncheck);
if (_stateEnable >= 0)
setEnabled(GetUIState() == _stateEnable);
if (_stateDisable >= 0)
setEnabled(GetUIState() != _stateDisable);
2021-09-15 12:32:54 +00:00
if (_enabledFunc)
setEnabled(_enabledFunc());
}
private:
2014-02-15 09:47:14 +00:00
const char *_text;
2021-09-15 12:32:54 +00:00
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) {
2014-07-10 12:41:26 +00:00
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:
2014-02-15 09:47:14 +00:00
MenuTree(QWidget* parent, QMenuBar* menu, const char *text) :
QMenu(parent), _text(text)
{
menu->addMenu(this);
connect(parent, SIGNAL(retranslate()), this, SLOT(retranslate()));
}
2014-02-15 09:47:14 +00:00
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:
2014-02-15 09:47:14 +00:00
const char *_text;
};