summaryrefslogtreecommitdiff
path: root/src/citra_qt
diff options
context:
space:
mode:
Diffstat (limited to 'src/citra_qt')
-rw-r--r--src/citra_qt/CMakeLists.txt21
-rw-r--r--src/citra_qt/bootmanager.cpp2
-rw-r--r--src/citra_qt/config.cpp91
-rw-r--r--src/citra_qt/configure.ui108
-rw-r--r--src/citra_qt/configure_audio.cpp44
-rw-r--r--src/citra_qt/configure_audio.h27
-rw-r--r--src/citra_qt/configure_audio.ui48
-rw-r--r--src/citra_qt/configure_debug.cpp31
-rw-r--r--src/citra_qt/configure_debug.h29
-rw-r--r--src/citra_qt/configure_debug.ui102
-rw-r--r--src/citra_qt/configure_dialog.cpp30
-rw-r--r--src/citra_qt/configure_dialog.h29
-rw-r--r--src/citra_qt/configure_general.cpp39
-rw-r--r--src/citra_qt/configure_general.h29
-rw-r--r--src/citra_qt/configure_general.ui173
-rw-r--r--src/citra_qt/debugger/graphics_breakpoints.cpp6
-rw-r--r--src/citra_qt/debugger/graphics_framebuffer.cpp6
-rw-r--r--src/citra_qt/debugger/graphics_tracing.cpp6
-rw-r--r--src/citra_qt/debugger/graphics_vertex_shader.cpp8
-rw-r--r--src/citra_qt/debugger/profiler.cpp55
-rw-r--r--src/citra_qt/debugger/profiler.h3
-rw-r--r--src/citra_qt/game_list.cpp27
-rw-r--r--src/citra_qt/game_list.h6
-rw-r--r--src/citra_qt/game_list_p.h106
-rw-r--r--src/citra_qt/hotkeys.cpp54
-rw-r--r--src/citra_qt/hotkeys.h8
-rw-r--r--src/citra_qt/hotkeys.ui47
-rw-r--r--src/citra_qt/main.cpp184
-rw-r--r--src/citra_qt/main.h8
-rw-r--r--src/citra_qt/main.ui51
-rw-r--r--src/citra_qt/ui_settings.cpp11
-rw-r--r--src/citra_qt/ui_settings.h47
-rw-r--r--src/citra_qt/util/util.cpp2
33 files changed, 1122 insertions, 316 deletions
diff --git a/src/citra_qt/CMakeLists.txt b/src/citra_qt/CMakeLists.txt
index 9b3eb2cd6..0a5d4624b 100644
--- a/src/citra_qt/CMakeLists.txt
+++ b/src/citra_qt/CMakeLists.txt
@@ -17,12 +17,17 @@ set(SRCS
17 debugger/profiler.cpp 17 debugger/profiler.cpp
18 debugger/ramview.cpp 18 debugger/ramview.cpp
19 debugger/registers.cpp 19 debugger/registers.cpp
20 game_list.cpp
21 util/spinbox.cpp 20 util/spinbox.cpp
22 util/util.cpp 21 util/util.cpp
23 bootmanager.cpp 22 bootmanager.cpp
23 configure_audio.cpp
24 configure_debug.cpp
25 configure_dialog.cpp
26 configure_general.cpp
27 game_list.cpp
24 hotkeys.cpp 28 hotkeys.cpp
25 main.cpp 29 main.cpp
30 ui_settings.cpp
26 citra-qt.rc 31 citra-qt.rc
27 Info.plist 32 Info.plist
28 ) 33 )
@@ -44,12 +49,18 @@ set(HEADERS
44 debugger/profiler.h 49 debugger/profiler.h
45 debugger/ramview.h 50 debugger/ramview.h
46 debugger/registers.h 51 debugger/registers.h
47 game_list.h
48 util/spinbox.h 52 util/spinbox.h
49 util/util.h 53 util/util.h
50 bootmanager.h 54 bootmanager.h
55 configure_audio.h
56 configure_debug.h
57 configure_dialog.h
58 configure_general.h
59 game_list.h
60 game_list_p.h
51 hotkeys.h 61 hotkeys.h
52 main.h 62 main.h
63 ui_settings.h
53 version.h 64 version.h
54 ) 65 )
55 66
@@ -59,6 +70,10 @@ set(UIS
59 debugger/disassembler.ui 70 debugger/disassembler.ui
60 debugger/profiler.ui 71 debugger/profiler.ui
61 debugger/registers.ui 72 debugger/registers.ui
73 configure.ui
74 configure_audio.ui
75 configure_debug.ui
76 configure_general.ui
62 hotkeys.ui 77 hotkeys.ui
63 main.ui 78 main.ui
64 ) 79 )
@@ -81,7 +96,7 @@ else()
81endif() 96endif()
82target_link_libraries(citra-qt core video_core audio_core common qhexedit) 97target_link_libraries(citra-qt core video_core audio_core common qhexedit)
83target_link_libraries(citra-qt ${OPENGL_gl_LIBRARY} ${CITRA_QT_LIBS}) 98target_link_libraries(citra-qt ${OPENGL_gl_LIBRARY} ${CITRA_QT_LIBS})
84target_link_libraries(citra-qt ${PLATFORM_LIBRARIES}) 99target_link_libraries(citra-qt ${PLATFORM_LIBRARIES} Threads::Threads)
85 100
86if(${CMAKE_SYSTEM_NAME} MATCHES "Linux|FreeBSD|OpenBSD|NetBSD") 101if(${CMAKE_SYSTEM_NAME} MATCHES "Linux|FreeBSD|OpenBSD|NetBSD")
87 install(TARGETS citra-qt RUNTIME DESTINATION "${CMAKE_INSTALL_PREFIX}/bin") 102 install(TARGETS citra-qt RUNTIME DESTINATION "${CMAKE_INSTALL_PREFIX}/bin")
diff --git a/src/citra_qt/bootmanager.cpp b/src/citra_qt/bootmanager.cpp
index 8e60b9cad..01b81c11c 100644
--- a/src/citra_qt/bootmanager.cpp
+++ b/src/citra_qt/bootmanager.cpp
@@ -71,7 +71,9 @@ void EmuThread::run() {
71 // Shutdown the core emulation 71 // Shutdown the core emulation
72 System::Shutdown(); 72 System::Shutdown();
73 73
74#if MICROPROFILE_ENABLED
74 MicroProfileOnThreadExit(); 75 MicroProfileOnThreadExit();
76#endif
75 77
76 render_window->moveContext(); 78 render_window->moveContext();
77} 79}
diff --git a/src/citra_qt/config.cpp b/src/citra_qt/config.cpp
index 66271aa7b..f6e498128 100644
--- a/src/citra_qt/config.cpp
+++ b/src/citra_qt/config.cpp
@@ -7,12 +7,12 @@
7#include <QStringList> 7#include <QStringList>
8 8
9#include "citra_qt/config.h" 9#include "citra_qt/config.h"
10#include "citra_qt/ui_settings.h"
10 11
11#include "common/file_util.h" 12#include "common/file_util.h"
12#include "core/settings.h" 13#include "core/settings.h"
13 14
14Config::Config() { 15Config::Config() {
15
16 // TODO: Don't hardcode the path; let the frontend decide where to put the config files. 16 // TODO: Don't hardcode the path; let the frontend decide where to put the config files.
17 qt_config_loc = FileUtil::GetUserPath(D_CONFIG_IDX) + "qt-config.ini"; 17 qt_config_loc = FileUtil::GetUserPath(D_CONFIG_IDX) + "qt-config.ini";
18 FileUtil::CreateFullPath(qt_config_loc); 18 FileUtil::CreateFullPath(qt_config_loc);
@@ -45,12 +45,17 @@ void Config::ReadValues() {
45 qt_config->beginGroup("Renderer"); 45 qt_config->beginGroup("Renderer");
46 Settings::values.use_hw_renderer = qt_config->value("use_hw_renderer", false).toBool(); 46 Settings::values.use_hw_renderer = qt_config->value("use_hw_renderer", false).toBool();
47 Settings::values.use_shader_jit = qt_config->value("use_shader_jit", true).toBool(); 47 Settings::values.use_shader_jit = qt_config->value("use_shader_jit", true).toBool();
48 Settings::values.use_scaled_resolution = qt_config->value("use_scaled_resolution", false).toBool();
48 49
49 Settings::values.bg_red = qt_config->value("bg_red", 1.0).toFloat(); 50 Settings::values.bg_red = qt_config->value("bg_red", 1.0).toFloat();
50 Settings::values.bg_green = qt_config->value("bg_green", 1.0).toFloat(); 51 Settings::values.bg_green = qt_config->value("bg_green", 1.0).toFloat();
51 Settings::values.bg_blue = qt_config->value("bg_blue", 1.0).toFloat(); 52 Settings::values.bg_blue = qt_config->value("bg_blue", 1.0).toFloat();
52 qt_config->endGroup(); 53 qt_config->endGroup();
53 54
55 qt_config->beginGroup("Audio");
56 Settings::values.sink_id = qt_config->value("output_engine", "auto").toString().toStdString();
57 qt_config->endGroup();
58
54 qt_config->beginGroup("Data Storage"); 59 qt_config->beginGroup("Data Storage");
55 Settings::values.use_virtual_sd = qt_config->value("use_virtual_sd", true).toBool(); 60 Settings::values.use_virtual_sd = qt_config->value("use_virtual_sd", true).toBool();
56 qt_config->endGroup(); 61 qt_config->endGroup();
@@ -68,6 +73,51 @@ void Config::ReadValues() {
68 Settings::values.use_gdbstub = qt_config->value("use_gdbstub", false).toBool(); 73 Settings::values.use_gdbstub = qt_config->value("use_gdbstub", false).toBool();
69 Settings::values.gdbstub_port = qt_config->value("gdbstub_port", 24689).toInt(); 74 Settings::values.gdbstub_port = qt_config->value("gdbstub_port", 24689).toInt();
70 qt_config->endGroup(); 75 qt_config->endGroup();
76
77 qt_config->beginGroup("UI");
78
79 qt_config->beginGroup("UILayout");
80 UISettings::values.geometry = qt_config->value("geometry").toByteArray();
81 UISettings::values.state = qt_config->value("state").toByteArray();
82 UISettings::values.renderwindow_geometry = qt_config->value("geometryRenderWindow").toByteArray();
83 UISettings::values.gamelist_header_state = qt_config->value("gameListHeaderState").toByteArray();
84 UISettings::values.microprofile_geometry = qt_config->value("microProfileDialogGeometry").toByteArray();
85 UISettings::values.microprofile_visible = qt_config->value("microProfileDialogVisible", false).toBool();
86 qt_config->endGroup();
87
88 qt_config->beginGroup("Paths");
89 UISettings::values.roms_path = qt_config->value("romsPath").toString();
90 UISettings::values.symbols_path = qt_config->value("symbolsPath").toString();
91 UISettings::values.gamedir = qt_config->value("gameListRootDir", ".").toString();
92 UISettings::values.gamedir_deepscan = qt_config->value("gameListDeepScan", false).toBool();
93 UISettings::values.recent_files = qt_config->value("recentFiles").toStringList();
94 qt_config->endGroup();
95
96 qt_config->beginGroup("Shortcuts");
97 QStringList groups = qt_config->childGroups();
98 for (auto group : groups) {
99 qt_config->beginGroup(group);
100
101 QStringList hotkeys = qt_config->childGroups();
102 for (auto hotkey : hotkeys) {
103 qt_config->beginGroup(hotkey);
104 UISettings::values.shortcuts.emplace_back(
105 UISettings::Shortcut(group + "/" + hotkey,
106 UISettings::ContextualShortcut(qt_config->value("KeySeq").toString(),
107 qt_config->value("Context").toInt())));
108 qt_config->endGroup();
109 }
110
111 qt_config->endGroup();
112 }
113 qt_config->endGroup();
114
115 UISettings::values.single_window_mode = qt_config->value("singleWindowMode", true).toBool();
116 UISettings::values.display_titlebar = qt_config->value("displayTitleBars", true).toBool();
117 UISettings::values.confirm_before_closing = qt_config->value("confirmClose",true).toBool();
118 UISettings::values.first_start = qt_config->value("firstStart", true).toBool();
119
120 qt_config->endGroup();
71} 121}
72 122
73void Config::SaveValues() { 123void Config::SaveValues() {
@@ -85,6 +135,7 @@ void Config::SaveValues() {
85 qt_config->beginGroup("Renderer"); 135 qt_config->beginGroup("Renderer");
86 qt_config->setValue("use_hw_renderer", Settings::values.use_hw_renderer); 136 qt_config->setValue("use_hw_renderer", Settings::values.use_hw_renderer);
87 qt_config->setValue("use_shader_jit", Settings::values.use_shader_jit); 137 qt_config->setValue("use_shader_jit", Settings::values.use_shader_jit);
138 qt_config->setValue("use_scaled_resolution", Settings::values.use_scaled_resolution);
88 139
89 // Cast to double because Qt's written float values are not human-readable 140 // Cast to double because Qt's written float values are not human-readable
90 qt_config->setValue("bg_red", (double)Settings::values.bg_red); 141 qt_config->setValue("bg_red", (double)Settings::values.bg_red);
@@ -92,6 +143,10 @@ void Config::SaveValues() {
92 qt_config->setValue("bg_blue", (double)Settings::values.bg_blue); 143 qt_config->setValue("bg_blue", (double)Settings::values.bg_blue);
93 qt_config->endGroup(); 144 qt_config->endGroup();
94 145
146 qt_config->beginGroup("Audio");
147 qt_config->setValue("output_engine", QString::fromStdString(Settings::values.sink_id));
148 qt_config->endGroup();
149
95 qt_config->beginGroup("Data Storage"); 150 qt_config->beginGroup("Data Storage");
96 qt_config->setValue("use_virtual_sd", Settings::values.use_virtual_sd); 151 qt_config->setValue("use_virtual_sd", Settings::values.use_virtual_sd);
97 qt_config->endGroup(); 152 qt_config->endGroup();
@@ -109,10 +164,44 @@ void Config::SaveValues() {
109 qt_config->setValue("use_gdbstub", Settings::values.use_gdbstub); 164 qt_config->setValue("use_gdbstub", Settings::values.use_gdbstub);
110 qt_config->setValue("gdbstub_port", Settings::values.gdbstub_port); 165 qt_config->setValue("gdbstub_port", Settings::values.gdbstub_port);
111 qt_config->endGroup(); 166 qt_config->endGroup();
167
168 qt_config->beginGroup("UI");
169
170 qt_config->beginGroup("UILayout");
171 qt_config->setValue("geometry", UISettings::values.geometry);
172 qt_config->setValue("state", UISettings::values.state);
173 qt_config->setValue("geometryRenderWindow", UISettings::values.renderwindow_geometry);
174 qt_config->setValue("gameListHeaderState", UISettings::values.gamelist_header_state);
175 qt_config->setValue("microProfileDialogGeometry", UISettings::values.microprofile_geometry);
176 qt_config->setValue("microProfileDialogVisible", UISettings::values.microprofile_visible);
177 qt_config->endGroup();
178
179 qt_config->beginGroup("Paths");
180 qt_config->setValue("romsPath", UISettings::values.roms_path);
181 qt_config->setValue("symbolsPath", UISettings::values.symbols_path);
182 qt_config->setValue("gameListRootDir", UISettings::values.gamedir);
183 qt_config->setValue("gameListDeepScan", UISettings::values.gamedir_deepscan);
184 qt_config->setValue("recentFiles", UISettings::values.recent_files);
185 qt_config->endGroup();
186
187 qt_config->beginGroup("Shortcuts");
188 for (auto shortcut : UISettings::values.shortcuts ) {
189 qt_config->setValue(shortcut.first + "/KeySeq", shortcut.second.first);
190 qt_config->setValue(shortcut.first + "/Context", shortcut.second.second);
191 }
192 qt_config->endGroup();
193
194 qt_config->setValue("singleWindowMode", UISettings::values.single_window_mode);
195 qt_config->setValue("displayTitleBars", UISettings::values.display_titlebar);
196 qt_config->setValue("confirmClose", UISettings::values.confirm_before_closing);
197 qt_config->setValue("firstStart", UISettings::values.first_start);
198
199 qt_config->endGroup();
112} 200}
113 201
114void Config::Reload() { 202void Config::Reload() {
115 ReadValues(); 203 ReadValues();
204 Settings::Apply();
116} 205}
117 206
118void Config::Save() { 207void Config::Save() {
diff --git a/src/citra_qt/configure.ui b/src/citra_qt/configure.ui
new file mode 100644
index 000000000..e1624bbef
--- /dev/null
+++ b/src/citra_qt/configure.ui
@@ -0,0 +1,108 @@
1<?xml version="1.0" encoding="UTF-8"?>
2<ui version="4.0">
3 <class>ConfigureDialog</class>
4 <widget class="QDialog" name="ConfigureDialog">
5 <property name="geometry">
6 <rect>
7 <x>0</x>
8 <y>0</y>
9 <width>441</width>
10 <height>501</height>
11 </rect>
12 </property>
13 <property name="windowTitle">
14 <string>Citra Configuration</string>
15 </property>
16 <layout class="QVBoxLayout" name="verticalLayout">
17 <item>
18 <widget class="QTabWidget" name="tabWidget">
19 <property name="currentIndex">
20 <number>0</number>
21 </property>
22 <widget class="ConfigureGeneral" name="generalTab">
23 <attribute name="title">
24 <string>General</string>
25 </attribute>
26 </widget>
27 <widget class="QWidget" name="inputTab">
28 <attribute name="title">
29 <string>Input</string>
30 </attribute>
31 </widget>
32 <widget class="ConfigureAudio" name="audioTab">
33 <attribute name="title">
34 <string>Audio</string>
35 </attribute>
36 </widget>
37 <widget class="ConfigureDebug" name="debugTab">
38 <attribute name="title">
39 <string>Debug</string>
40 </attribute>
41 </widget>
42 </widget>
43 </item>
44 <item>
45 <widget class="QDialogButtonBox" name="buttonBox">
46 <property name="standardButtons">
47 <set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
48 </property>
49 </widget>
50 </item>
51 </layout>
52 </widget>
53 <customwidgets>
54 <customwidget>
55 <class>ConfigureGeneral</class>
56 <extends>QWidget</extends>
57 <header>configure_general.h</header>
58 <container>1</container>
59 </customwidget>
60 <customwidget>
61 <class>ConfigureAudio</class>
62 <extends>QWidget</extends>
63 <header>configure_audio.h</header>
64 <container>1</container>
65 </customwidget>
66 <customwidget>
67 <class>ConfigureDebug</class>
68 <extends>QWidget</extends>
69 <header>configure_debug.h</header>
70 <container>1</container>
71 </customwidget>
72 </customwidgets>
73 <resources/>
74 <connections>
75 <connection>
76 <sender>buttonBox</sender>
77 <signal>accepted()</signal>
78 <receiver>ConfigureDialog</receiver>
79 <slot>accept()</slot>
80 <hints>
81 <hint type="sourcelabel">
82 <x>220</x>
83 <y>380</y>
84 </hint>
85 <hint type="destinationlabel">
86 <x>220</x>
87 <y>200</y>
88 </hint>
89 </hints>
90 </connection>
91 <connection>
92 <sender>buttonBox</sender>
93 <signal>rejected()</signal>
94 <receiver>ConfigureDialog</receiver>
95 <slot>reject()</slot>
96 <hints>
97 <hint type="sourcelabel">
98 <x>220</x>
99 <y>380</y>
100 </hint>
101 <hint type="destinationlabel">
102 <x>220</x>
103 <y>200</y>
104 </hint>
105 </hints>
106 </connection>
107 </connections>
108</ui>
diff --git a/src/citra_qt/configure_audio.cpp b/src/citra_qt/configure_audio.cpp
new file mode 100644
index 000000000..cedfa2f2a
--- /dev/null
+++ b/src/citra_qt/configure_audio.cpp
@@ -0,0 +1,44 @@
1// Copyright 2016 Citra Emulator Project
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#include "audio_core/sink_details.h"
6
7#include "citra_qt/configure_audio.h"
8#include "ui_configure_audio.h"
9
10#include "core/settings.h"
11
12ConfigureAudio::ConfigureAudio(QWidget* parent) :
13 QWidget(parent),
14 ui(std::make_unique<Ui::ConfigureAudio>())
15{
16 ui->setupUi(this);
17
18 ui->output_sink_combo_box->clear();
19 ui->output_sink_combo_box->addItem("auto");
20 for (const auto& sink_detail : AudioCore::g_sink_details) {
21 ui->output_sink_combo_box->addItem(sink_detail.id);
22 }
23
24 this->setConfiguration();
25}
26
27ConfigureAudio::~ConfigureAudio() {
28}
29
30void ConfigureAudio::setConfiguration() {
31 int new_sink_index = 0;
32 for (int index = 0; index < ui->output_sink_combo_box->count(); index++) {
33 if (ui->output_sink_combo_box->itemText(index).toStdString() == Settings::values.sink_id) {
34 new_sink_index = index;
35 break;
36 }
37 }
38 ui->output_sink_combo_box->setCurrentIndex(new_sink_index);
39}
40
41void ConfigureAudio::applyConfiguration() {
42 Settings::values.sink_id = ui->output_sink_combo_box->itemText(ui->output_sink_combo_box->currentIndex()).toStdString();
43 Settings::Apply();
44}
diff --git a/src/citra_qt/configure_audio.h b/src/citra_qt/configure_audio.h
new file mode 100644
index 000000000..51df2e27b
--- /dev/null
+++ b/src/citra_qt/configure_audio.h
@@ -0,0 +1,27 @@
1// Copyright 2016 Citra Emulator Project
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#pragma once
6
7#include <memory>
8#include <QWidget>
9
10namespace Ui {
11class ConfigureAudio;
12}
13
14class ConfigureAudio : public QWidget {
15 Q_OBJECT
16
17public:
18 explicit ConfigureAudio(QWidget* parent = nullptr);
19 ~ConfigureAudio();
20
21 void applyConfiguration();
22
23private:
24 void setConfiguration();
25
26 std::unique_ptr<Ui::ConfigureAudio> ui;
27};
diff --git a/src/citra_qt/configure_audio.ui b/src/citra_qt/configure_audio.ui
new file mode 100644
index 000000000..d7f6946ca
--- /dev/null
+++ b/src/citra_qt/configure_audio.ui
@@ -0,0 +1,48 @@
1<?xml version="1.0" encoding="utf-8"?>
2
3<ui version="4.0">
4 <class>ConfigureAudio</class>
5 <widget class="QWidget" name="ConfigureAudio">
6 <layout class="QVBoxLayout">
7 <item>
8 <widget class="QGroupBox">
9 <property name="title">
10 <string>Audio</string>
11 </property>
12 <layout class="QVBoxLayout">
13 <item>
14 <layout class="QHBoxLayout">
15 <item>
16 <widget class="QLabel">
17 <property name="text">
18 <string>Output Engine:</string>
19 </property>
20 </widget>
21 </item>
22 <item>
23 <widget class="QComboBox" name="output_sink_combo_box">
24 </widget>
25 </item>
26 </layout>
27 </item>
28 </layout>
29 </widget>
30 </item>
31 <item>
32 <spacer>
33 <property name="orientation">
34 <enum>Qt::Vertical</enum>
35 </property>
36 <property name="sizeHint" stdset="0">
37 <size>
38 <width>20</width>
39 <height>40</height>
40 </size>
41 </property>
42 </spacer>
43 </item>
44 </layout>
45 </widget>
46 <resources />
47 <connections />
48</ui>
diff --git a/src/citra_qt/configure_debug.cpp b/src/citra_qt/configure_debug.cpp
new file mode 100644
index 000000000..dc3d7b906
--- /dev/null
+++ b/src/citra_qt/configure_debug.cpp
@@ -0,0 +1,31 @@
1// Copyright 2016 Citra Emulator Project
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#include "citra_qt/configure_debug.h"
6#include "ui_configure_debug.h"
7
8#include "core/settings.h"
9
10ConfigureDebug::ConfigureDebug(QWidget *parent) :
11 QWidget(parent),
12 ui(new Ui::ConfigureDebug)
13{
14 ui->setupUi(this);
15 this->setConfiguration();
16}
17
18ConfigureDebug::~ConfigureDebug() {
19}
20
21void ConfigureDebug::setConfiguration() {
22 ui->toogle_gdbstub->setChecked(Settings::values.use_gdbstub);
23 ui->gdbport_spinbox->setEnabled(Settings::values.use_gdbstub);
24 ui->gdbport_spinbox->setValue(Settings::values.gdbstub_port);
25}
26
27void ConfigureDebug::applyConfiguration() {
28 Settings::values.use_gdbstub = ui->toogle_gdbstub->isChecked();
29 Settings::values.gdbstub_port = ui->gdbport_spinbox->value();
30 Settings::Apply();
31}
diff --git a/src/citra_qt/configure_debug.h b/src/citra_qt/configure_debug.h
new file mode 100644
index 000000000..ab58ebbdc
--- /dev/null
+++ b/src/citra_qt/configure_debug.h
@@ -0,0 +1,29 @@
1// Copyright 2016 Citra Emulator Project
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#pragma once
6
7#include <memory>
8#include <QWidget>
9
10namespace Ui {
11class ConfigureDebug;
12}
13
14class ConfigureDebug : public QWidget
15{
16 Q_OBJECT
17
18public:
19 explicit ConfigureDebug(QWidget *parent = nullptr);
20 ~ConfigureDebug();
21
22 void applyConfiguration();
23
24private:
25 void setConfiguration();
26
27private:
28 std::unique_ptr<Ui::ConfigureDebug> ui;
29};
diff --git a/src/citra_qt/configure_debug.ui b/src/citra_qt/configure_debug.ui
new file mode 100644
index 000000000..3ba7f44da
--- /dev/null
+++ b/src/citra_qt/configure_debug.ui
@@ -0,0 +1,102 @@
1<?xml version="1.0" encoding="UTF-8"?>
2<ui version="4.0">
3 <class>ConfigureDebug</class>
4 <widget class="QWidget" name="ConfigureDebug">
5 <property name="geometry">
6 <rect>
7 <x>0</x>
8 <y>0</y>
9 <width>400</width>
10 <height>300</height>
11 </rect>
12 </property>
13 <property name="windowTitle">
14 <string>Form</string>
15 </property>
16 <layout class="QVBoxLayout" name="verticalLayout">
17 <item>
18 <layout class="QVBoxLayout" name="verticalLayout_3">
19 <item>
20 <widget class="QGroupBox" name="groupBox">
21 <property name="title">
22 <string>GDB</string>
23 </property>
24 <layout class="QVBoxLayout" name="verticalLayout_2">
25 <item>
26 <layout class="QHBoxLayout" name="horizontalLayout_3">
27 <item>
28 <widget class="QCheckBox" name="toogle_gdbstub">
29 <property name="text">
30 <string>Enable GDB Stub</string>
31 </property>
32 </widget>
33 </item>
34 <item>
35 <spacer name="horizontalSpacer">
36 <property name="orientation">
37 <enum>Qt::Horizontal</enum>
38 </property>
39 <property name="sizeHint" stdset="0">
40 <size>
41 <width>40</width>
42 <height>20</height>
43 </size>
44 </property>
45 </spacer>
46 </item>
47 <item>
48 <widget class="QLabel" name="label">
49 <property name="text">
50 <string>Port:</string>
51 </property>
52 </widget>
53 </item>
54 <item>
55 <widget class="QSpinBox" name="gdbport_spinbox">
56 <property name="maximum">
57 <number>65536</number>
58 </property>
59 </widget>
60 </item>
61 </layout>
62 </item>
63 </layout>
64 </widget>
65 </item>
66 </layout>
67 </item>
68 <item>
69 <spacer name="verticalSpacer">
70 <property name="orientation">
71 <enum>Qt::Vertical</enum>
72 </property>
73 <property name="sizeHint" stdset="0">
74 <size>
75 <width>20</width>
76 <height>40</height>
77 </size>
78 </property>
79 </spacer>
80 </item>
81 </layout>
82 </widget>
83 <resources/>
84 <connections>
85 <connection>
86 <sender>toogle_gdbstub</sender>
87 <signal>toggled(bool)</signal>
88 <receiver>gdbport_spinbox</receiver>
89 <slot>setEnabled(bool)</slot>
90 <hints>
91 <hint type="sourcelabel">
92 <x>84</x>
93 <y>157</y>
94 </hint>
95 <hint type="destinationlabel">
96 <x>342</x>
97 <y>158</y>
98 </hint>
99 </hints>
100 </connection>
101 </connections>
102</ui>
diff --git a/src/citra_qt/configure_dialog.cpp b/src/citra_qt/configure_dialog.cpp
new file mode 100644
index 000000000..2f0317fe0
--- /dev/null
+++ b/src/citra_qt/configure_dialog.cpp
@@ -0,0 +1,30 @@
1// Copyright 2016 Citra Emulator Project
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#include "citra_qt/config.h"
6#include "citra_qt/configure_dialog.h"
7#include "ui_configure.h"
8
9
10#include "core/settings.h"
11
12ConfigureDialog::ConfigureDialog(QWidget *parent) :
13 QDialog(parent),
14 ui(new Ui::ConfigureDialog)
15{
16 ui->setupUi(this);
17 this->setConfiguration();
18}
19
20ConfigureDialog::~ConfigureDialog() {
21}
22
23void ConfigureDialog::setConfiguration() {
24}
25
26void ConfigureDialog::applyConfiguration() {
27 ui->generalTab->applyConfiguration();
28 ui->audioTab->applyConfiguration();
29 ui->debugTab->applyConfiguration();
30}
diff --git a/src/citra_qt/configure_dialog.h b/src/citra_qt/configure_dialog.h
new file mode 100644
index 000000000..89020eeb4
--- /dev/null
+++ b/src/citra_qt/configure_dialog.h
@@ -0,0 +1,29 @@
1// Copyright 2016 Citra Emulator Project
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#pragma once
6
7#include <memory>
8#include <QDialog>
9
10namespace Ui {
11class ConfigureDialog;
12}
13
14class ConfigureDialog : public QDialog
15{
16 Q_OBJECT
17
18public:
19 explicit ConfigureDialog(QWidget *parent = nullptr);
20 ~ConfigureDialog();
21
22 void applyConfiguration();
23
24private:
25 void setConfiguration();
26
27private:
28 std::unique_ptr<Ui::ConfigureDialog> ui;
29};
diff --git a/src/citra_qt/configure_general.cpp b/src/citra_qt/configure_general.cpp
new file mode 100644
index 000000000..62648e665
--- /dev/null
+++ b/src/citra_qt/configure_general.cpp
@@ -0,0 +1,39 @@
1// Copyright 2016 Citra Emulator Project
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#include "citra_qt/configure_general.h"
6#include "citra_qt/ui_settings.h"
7#include "ui_configure_general.h"
8
9#include "core/settings.h"
10
11ConfigureGeneral::ConfigureGeneral(QWidget *parent) :
12 QWidget(parent),
13 ui(new Ui::ConfigureGeneral)
14{
15 ui->setupUi(this);
16 this->setConfiguration();
17}
18
19ConfigureGeneral::~ConfigureGeneral() {
20}
21
22void ConfigureGeneral::setConfiguration() {
23 ui->toogle_deepscan->setChecked(UISettings::values.gamedir_deepscan);
24 ui->toogle_check_exit->setChecked(UISettings::values.confirm_before_closing);
25 ui->region_combobox->setCurrentIndex(Settings::values.region_value);
26 ui->toogle_hw_renderer->setChecked(Settings::values.use_hw_renderer);
27 ui->toogle_shader_jit->setChecked(Settings::values.use_shader_jit);
28 ui->toogle_scaled_resolution->setChecked(Settings::values.use_scaled_resolution);
29}
30
31void ConfigureGeneral::applyConfiguration() {
32 UISettings::values.gamedir_deepscan = ui->toogle_deepscan->isChecked();
33 UISettings::values.confirm_before_closing = ui->toogle_check_exit->isChecked();
34 Settings::values.region_value = ui->region_combobox->currentIndex();
35 Settings::values.use_hw_renderer = ui->toogle_hw_renderer->isChecked();
36 Settings::values.use_shader_jit = ui->toogle_shader_jit->isChecked();
37 Settings::values.use_scaled_resolution = ui->toogle_scaled_resolution->isChecked();
38 Settings::Apply();
39}
diff --git a/src/citra_qt/configure_general.h b/src/citra_qt/configure_general.h
new file mode 100644
index 000000000..a6c68e62d
--- /dev/null
+++ b/src/citra_qt/configure_general.h
@@ -0,0 +1,29 @@
1// Copyright 2016 Citra Emulator Project
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#pragma once
6
7#include <memory>
8#include <QWidget>
9
10namespace Ui {
11class ConfigureGeneral;
12}
13
14class ConfigureGeneral : public QWidget
15{
16 Q_OBJECT
17
18public:
19 explicit ConfigureGeneral(QWidget *parent = nullptr);
20 ~ConfigureGeneral();
21
22 void applyConfiguration();
23
24private:
25 void setConfiguration();
26
27private:
28 std::unique_ptr<Ui::ConfigureGeneral> ui;
29};
diff --git a/src/citra_qt/configure_general.ui b/src/citra_qt/configure_general.ui
new file mode 100644
index 000000000..5eb309793
--- /dev/null
+++ b/src/citra_qt/configure_general.ui
@@ -0,0 +1,173 @@
1<?xml version="1.0" encoding="UTF-8"?>
2<ui version="4.0">
3 <class>ConfigureGeneral</class>
4 <widget class="QWidget" name="ConfigureGeneral">
5 <property name="geometry">
6 <rect>
7 <x>0</x>
8 <y>0</y>
9 <width>300</width>
10 <height>377</height>
11 </rect>
12 </property>
13 <property name="windowTitle">
14 <string>Form</string>
15 </property>
16 <layout class="QHBoxLayout" name="horizontalLayout">
17 <item>
18 <layout class="QVBoxLayout" name="verticalLayout">
19 <item>
20 <widget class="QGroupBox" name="groupBox">
21 <property name="title">
22 <string>General</string>
23 </property>
24 <layout class="QHBoxLayout" name="horizontalLayout_3">
25 <item>
26 <layout class="QVBoxLayout" name="verticalLayout_2">
27 <item>
28 <widget class="QCheckBox" name="toogle_deepscan">
29 <property name="text">
30 <string>Recursive scan for game folder</string>
31 </property>
32 </widget>
33 </item>
34 <item>
35 <widget class="QCheckBox" name="toogle_check_exit">
36 <property name="text">
37 <string>Confirm exit while emulation is running</string>
38 </property>
39 </widget>
40 </item>
41 </layout>
42 </item>
43 </layout>
44 </widget>
45 </item>
46 <item>
47 <widget class="QGroupBox" name="groupBox_4">
48 <property name="title">
49 <string>Emulation</string>
50 </property>
51 <layout class="QHBoxLayout" name="horizontalLayout_5">
52 <item>
53 <layout class="QVBoxLayout" name="verticalLayout_6">
54 <item>
55 <layout class="QHBoxLayout" name="horizontalLayout_6">
56 <item>
57 <widget class="QLabel" name="label">
58 <property name="text">
59 <string>Region:</string>
60 </property>
61 </widget>
62 </item>
63 <item>
64 <widget class="QComboBox" name="region_combobox">
65 <item>
66 <property name="text">
67 <string notr="true">JPN</string>
68 </property>
69 </item>
70 <item>
71 <property name="text">
72 <string notr="true">USA</string>
73 </property>
74 </item>
75 <item>
76 <property name="text">
77 <string notr="true">EUR</string>
78 </property>
79 </item>
80 <item>
81 <property name="text">
82 <string notr="true">AUS</string>
83 </property>
84 </item>
85 <item>
86 <property name="text">
87 <string notr="true">CHN</string>
88 </property>
89 </item>
90 <item>
91 <property name="text">
92 <string notr="true">KOR</string>
93 </property>
94 </item>
95 <item>
96 <property name="text">
97 <string notr="true">TWN</string>
98 </property>
99 </item>
100 </widget>
101 </item>
102 </layout>
103 </item>
104 </layout>
105 </item>
106 </layout>
107 </widget>
108 </item>
109 <item>
110 <widget class="QGroupBox" name="groupBox_2">
111 <property name="title">
112 <string>Performance</string>
113 </property>
114 <layout class="QHBoxLayout" name="horizontalLayout_2">
115 <item>
116 <layout class="QVBoxLayout" name="verticalLayout_3">
117 <item>
118 <widget class="QCheckBox" name="toogle_hw_renderer">
119 <property name="text">
120 <string>Enable hardware renderer</string>
121 </property>
122 </widget>
123 </item>
124 <item>
125 <widget class="QCheckBox" name="toogle_shader_jit">
126 <property name="text">
127 <string>Enable shader JIT</string>
128 </property>
129 </widget>
130 </item>
131 <item>
132 <widget class="QCheckBox" name="toogle_scaled_resolution">
133 <property name="text">
134 <string>Enable scaled resolution</string>
135 </property>
136 </widget>
137 </item>
138 </layout>
139 </item>
140 </layout>
141 </widget>
142 </item>
143 <item>
144 <widget class="QGroupBox" name="groupBox_3">
145 <property name="title">
146 <string>Hotkeys</string>
147 </property>
148 <layout class="QHBoxLayout" name="horizontalLayout_4">
149 <item>
150 <layout class="QVBoxLayout" name="verticalLayout_4">
151 <item>
152 <widget class="GHotkeysDialog" name="widget" native="true"/>
153 </item>
154 </layout>
155 </item>
156 </layout>
157 </widget>
158 </item>
159 </layout>
160 </item>
161 </layout>
162 </widget>
163 <customwidgets>
164 <customwidget>
165 <class>GHotkeysDialog</class>
166 <extends>QWidget</extends>
167 <header>hotkeys.h</header>
168 <container>1</container>
169 </customwidget>
170 </customwidgets>
171 <resources/>
172 <connections/>
173</ui>
diff --git a/src/citra_qt/debugger/graphics_breakpoints.cpp b/src/citra_qt/debugger/graphics_breakpoints.cpp
index 819ec7707..fe66918a8 100644
--- a/src/citra_qt/debugger/graphics_breakpoints.cpp
+++ b/src/citra_qt/debugger/graphics_breakpoints.cpp
@@ -44,7 +44,7 @@ QVariant BreakPointModel::data(const QModelIndex& index, int role) const
44 { Pica::DebugContext::Event::PicaCommandProcessed, tr("Pica command processed") }, 44 { Pica::DebugContext::Event::PicaCommandProcessed, tr("Pica command processed") },
45 { Pica::DebugContext::Event::IncomingPrimitiveBatch, tr("Incoming primitive batch") }, 45 { Pica::DebugContext::Event::IncomingPrimitiveBatch, tr("Incoming primitive batch") },
46 { Pica::DebugContext::Event::FinishedPrimitiveBatch, tr("Finished primitive batch") }, 46 { Pica::DebugContext::Event::FinishedPrimitiveBatch, tr("Finished primitive batch") },
47 { Pica::DebugContext::Event::VertexLoaded, tr("Vertex loaded") }, 47 { Pica::DebugContext::Event::VertexShaderInvocation, tr("Vertex shader invocation") },
48 { Pica::DebugContext::Event::IncomingDisplayTransfer, tr("Incoming display transfer") }, 48 { Pica::DebugContext::Event::IncomingDisplayTransfer, tr("Incoming display transfer") },
49 { Pica::DebugContext::Event::GSPCommandProcessed, tr("GSP command processed") }, 49 { Pica::DebugContext::Event::GSPCommandProcessed, tr("GSP command processed") },
50 { Pica::DebugContext::Event::BufferSwapped, tr("Buffers swapped") } 50 { Pica::DebugContext::Event::BufferSwapped, tr("Buffers swapped") }
@@ -75,7 +75,7 @@ QVariant BreakPointModel::data(const QModelIndex& index, int role) const
75 case Role_IsEnabled: 75 case Role_IsEnabled:
76 { 76 {
77 auto context = context_weak.lock(); 77 auto context = context_weak.lock();
78 return context && context->breakpoints[event].enabled; 78 return context && context->breakpoints[(int)event].enabled;
79 } 79 }
80 80
81 default: 81 default:
@@ -110,7 +110,7 @@ bool BreakPointModel::setData(const QModelIndex& index, const QVariant& value, i
110 if (!context) 110 if (!context)
111 return false; 111 return false;
112 112
113 context->breakpoints[event].enabled = value == Qt::Checked; 113 context->breakpoints[(int)event].enabled = value == Qt::Checked;
114 QModelIndex changed_index = createIndex(index.row(), 0); 114 QModelIndex changed_index = createIndex(index.row(), 0);
115 emit dataChanged(changed_index, changed_index); 115 emit dataChanged(changed_index, changed_index);
116 return true; 116 return true;
diff --git a/src/citra_qt/debugger/graphics_framebuffer.cpp b/src/citra_qt/debugger/graphics_framebuffer.cpp
index c30e75933..68cff78b2 100644
--- a/src/citra_qt/debugger/graphics_framebuffer.cpp
+++ b/src/citra_qt/debugger/graphics_framebuffer.cpp
@@ -346,5 +346,11 @@ u32 GraphicsFramebufferWidget::BytesPerPixel(GraphicsFramebufferWidget::Format f
346 case Format::RGBA4: 346 case Format::RGBA4:
347 case Format::D16: 347 case Format::D16:
348 return 2; 348 return 2;
349 default:
350 UNREACHABLE_MSG("GraphicsFramebufferWidget::BytesPerPixel: this "
351 "should not be reached as this function should "
352 "be given a format which is in "
353 "GraphicsFramebufferWidget::Format. Instead got %i",
354 static_cast<int>(format));
349 } 355 }
350} 356}
diff --git a/src/citra_qt/debugger/graphics_tracing.cpp b/src/citra_qt/debugger/graphics_tracing.cpp
index e06498744..9c80f7ec9 100644
--- a/src/citra_qt/debugger/graphics_tracing.cpp
+++ b/src/citra_qt/debugger/graphics_tracing.cpp
@@ -2,6 +2,9 @@
2// Licensed under GPLv2 or any later version 2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included. 3// Refer to the license.txt file included.
4 4
5#include <algorithm>
6#include <array>
7#include <iterator>
5#include <memory> 8#include <memory>
6 9
7#include <boost/range/algorithm/copy.hpp> 10#include <boost/range/algorithm/copy.hpp>
@@ -18,6 +21,7 @@
18 21
19#include "core/hw/gpu.h" 22#include "core/hw/gpu.h"
20#include "core/hw/lcd.h" 23#include "core/hw/lcd.h"
24#include "core/tracer/recorder.h"
21 25
22#include "nihstro/float24.h" 26#include "nihstro/float24.h"
23 27
@@ -70,7 +74,7 @@ void GraphicsTracingWidget::StartRecording() {
70 std::array<u32, 4 * 16> default_attributes; 74 std::array<u32, 4 * 16> default_attributes;
71 for (unsigned i = 0; i < 16; ++i) { 75 for (unsigned i = 0; i < 16; ++i) {
72 for (unsigned comp = 0; comp < 3; ++comp) { 76 for (unsigned comp = 0; comp < 3; ++comp) {
73 default_attributes[4 * i + comp] = nihstro::to_float24(Pica::g_state.vs.default_attributes[i][comp].ToFloat32()); 77 default_attributes[4 * i + comp] = nihstro::to_float24(Pica::g_state.vs_default_attributes[i][comp].ToFloat32());
74 } 78 }
75 } 79 }
76 80
diff --git a/src/citra_qt/debugger/graphics_vertex_shader.cpp b/src/citra_qt/debugger/graphics_vertex_shader.cpp
index d648d4640..391666d35 100644
--- a/src/citra_qt/debugger/graphics_vertex_shader.cpp
+++ b/src/citra_qt/debugger/graphics_vertex_shader.cpp
@@ -365,7 +365,7 @@ GraphicsVertexShaderWidget::GraphicsVertexShaderWidget(std::shared_ptr< Pica::De
365 input_data[i]->setValidator(new QDoubleValidator(input_data[i])); 365 input_data[i]->setValidator(new QDoubleValidator(input_data[i]));
366 } 366 }
367 367
368 breakpoint_warning = new QLabel(tr("(data only available at VertexLoaded breakpoints)")); 368 breakpoint_warning = new QLabel(tr("(data only available at vertex shader invocation breakpoints)"));
369 369
370 // TODO: Add some button for jumping to the shader entry point 370 // TODO: Add some button for jumping to the shader entry point
371 371
@@ -454,7 +454,7 @@ GraphicsVertexShaderWidget::GraphicsVertexShaderWidget(std::shared_ptr< Pica::De
454 454
455void GraphicsVertexShaderWidget::OnBreakPointHit(Pica::DebugContext::Event event, void* data) { 455void GraphicsVertexShaderWidget::OnBreakPointHit(Pica::DebugContext::Event event, void* data) {
456 auto input = static_cast<Pica::Shader::InputVertex*>(data); 456 auto input = static_cast<Pica::Shader::InputVertex*>(data);
457 if (event == Pica::DebugContext::Event::VertexLoaded) { 457 if (event == Pica::DebugContext::Event::VertexShaderInvocation) {
458 Reload(true, data); 458 Reload(true, data);
459 } else { 459 } else {
460 // No vertex data is retrievable => invalidate currently stored vertex data 460 // No vertex data is retrievable => invalidate currently stored vertex data
@@ -501,7 +501,7 @@ void GraphicsVertexShaderWidget::Reload(bool replace_vertex_data, void* vertex_d
501 info.labels.insert({ entry_point, "main" }); 501 info.labels.insert({ entry_point, "main" });
502 502
503 // Generate debug information 503 // Generate debug information
504 debug_data = Pica::Shader::ProduceDebugInfo(input_vertex, num_attributes, shader_config, shader_setup); 504 debug_data = Pica::g_state.vs.ProduceDebugInfo(input_vertex, num_attributes, shader_config, shader_setup);
505 505
506 // Reload widget state 506 // Reload widget state
507 for (int attr = 0; attr < num_attributes; ++attr) { 507 for (int attr = 0; attr < num_attributes; ++attr) {
@@ -515,7 +515,7 @@ void GraphicsVertexShaderWidget::Reload(bool replace_vertex_data, void* vertex_d
515 } 515 }
516 516
517 // Initialize debug info text for current cycle count 517 // Initialize debug info text for current cycle count
518 cycle_index->setMaximum(debug_data.records.size() - 1); 518 cycle_index->setMaximum(static_cast<int>(debug_data.records.size() - 1));
519 OnCycleIndexChanged(cycle_index->value()); 519 OnCycleIndexChanged(cycle_index->value());
520 520
521 model->endResetModel(); 521 model->endResetModel();
diff --git a/src/citra_qt/debugger/profiler.cpp b/src/citra_qt/debugger/profiler.cpp
index 4f6ba0e1f..585ac049a 100644
--- a/src/citra_qt/debugger/profiler.cpp
+++ b/src/citra_qt/debugger/profiler.cpp
@@ -9,13 +9,16 @@
9#include "citra_qt/debugger/profiler.h" 9#include "citra_qt/debugger/profiler.h"
10#include "citra_qt/util/util.h" 10#include "citra_qt/util/util.h"
11 11
12#include "common/common_types.h"
12#include "common/microprofile.h" 13#include "common/microprofile.h"
13#include "common/profiler_reporting.h" 14#include "common/profiler_reporting.h"
14 15
15// Include the implementation of the UI in this file. This isn't in microprofile.cpp because the 16// Include the implementation of the UI in this file. This isn't in microprofile.cpp because the
16// non-Qt frontends don't need it (and don't implement the UI drawing hooks either). 17// non-Qt frontends don't need it (and don't implement the UI drawing hooks either).
18#if MICROPROFILE_ENABLED
17#define MICROPROFILEUI_IMPL 1 19#define MICROPROFILEUI_IMPL 1
18#include "common/microprofileui.h" 20#include "common/microprofileui.h"
21#endif
19 22
20using namespace Common::Profiling; 23using namespace Common::Profiling;
21 24
@@ -34,21 +37,9 @@ static QVariant GetDataForColumn(int col, const AggregatedDuration& duration)
34 } 37 }
35} 38}
36 39
37static const TimingCategoryInfo* GetCategoryInfo(int id)
38{
39 const auto& categories = GetProfilingManager().GetTimingCategoriesInfo();
40 if ((size_t)id >= categories.size()) {
41 return nullptr;
42 } else {
43 return &categories[id];
44 }
45}
46
47ProfilerModel::ProfilerModel(QObject* parent) : QAbstractItemModel(parent) 40ProfilerModel::ProfilerModel(QObject* parent) : QAbstractItemModel(parent)
48{ 41{
49 updateProfilingInfo(); 42 updateProfilingInfo();
50 const auto& categories = GetProfilingManager().GetTimingCategoriesInfo();
51 results.time_per_category.resize(categories.size());
52} 43}
53 44
54QVariant ProfilerModel::headerData(int section, Qt::Orientation orientation, int role) const 45QVariant ProfilerModel::headerData(int section, Qt::Orientation orientation, int role) const
@@ -85,7 +76,7 @@ int ProfilerModel::rowCount(const QModelIndex& parent) const
85 if (parent.isValid()) { 76 if (parent.isValid()) {
86 return 0; 77 return 0;
87 } else { 78 } else {
88 return static_cast<int>(results.time_per_category.size() + 2); 79 return 2;
89 } 80 }
90} 81}
91 82
@@ -104,17 +95,6 @@ QVariant ProfilerModel::data(const QModelIndex& index, int role) const
104 } else { 95 } else {
105 return GetDataForColumn(index.column(), results.interframe_time); 96 return GetDataForColumn(index.column(), results.interframe_time);
106 } 97 }
107 } else {
108 if (index.column() == 0) {
109 const TimingCategoryInfo* info = GetCategoryInfo(index.row() - 2);
110 return info != nullptr ? QString(info->name) : QVariant();
111 } else {
112 if (index.row() - 2 < (int)results.time_per_category.size()) {
113 return GetDataForColumn(index.column(), results.time_per_category[index.row() - 2]);
114 } else {
115 return QVariant();
116 }
117 }
118 } 98 }
119 } 99 }
120 100
@@ -148,6 +128,8 @@ void ProfilerWidget::setProfilingInfoUpdateEnabled(bool enable)
148 } 128 }
149} 129}
150 130
131#if MICROPROFILE_ENABLED
132
151class MicroProfileWidget : public QWidget { 133class MicroProfileWidget : public QWidget {
152public: 134public:
153 MicroProfileWidget(QWidget* parent = nullptr); 135 MicroProfileWidget(QWidget* parent = nullptr);
@@ -169,8 +151,12 @@ private:
169 /// This timer is used to redraw the widget's contents continuously. To save resources, it only 151 /// This timer is used to redraw the widget's contents continuously. To save resources, it only
170 /// runs while the widget is visible. 152 /// runs while the widget is visible.
171 QTimer update_timer; 153 QTimer update_timer;
154 /// Scale the coordinate system appropriately when physical DPI != logical DPI.
155 qreal x_scale, y_scale;
172}; 156};
173 157
158#endif
159
174MicroProfileDialog::MicroProfileDialog(QWidget* parent) 160MicroProfileDialog::MicroProfileDialog(QWidget* parent)
175 : QWidget(parent, Qt::Dialog) 161 : QWidget(parent, Qt::Dialog)
176{ 162{
@@ -180,6 +166,8 @@ MicroProfileDialog::MicroProfileDialog(QWidget* parent)
180 // Remove the "?" button from the titlebar and enable the maximize button 166 // Remove the "?" button from the titlebar and enable the maximize button
181 setWindowFlags(windowFlags() & ~Qt::WindowContextHelpButtonHint | Qt::WindowMaximizeButtonHint); 167 setWindowFlags(windowFlags() & ~Qt::WindowContextHelpButtonHint | Qt::WindowMaximizeButtonHint);
182 168
169#if MICROPROFILE_ENABLED
170
183 MicroProfileWidget* widget = new MicroProfileWidget(this); 171 MicroProfileWidget* widget = new MicroProfileWidget(this);
184 172
185 QLayout* layout = new QVBoxLayout(this); 173 QLayout* layout = new QVBoxLayout(this);
@@ -191,6 +179,7 @@ MicroProfileDialog::MicroProfileDialog(QWidget* parent)
191 setFocusProxy(widget); 179 setFocusProxy(widget);
192 widget->setFocusPolicy(Qt::StrongFocus); 180 widget->setFocusPolicy(Qt::StrongFocus);
193 widget->setFocus(); 181 widget->setFocus();
182#endif
194} 183}
195 184
196QAction* MicroProfileDialog::toggleViewAction() { 185QAction* MicroProfileDialog::toggleViewAction() {
@@ -218,6 +207,9 @@ void MicroProfileDialog::hideEvent(QHideEvent* ev) {
218 QWidget::hideEvent(ev); 207 QWidget::hideEvent(ev);
219} 208}
220 209
210
211#if MICROPROFILE_ENABLED
212
221/// There's no way to pass a user pointer to MicroProfile, so this variable is used to make the 213/// There's no way to pass a user pointer to MicroProfile, so this variable is used to make the
222/// QPainter available inside the drawing callbacks. 214/// QPainter available inside the drawing callbacks.
223static QPainter* mp_painter = nullptr; 215static QPainter* mp_painter = nullptr;
@@ -230,11 +222,17 @@ MicroProfileWidget::MicroProfileWidget(QWidget* parent) : QWidget(parent) {
230 MicroProfileInitUI(); 222 MicroProfileInitUI();
231 223
232 connect(&update_timer, SIGNAL(timeout()), SLOT(update())); 224 connect(&update_timer, SIGNAL(timeout()), SLOT(update()));
225
226 QPainter painter(this);
227 x_scale = qreal(painter.device()->physicalDpiX()) / qreal(painter.device()->logicalDpiX());
228 y_scale = qreal(painter.device()->physicalDpiY()) / qreal(painter.device()->logicalDpiY());
233} 229}
234 230
235void MicroProfileWidget::paintEvent(QPaintEvent* ev) { 231void MicroProfileWidget::paintEvent(QPaintEvent* ev) {
236 QPainter painter(this); 232 QPainter painter(this);
237 233
234 painter.scale(x_scale, y_scale);
235
238 painter.setBackground(Qt::black); 236 painter.setBackground(Qt::black);
239 painter.eraseRect(rect()); 237 painter.eraseRect(rect());
240 238
@@ -258,24 +256,24 @@ void MicroProfileWidget::hideEvent(QHideEvent* ev) {
258} 256}
259 257
260void MicroProfileWidget::mouseMoveEvent(QMouseEvent* ev) { 258void MicroProfileWidget::mouseMoveEvent(QMouseEvent* ev) {
261 MicroProfileMousePosition(ev->x(), ev->y(), 0); 259 MicroProfileMousePosition(ev->x() / x_scale, ev->y() / y_scale, 0);
262 ev->accept(); 260 ev->accept();
263} 261}
264 262
265void MicroProfileWidget::mousePressEvent(QMouseEvent* ev) { 263void MicroProfileWidget::mousePressEvent(QMouseEvent* ev) {
266 MicroProfileMousePosition(ev->x(), ev->y(), 0); 264 MicroProfileMousePosition(ev->x() / x_scale, ev->y() / y_scale, 0);
267 MicroProfileMouseButton(ev->buttons() & Qt::LeftButton, ev->buttons() & Qt::RightButton); 265 MicroProfileMouseButton(ev->buttons() & Qt::LeftButton, ev->buttons() & Qt::RightButton);
268 ev->accept(); 266 ev->accept();
269} 267}
270 268
271void MicroProfileWidget::mouseReleaseEvent(QMouseEvent* ev) { 269void MicroProfileWidget::mouseReleaseEvent(QMouseEvent* ev) {
272 MicroProfileMousePosition(ev->x(), ev->y(), 0); 270 MicroProfileMousePosition(ev->x() / x_scale, ev->y() / y_scale, 0);
273 MicroProfileMouseButton(ev->buttons() & Qt::LeftButton, ev->buttons() & Qt::RightButton); 271 MicroProfileMouseButton(ev->buttons() & Qt::LeftButton, ev->buttons() & Qt::RightButton);
274 ev->accept(); 272 ev->accept();
275} 273}
276 274
277void MicroProfileWidget::wheelEvent(QWheelEvent* ev) { 275void MicroProfileWidget::wheelEvent(QWheelEvent* ev) {
278 MicroProfileMousePosition(ev->x(), ev->y(), ev->delta() / 120); 276 MicroProfileMousePosition(ev->x() / x_scale, ev->y() / y_scale, ev->delta() / 120);
279 ev->accept(); 277 ev->accept();
280} 278}
281 279
@@ -337,3 +335,4 @@ void MicroProfileDrawLine2D(u32 vertices_length, float* vertices, u32 hex_color)
337 mp_painter->drawPolyline(point_buf.data(), vertices_length); 335 mp_painter->drawPolyline(point_buf.data(), vertices_length);
338 point_buf.clear(); 336 point_buf.clear();
339} 337}
338#endif
diff --git a/src/citra_qt/debugger/profiler.h b/src/citra_qt/debugger/profiler.h
index 036054740..3b38ed8ec 100644
--- a/src/citra_qt/debugger/profiler.h
+++ b/src/citra_qt/debugger/profiler.h
@@ -7,8 +7,10 @@
7#include <QAbstractItemModel> 7#include <QAbstractItemModel>
8#include <QDockWidget> 8#include <QDockWidget>
9#include <QTimer> 9#include <QTimer>
10
10#include "ui_profiler.h" 11#include "ui_profiler.h"
11 12
13#include "common/microprofile.h"
12#include "common/profiler_reporting.h" 14#include "common/profiler_reporting.h"
13 15
14class ProfilerModel : public QAbstractItemModel 16class ProfilerModel : public QAbstractItemModel
@@ -49,6 +51,7 @@ private:
49 QTimer update_timer; 51 QTimer update_timer;
50}; 52};
51 53
54
52class MicroProfileDialog : public QWidget { 55class MicroProfileDialog : public QWidget {
53 Q_OBJECT 56 Q_OBJECT
54 57
diff --git a/src/citra_qt/game_list.cpp b/src/citra_qt/game_list.cpp
index ffcab1f03..d4ac9c96e 100644
--- a/src/citra_qt/game_list.cpp
+++ b/src/citra_qt/game_list.cpp
@@ -8,6 +8,7 @@
8 8
9#include "game_list.h" 9#include "game_list.h"
10#include "game_list_p.h" 10#include "game_list_p.h"
11#include "ui_settings.h"
11 12
12#include "core/loader/loader.h" 13#include "core/loader/loader.h"
13 14
@@ -33,8 +34,8 @@ GameList::GameList(QWidget* parent)
33 tree_view->setUniformRowHeights(true); 34 tree_view->setUniformRowHeights(true);
34 35
35 item_model->insertColumns(0, COLUMN_COUNT); 36 item_model->insertColumns(0, COLUMN_COUNT);
36 item_model->setHeaderData(COLUMN_FILE_TYPE, Qt::Horizontal, "File type");
37 item_model->setHeaderData(COLUMN_NAME, Qt::Horizontal, "Name"); 37 item_model->setHeaderData(COLUMN_NAME, Qt::Horizontal, "Name");
38 item_model->setHeaderData(COLUMN_FILE_TYPE, Qt::Horizontal, "File type");
38 item_model->setHeaderData(COLUMN_SIZE, Qt::Horizontal, "Size"); 39 item_model->setHeaderData(COLUMN_SIZE, Qt::Horizontal, "Size");
39 40
40 connect(tree_view, SIGNAL(activated(const QModelIndex&)), this, SLOT(ValidateEntry(const QModelIndex&))); 41 connect(tree_view, SIGNAL(activated(const QModelIndex&)), this, SLOT(ValidateEntry(const QModelIndex&)));
@@ -100,19 +101,19 @@ void GameList::PopulateAsync(const QString& dir_path, bool deep_scan)
100 current_worker = std::move(worker); 101 current_worker = std::move(worker);
101} 102}
102 103
103void GameList::SaveInterfaceLayout(QSettings& settings) 104void GameList::SaveInterfaceLayout()
104{ 105{
105 settings.beginGroup("UILayout"); 106 UISettings::values.gamelist_header_state = tree_view->header()->saveState();
106 settings.setValue("gameListHeaderState", tree_view->header()->saveState());
107 settings.endGroup();
108} 107}
109 108
110void GameList::LoadInterfaceLayout(QSettings& settings) 109void GameList::LoadInterfaceLayout()
111{ 110{
112 auto header = tree_view->header(); 111 auto header = tree_view->header();
113 settings.beginGroup("UILayout"); 112 if (!header->restoreState(UISettings::values.gamelist_header_state)) {
114 header->restoreState(settings.value("gameListHeaderState").toByteArray()); 113 // We are using the name column to display icons and titles
115 settings.endGroup(); 114 // so make it as large as possible as default.
115 header->resizeSection(COLUMN_NAME, header->width());
116 }
116 117
117 item_model->sort(header->sortIndicatorSection(), header->sortIndicatorOrder()); 118 item_model->sort(header->sortIndicatorSection(), header->sortIndicatorOrder());
118} 119}
@@ -146,9 +147,15 @@ void GameListWorker::AddFstEntriesToGameList(const std::string& dir_path, bool d
146 LOG_WARNING(Frontend, "Filetype and extension of file %s do not match.", physical_name.c_str()); 147 LOG_WARNING(Frontend, "Filetype and extension of file %s do not match.", physical_name.c_str());
147 } 148 }
148 149
150 std::vector<u8> smdh;
151 std::unique_ptr<Loader::AppLoader> loader = Loader::GetLoader(FileUtil::IOFile(physical_name, "rb"), filetype, filename_filename, physical_name);
152
153 if (loader)
154 loader->ReadIcon(smdh);
155
149 emit EntryReady({ 156 emit EntryReady({
157 new GameListItemPath(QString::fromStdString(physical_name), smdh),
150 new GameListItem(QString::fromStdString(Loader::GetFileTypeString(filetype))), 158 new GameListItem(QString::fromStdString(Loader::GetFileTypeString(filetype))),
151 new GameListItemPath(QString::fromStdString(physical_name)),
152 new GameListItemSize(FileUtil::GetSize(physical_name)), 159 new GameListItemSize(FileUtil::GetSize(physical_name)),
153 }); 160 });
154 } 161 }
diff --git a/src/citra_qt/game_list.h b/src/citra_qt/game_list.h
index 0950d9622..198674f04 100644
--- a/src/citra_qt/game_list.h
+++ b/src/citra_qt/game_list.h
@@ -20,8 +20,8 @@ class GameList : public QWidget {
20 20
21public: 21public:
22 enum { 22 enum {
23 COLUMN_FILE_TYPE,
24 COLUMN_NAME, 23 COLUMN_NAME,
24 COLUMN_FILE_TYPE,
25 COLUMN_SIZE, 25 COLUMN_SIZE,
26 COLUMN_COUNT, // Number of columns 26 COLUMN_COUNT, // Number of columns
27 }; 27 };
@@ -31,8 +31,8 @@ public:
31 31
32 void PopulateAsync(const QString& dir_path, bool deep_scan); 32 void PopulateAsync(const QString& dir_path, bool deep_scan);
33 33
34 void SaveInterfaceLayout(QSettings& settings); 34 void SaveInterfaceLayout();
35 void LoadInterfaceLayout(QSettings& settings); 35 void LoadInterfaceLayout();
36 36
37public slots: 37public slots:
38 void AddEntry(QList<QStandardItem*> entry_items); 38 void AddEntry(QList<QStandardItem*> entry_items);
diff --git a/src/citra_qt/game_list_p.h b/src/citra_qt/game_list_p.h
index 820012bce..284f5da81 100644
--- a/src/citra_qt/game_list_p.h
+++ b/src/citra_qt/game_list_p.h
@@ -6,13 +6,85 @@
6 6
7#include <atomic> 7#include <atomic>
8 8
9#include <QImage>
9#include <QRunnable> 10#include <QRunnable>
10#include <QStandardItem> 11#include <QStandardItem>
11#include <QString> 12#include <QString>
12 13
13#include "citra_qt/util/util.h" 14#include "citra_qt/util/util.h"
14#include "common/string_util.h" 15#include "common/string_util.h"
16#include "common/color.h"
15 17
18#include "core/loader/loader.h"
19
20#include "video_core/utils.h"
21
22/**
23 * Tests if data is a valid SMDH by its length and magic number.
24 * @param smdh_data data buffer to test
25 * @return bool test result
26 */
27static bool IsValidSMDH(const std::vector<u8>& smdh_data) {
28 if (smdh_data.size() < sizeof(Loader::SMDH))
29 return false;
30
31 u32 magic;
32 memcpy(&magic, smdh_data.data(), 4);
33
34 return Loader::MakeMagic('S', 'M', 'D', 'H') == magic;
35}
36
37/**
38 * Gets game icon from SMDH
39 * @param sdmh SMDH data
40 * @param large If true, returns large icon (48x48), otherwise returns small icon (24x24)
41 * @return QPixmap game icon
42 */
43static QPixmap GetIconFromSMDH(const Loader::SMDH& smdh, bool large) {
44 u32 size;
45 const u8* icon_data;
46
47 if (large) {
48 size = 48;
49 icon_data = smdh.large_icon.data();
50 } else {
51 size = 24;
52 icon_data = smdh.small_icon.data();
53 }
54
55 QImage icon(size, size, QImage::Format::Format_RGB888);
56 for (u32 x = 0; x < size; ++x) {
57 for (u32 y = 0; y < size; ++y) {
58 u32 coarse_y = y & ~7;
59 auto v = Color::DecodeRGB565(
60 icon_data + VideoCore::GetMortonOffset(x, y, 2) + coarse_y * size * 2);
61 icon.setPixel(x, y, qRgb(v.r(), v.g(), v.b()));
62 }
63 }
64 return QPixmap::fromImage(icon);
65}
66
67/**
68 * Gets the default icon (for games without valid SMDH)
69 * @param large If true, returns large icon (48x48), otherwise returns small icon (24x24)
70 * @return QPixmap default icon
71 */
72static QPixmap GetDefaultIcon(bool large) {
73 int size = large ? 48 : 24;
74 QPixmap icon(size, size);
75 icon.fill(Qt::transparent);
76 return icon;
77}
78
79/**
80 * Gets the short game title fromn SMDH
81 * @param sdmh SMDH data
82 * @param language title language
83 * @return QString short title
84 */
85static QString GetShortTitleFromSMDH(const Loader::SMDH& smdh, Loader::SMDH::TitleLanguage language) {
86 return QString::fromUtf16(smdh.titles[static_cast<int>(language)].short_title.data());
87}
16 88
17class GameListItem : public QStandardItem { 89class GameListItem : public QStandardItem {
18 90
@@ -27,29 +99,43 @@ public:
27 * A specialization of GameListItem for path values. 99 * A specialization of GameListItem for path values.
28 * This class ensures that for every full path value it holds, a correct string representation 100 * This class ensures that for every full path value it holds, a correct string representation
29 * of just the filename (with no extension) will be displayed to the user. 101 * of just the filename (with no extension) will be displayed to the user.
102 * If this class recieves valid SMDH data, it will also display game icons and titles.
30 */ 103 */
31class GameListItemPath : public GameListItem { 104class GameListItemPath : public GameListItem {
32 105
33public: 106public:
34 static const int FullPathRole = Qt::UserRole + 1; 107 static const int FullPathRole = Qt::UserRole + 1;
108 static const int TitleRole = Qt::UserRole + 2;
35 109
36 GameListItemPath(): GameListItem() {} 110 GameListItemPath(): GameListItem() {}
37 GameListItemPath(const QString& game_path): GameListItem() 111 GameListItemPath(const QString& game_path, const std::vector<u8>& smdh_data): GameListItem()
38 { 112 {
39 setData(game_path, FullPathRole); 113 setData(game_path, FullPathRole);
114
115 if (!IsValidSMDH(smdh_data)) {
116 // SMDH is not valid, set a default icon
117 setData(GetDefaultIcon(true), Qt::DecorationRole);
118 return;
119 }
120
121 Loader::SMDH smdh;
122 memcpy(&smdh, smdh_data.data(), sizeof(Loader::SMDH));
123
124 // Get icon from SMDH
125 setData(GetIconFromSMDH(smdh, true), Qt::DecorationRole);
126
127 // Get title form SMDH
128 setData(GetShortTitleFromSMDH(smdh, Loader::SMDH::TitleLanguage::English), TitleRole);
40 } 129 }
41 130
42 void setData(const QVariant& value, int role) override 131 QVariant data(int role) const override {
43 { 132 if (role == Qt::DisplayRole) {
44 // By specializing setData for FullPathRole, we can ensure that the two string
45 // representations of the data are always accurate and in the correct format.
46 if (role == FullPathRole) {
47 std::string filename; 133 std::string filename;
48 Common::SplitPath(value.toString().toStdString(), nullptr, &filename, nullptr); 134 Common::SplitPath(data(FullPathRole).toString().toStdString(), nullptr, &filename, nullptr);
49 GameListItem::setData(QString::fromStdString(filename), Qt::DisplayRole); 135 QString title = data(TitleRole).toString();
50 GameListItem::setData(value, FullPathRole); 136 return QString::fromStdString(filename) + (title.isEmpty() ? "" : "\n " + title);
51 } else { 137 } else {
52 GameListItem::setData(value, role); 138 return GameListItem::data(role);
53 } 139 }
54 } 140 }
55}; 141};
diff --git a/src/citra_qt/hotkeys.cpp b/src/citra_qt/hotkeys.cpp
index ed6b12fc4..41f95c63d 100644
--- a/src/citra_qt/hotkeys.cpp
+++ b/src/citra_qt/hotkeys.cpp
@@ -4,11 +4,12 @@
4 4
5#include <map> 5#include <map>
6 6
7#include <QtGlobal>
7#include <QKeySequence> 8#include <QKeySequence>
8#include <QSettings>
9#include <QShortcut> 9#include <QShortcut>
10 10
11#include "citra_qt/hotkeys.h" 11#include "citra_qt/hotkeys.h"
12#include "citra_qt/ui_settings.h"
12 13
13struct Hotkey 14struct Hotkey
14{ 15{
@@ -24,54 +25,39 @@ typedef std::map<QString, HotkeyMap> HotkeyGroupMap;
24 25
25HotkeyGroupMap hotkey_groups; 26HotkeyGroupMap hotkey_groups;
26 27
27void SaveHotkeys(QSettings& settings) 28void SaveHotkeys()
28{ 29{
29 settings.beginGroup("Shortcuts"); 30 UISettings::values.shortcuts.clear();
30
31 for (auto group : hotkey_groups) 31 for (auto group : hotkey_groups)
32 { 32 {
33 settings.beginGroup(group.first);
34 for (auto hotkey : group.second) 33 for (auto hotkey : group.second)
35 { 34 {
36 settings.beginGroup(hotkey.first); 35 UISettings::values.shortcuts.emplace_back(
37 settings.setValue(QString("KeySeq"), hotkey.second.keyseq.toString()); 36 UISettings::Shortcut(group.first + "/" + hotkey.first,
38 settings.setValue(QString("Context"), hotkey.second.context); 37 UISettings::ContextualShortcut(hotkey.second.keyseq.toString(),
39 settings.endGroup(); 38 hotkey.second.context)));
40 } 39 }
41 settings.endGroup();
42 } 40 }
43 settings.endGroup();
44} 41}
45 42
46void LoadHotkeys(QSettings& settings) 43void LoadHotkeys()
47{ 44{
48 settings.beginGroup("Shortcuts");
49
50 // Make sure NOT to use a reference here because it would become invalid once we call beginGroup() 45 // Make sure NOT to use a reference here because it would become invalid once we call beginGroup()
51 QStringList groups = settings.childGroups(); 46 for (auto shortcut : UISettings::values.shortcuts)
52 for (auto group : groups)
53 { 47 {
54 settings.beginGroup(group); 48 QStringList cat = shortcut.first.split("/");
49 Q_ASSERT(cat.size() >= 2);
55 50
56 QStringList hotkeys = settings.childGroups(); 51 // RegisterHotkey assigns default keybindings, so use old values as default parameters
57 for (auto hotkey : hotkeys) 52 Hotkey& hk = hotkey_groups[cat[0]][cat[1]];
53 if (!shortcut.second.first.isEmpty())
58 { 54 {
59 settings.beginGroup(hotkey); 55 hk.keyseq = QKeySequence::fromString(shortcut.second.first);
60 56 hk.context = (Qt::ShortcutContext)shortcut.second.second;
61 // RegisterHotkey assigns default keybindings, so use old values as default parameters
62 Hotkey& hk = hotkey_groups[group][hotkey];
63 hk.keyseq = QKeySequence::fromString(settings.value("KeySeq", hk.keyseq.toString()).toString());
64 hk.context = (Qt::ShortcutContext)settings.value("Context", hk.context).toInt();
65 if (hk.shortcut)
66 hk.shortcut->setKey(hk.keyseq);
67
68 settings.endGroup();
69 } 57 }
70 58 if (hk.shortcut)
71 settings.endGroup(); 59 hk.shortcut->setKey(hk.keyseq);
72 } 60 }
73
74 settings.endGroup();
75} 61}
76 62
77void RegisterHotkey(const QString& group, const QString& action, const QKeySequence& default_keyseq, Qt::ShortcutContext default_context) 63void RegisterHotkey(const QString& group, const QString& action, const QKeySequence& default_keyseq, Qt::ShortcutContext default_context)
@@ -94,7 +80,7 @@ QShortcut* GetHotkey(const QString& group, const QString& action, QWidget* widge
94} 80}
95 81
96 82
97GHotkeysDialog::GHotkeysDialog(QWidget* parent): QDialog(parent) 83GHotkeysDialog::GHotkeysDialog(QWidget* parent): QWidget(parent)
98{ 84{
99 ui.setupUi(this); 85 ui.setupUi(this);
100 86
diff --git a/src/citra_qt/hotkeys.h b/src/citra_qt/hotkeys.h
index 2fe635882..38aa5f012 100644
--- a/src/citra_qt/hotkeys.h
+++ b/src/citra_qt/hotkeys.h
@@ -2,6 +2,8 @@
2// Licensed under GPLv2 or any later version 2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included. 3// Refer to the license.txt file included.
4 4
5#pragma once
6
5#include "ui_hotkeys.h" 7#include "ui_hotkeys.h"
6 8
7class QDialog; 9class QDialog;
@@ -33,16 +35,16 @@ QShortcut* GetHotkey(const QString& group, const QString& action, QWidget* widge
33 * 35 *
34 * @note Each hotkey group will be stored a settings group; For each hotkey inside that group, a settings group will be created to store the key sequence and the hotkey context. 36 * @note Each hotkey group will be stored a settings group; For each hotkey inside that group, a settings group will be created to store the key sequence and the hotkey context.
35 */ 37 */
36void SaveHotkeys(QSettings& settings); 38void SaveHotkeys();
37 39
38/** 40/**
39 * Loads hotkeys from the settings file. 41 * Loads hotkeys from the settings file.
40 * 42 *
41 * @note Yet unregistered hotkeys which are present in the settings will automatically be registered. 43 * @note Yet unregistered hotkeys which are present in the settings will automatically be registered.
42 */ 44 */
43void LoadHotkeys(QSettings& settings); 45void LoadHotkeys();
44 46
45class GHotkeysDialog : public QDialog 47class GHotkeysDialog : public QWidget
46{ 48{
47 Q_OBJECT 49 Q_OBJECT
48 50
diff --git a/src/citra_qt/hotkeys.ui b/src/citra_qt/hotkeys.ui
index 38a9a14d1..050fe064e 100644
--- a/src/citra_qt/hotkeys.ui
+++ b/src/citra_qt/hotkeys.ui
@@ -1,7 +1,7 @@
1<?xml version="1.0" encoding="UTF-8"?> 1<?xml version="1.0" encoding="UTF-8"?>
2<ui version="4.0"> 2<ui version="4.0">
3 <class>hotkeys</class> 3 <class>hotkeys</class>
4 <widget class="QDialog" name="hotkeys"> 4 <widget class="QWidget" name="hotkeys">
5 <property name="geometry"> 5 <property name="geometry">
6 <rect> 6 <rect>
7 <x>0</x> 7 <x>0</x>
@@ -39,51 +39,8 @@
39 </column> 39 </column>
40 </widget> 40 </widget>
41 </item> 41 </item>
42 <item>
43 <widget class="QDialogButtonBox" name="buttonBox">
44 <property name="orientation">
45 <enum>Qt::Horizontal</enum>
46 </property>
47 <property name="standardButtons">
48 <set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok|QDialogButtonBox::Reset</set>
49 </property>
50 </widget>
51 </item>
52 </layout> 42 </layout>
53 </widget> 43 </widget>
54 <resources/> 44 <resources/>
55 <connections> 45 <connections/>
56 <connection>
57 <sender>buttonBox</sender>
58 <signal>accepted()</signal>
59 <receiver>hotkeys</receiver>
60 <slot>accept()</slot>
61 <hints>
62 <hint type="sourcelabel">
63 <x>248</x>
64 <y>254</y>
65 </hint>
66 <hint type="destinationlabel">
67 <x>157</x>
68 <y>274</y>
69 </hint>
70 </hints>
71 </connection>
72 <connection>
73 <sender>buttonBox</sender>
74 <signal>rejected()</signal>
75 <receiver>hotkeys</receiver>
76 <slot>reject()</slot>
77 <hints>
78 <hint type="sourcelabel">
79 <x>316</x>
80 <y>260</y>
81 </hint>
82 <hint type="destinationlabel">
83 <x>286</x>
84 <y>274</y>
85 </hint>
86 </hints>
87 </connection>
88 </connections>
89</ui> 46</ui>
diff --git a/src/citra_qt/main.cpp b/src/citra_qt/main.cpp
index ca0ae6f7b..a85c94a4b 100644
--- a/src/citra_qt/main.cpp
+++ b/src/citra_qt/main.cpp
@@ -6,6 +6,9 @@
6#include <memory> 6#include <memory>
7#include <thread> 7#include <thread>
8 8
9#include <glad/glad.h>
10
11#define QT_NO_OPENGL
9#include <QDesktopWidget> 12#include <QDesktopWidget>
10#include <QtGui> 13#include <QtGui>
11#include <QFileDialog> 14#include <QFileDialog>
@@ -14,9 +17,11 @@
14 17
15#include "citra_qt/bootmanager.h" 18#include "citra_qt/bootmanager.h"
16#include "citra_qt/config.h" 19#include "citra_qt/config.h"
20#include "citra_qt/configure_dialog.h"
17#include "citra_qt/game_list.h" 21#include "citra_qt/game_list.h"
18#include "citra_qt/hotkeys.h" 22#include "citra_qt/hotkeys.h"
19#include "citra_qt/main.h" 23#include "citra_qt/main.h"
24#include "citra_qt/ui_settings.h"
20 25
21// Debugger 26// Debugger
22#include "citra_qt/debugger/callstack.h" 27#include "citra_qt/debugger/callstack.h"
@@ -50,12 +55,10 @@
50 55
51#include "video_core/video_core.h" 56#include "video_core/video_core.h"
52 57
53GMainWindow::GMainWindow() : emu_thread(nullptr) 58GMainWindow::GMainWindow() : config(new Config()), emu_thread(nullptr)
54{ 59{
55 Pica::g_debug_context = Pica::DebugContext::Construct(); 60 Pica::g_debug_context = Pica::DebugContext::Construct();
56 61
57 Config config;
58
59 ui.setupUi(this); 62 ui.setupUi(this);
60 statusBar()->hide(); 63 statusBar()->hide();
61 64
@@ -69,8 +72,10 @@ GMainWindow::GMainWindow() : emu_thread(nullptr)
69 addDockWidget(Qt::BottomDockWidgetArea, profilerWidget); 72 addDockWidget(Qt::BottomDockWidgetArea, profilerWidget);
70 profilerWidget->hide(); 73 profilerWidget->hide();
71 74
75#if MICROPROFILE_ENABLED
72 microProfileDialog = new MicroProfileDialog(this); 76 microProfileDialog = new MicroProfileDialog(this);
73 microProfileDialog->hide(); 77 microProfileDialog->hide();
78#endif
74 79
75 disasmWidget = new DisassemblerWidget(this, emu_thread.get()); 80 disasmWidget = new DisassemblerWidget(this, emu_thread.get());
76 addDockWidget(Qt::BottomDockWidgetArea, disasmWidget); 81 addDockWidget(Qt::BottomDockWidgetArea, disasmWidget);
@@ -110,7 +115,9 @@ GMainWindow::GMainWindow() : emu_thread(nullptr)
110 115
111 QMenu* debug_menu = ui.menu_View->addMenu(tr("Debugging")); 116 QMenu* debug_menu = ui.menu_View->addMenu(tr("Debugging"));
112 debug_menu->addAction(profilerWidget->toggleViewAction()); 117 debug_menu->addAction(profilerWidget->toggleViewAction());
118#if MICROPROFILE_ENABLED
113 debug_menu->addAction(microProfileDialog->toggleViewAction()); 119 debug_menu->addAction(microProfileDialog->toggleViewAction());
120#endif
114 debug_menu->addAction(disasmWidget->toggleViewAction()); 121 debug_menu->addAction(disasmWidget->toggleViewAction());
115 debug_menu->addAction(registersWidget->toggleViewAction()); 122 debug_menu->addAction(registersWidget->toggleViewAction());
116 debug_menu->addAction(callstackWidget->toggleViewAction()); 123 debug_menu->addAction(callstackWidget->toggleViewAction());
@@ -133,33 +140,20 @@ GMainWindow::GMainWindow() : emu_thread(nullptr)
133 setGeometry(x, y, w, h); 140 setGeometry(x, y, w, h);
134 141
135 // Restore UI state 142 // Restore UI state
136 QSettings settings; 143 restoreGeometry(UISettings::values.geometry);
137 144 restoreState(UISettings::values.state);
138 settings.beginGroup("UILayout"); 145 render_window->restoreGeometry(UISettings::values.renderwindow_geometry);
139 restoreGeometry(settings.value("geometry").toByteArray()); 146#if MICROPROFILE_ENABLED
140 restoreState(settings.value("state").toByteArray()); 147 microProfileDialog->restoreGeometry(UISettings::values.microprofile_geometry);
141 render_window->restoreGeometry(settings.value("geometryRenderWindow").toByteArray()); 148 microProfileDialog->setVisible(UISettings::values.microprofile_visible);
142 microProfileDialog->restoreGeometry(settings.value("microProfileDialogGeometry").toByteArray()); 149#endif
143 microProfileDialog->setVisible(settings.value("microProfileDialogVisible").toBool());
144 settings.endGroup();
145
146 game_list->LoadInterfaceLayout(settings);
147
148 ui.action_Use_Gdbstub->setChecked(Settings::values.use_gdbstub);
149 SetGdbstubEnabled(ui.action_Use_Gdbstub->isChecked());
150
151 GDBStub::SetServerPort(static_cast<u32>(Settings::values.gdbstub_port));
152
153 ui.action_Use_Hardware_Renderer->setChecked(Settings::values.use_hw_renderer);
154 SetHardwareRendererEnabled(ui.action_Use_Hardware_Renderer->isChecked());
155 150
156 ui.action_Use_Shader_JIT->setChecked(Settings::values.use_shader_jit); 151 game_list->LoadInterfaceLayout();
157 SetShaderJITEnabled(ui.action_Use_Shader_JIT->isChecked());
158 152
159 ui.action_Single_Window_Mode->setChecked(settings.value("singleWindowMode", true).toBool()); 153 ui.action_Single_Window_Mode->setChecked(UISettings::values.single_window_mode);
160 ToggleWindowMode(); 154 ToggleWindowMode();
161 155
162 ui.actionDisplay_widget_title_bars->setChecked(settings.value("displayTitleBars", true).toBool()); 156 ui.actionDisplay_widget_title_bars->setChecked(UISettings::values.display_titlebar);
163 OnDisplayTitleBars(ui.actionDisplay_widget_title_bars->isChecked()); 157 OnDisplayTitleBars(ui.actionDisplay_widget_title_bars->isChecked());
164 158
165 // Prepare actions for recent files 159 // Prepare actions for recent files
@@ -172,21 +166,16 @@ GMainWindow::GMainWindow() : emu_thread(nullptr)
172 } 166 }
173 UpdateRecentFiles(); 167 UpdateRecentFiles();
174 168
175 confirm_before_closing = settings.value("confirmClose", true).toBool();
176
177 // Setup connections 169 // Setup connections
178 connect(game_list, SIGNAL(GameChosen(QString)), this, SLOT(OnGameListLoadFile(QString))); 170 connect(game_list, SIGNAL(GameChosen(QString)), this, SLOT(OnGameListLoadFile(QString)), Qt::DirectConnection);
179 connect(ui.action_Load_File, SIGNAL(triggered()), this, SLOT(OnMenuLoadFile())); 171 connect(ui.action_Configure, SIGNAL(triggered()), this, SLOT(OnConfigure()));
172 connect(ui.action_Load_File, SIGNAL(triggered()), this, SLOT(OnMenuLoadFile()),Qt::DirectConnection);
180 connect(ui.action_Load_Symbol_Map, SIGNAL(triggered()), this, SLOT(OnMenuLoadSymbolMap())); 173 connect(ui.action_Load_Symbol_Map, SIGNAL(triggered()), this, SLOT(OnMenuLoadSymbolMap()));
181 connect(ui.action_Select_Game_List_Root, SIGNAL(triggered()), this, SLOT(OnMenuSelectGameListRoot())); 174 connect(ui.action_Select_Game_List_Root, SIGNAL(triggered()), this, SLOT(OnMenuSelectGameListRoot()));
182 connect(ui.action_Start, SIGNAL(triggered()), this, SLOT(OnStartGame())); 175 connect(ui.action_Start, SIGNAL(triggered()), this, SLOT(OnStartGame()));
183 connect(ui.action_Pause, SIGNAL(triggered()), this, SLOT(OnPauseGame())); 176 connect(ui.action_Pause, SIGNAL(triggered()), this, SLOT(OnPauseGame()));
184 connect(ui.action_Stop, SIGNAL(triggered()), this, SLOT(OnStopGame())); 177 connect(ui.action_Stop, SIGNAL(triggered()), this, SLOT(OnStopGame()));
185 connect(ui.action_Use_Hardware_Renderer, SIGNAL(triggered(bool)), this, SLOT(SetHardwareRendererEnabled(bool)));
186 connect(ui.action_Use_Shader_JIT, SIGNAL(triggered(bool)), this, SLOT(SetShaderJITEnabled(bool)));
187 connect(ui.action_Use_Gdbstub, SIGNAL(triggered(bool)), this, SLOT(SetGdbstubEnabled(bool)));
188 connect(ui.action_Single_Window_Mode, SIGNAL(triggered(bool)), this, SLOT(ToggleWindowMode())); 178 connect(ui.action_Single_Window_Mode, SIGNAL(triggered(bool)), this, SLOT(ToggleWindowMode()));
189 connect(ui.action_Hotkeys, SIGNAL(triggered()), this, SLOT(OnOpenHotkeysDialog()));
190 179
191 connect(this, SIGNAL(EmulationStarting(EmuThread*)), disasmWidget, SLOT(OnEmulationStarting(EmuThread*))); 180 connect(this, SIGNAL(EmulationStarting(EmuThread*)), disasmWidget, SLOT(OnEmulationStarting(EmuThread*)));
192 connect(this, SIGNAL(EmulationStopping()), disasmWidget, SLOT(OnEmulationStopping())); 181 connect(this, SIGNAL(EmulationStopping()), disasmWidget, SLOT(OnEmulationStopping()));
@@ -201,7 +190,7 @@ GMainWindow::GMainWindow() : emu_thread(nullptr)
201 // Setup hotkeys 190 // Setup hotkeys
202 RegisterHotkey("Main Window", "Load File", QKeySequence::Open); 191 RegisterHotkey("Main Window", "Load File", QKeySequence::Open);
203 RegisterHotkey("Main Window", "Start Emulation"); 192 RegisterHotkey("Main Window", "Start Emulation");
204 LoadHotkeys(settings); 193 LoadHotkeys();
205 194
206 connect(GetHotkey("Main Window", "Load File", this), SIGNAL(activated()), this, SLOT(OnMenuLoadFile())); 195 connect(GetHotkey("Main Window", "Load File", this), SIGNAL(activated()), this, SLOT(OnMenuLoadFile()));
207 connect(GetHotkey("Main Window", "Start Emulation", this), SIGNAL(activated()), this, SLOT(OnStartGame())); 196 connect(GetHotkey("Main Window", "Start Emulation", this), SIGNAL(activated()), this, SLOT(OnStartGame()));
@@ -211,7 +200,7 @@ GMainWindow::GMainWindow() : emu_thread(nullptr)
211 200
212 show(); 201 show();
213 202
214 game_list->PopulateAsync(settings.value("gameListRootDir", ".").toString(), settings.value("gameListDeepScan", false).toBool()); 203 game_list->PopulateAsync(UISettings::values.gamedir, UISettings::values.gamedir_deepscan);
215 204
216 QStringList args = QApplication::arguments(); 205 QStringList args = QApplication::arguments();
217 if (args.length() >= 2) { 206 if (args.length() >= 2) {
@@ -254,6 +243,14 @@ bool GMainWindow::InitializeSystem() {
254 if (emu_thread != nullptr) 243 if (emu_thread != nullptr)
255 ShutdownGame(); 244 ShutdownGame();
256 245
246 render_window->MakeCurrent();
247 if (!gladLoadGL()) {
248 QMessageBox::critical(this, tr("Error while starting Citra!"),
249 tr("Failed to initialize the video core!\n\n"
250 "Please ensure that your GPU supports OpenGL 3.3 and that you have the latest graphics driver."));
251 return false;
252 }
253
257 // Initialize the core emulation 254 // Initialize the core emulation
258 System::Result system_result = System::Init(render_window); 255 System::Result system_result = System::Init(render_window);
259 if (System::Result::Success != system_result) { 256 if (System::Result::Success != system_result) {
@@ -375,32 +372,24 @@ void GMainWindow::ShutdownGame() {
375 emulation_running = false; 372 emulation_running = false;
376} 373}
377 374
378void GMainWindow::StoreRecentFile(const std::string& filename) 375void GMainWindow::StoreRecentFile(const std::string& filename) {
379{ 376 UISettings::values.recent_files.prepend(QString::fromStdString(filename));
380 QSettings settings; 377 UISettings::values.recent_files.removeDuplicates();
381 QStringList recent_files = settings.value("recentFiles").toStringList(); 378 while (UISettings::values.recent_files.size() > max_recent_files_item) {
382 recent_files.prepend(QString::fromStdString(filename)); 379 UISettings::values.recent_files.removeLast();
383 recent_files.removeDuplicates();
384 while (recent_files.size() > max_recent_files_item) {
385 recent_files.removeLast();
386 } 380 }
387 381
388 settings.setValue("recentFiles", recent_files);
389
390 UpdateRecentFiles(); 382 UpdateRecentFiles();
391} 383}
392 384
393void GMainWindow::UpdateRecentFiles() { 385void GMainWindow::UpdateRecentFiles() {
394 QSettings settings; 386 unsigned int num_recent_files = std::min(UISettings::values.recent_files.size(), static_cast<int>(max_recent_files_item));
395 QStringList recent_files = settings.value("recentFiles").toStringList();
396
397 unsigned int num_recent_files = std::min(recent_files.size(), static_cast<int>(max_recent_files_item));
398 387
399 for (unsigned int i = 0; i < num_recent_files; i++) { 388 for (unsigned int i = 0; i < num_recent_files; i++) {
400 QString text = QString("&%1. %2").arg(i + 1).arg(QFileInfo(recent_files[i]).fileName()); 389 QString text = QString("&%1. %2").arg(i + 1).arg(QFileInfo(UISettings::values.recent_files[i]).fileName());
401 actions_recent_files[i]->setText(text); 390 actions_recent_files[i]->setText(text);
402 actions_recent_files[i]->setData(recent_files[i]); 391 actions_recent_files[i]->setData(UISettings::values.recent_files[i]);
403 actions_recent_files[i]->setToolTip(recent_files[i]); 392 actions_recent_files[i]->setToolTip(UISettings::values.recent_files[i]);
404 actions_recent_files[i]->setVisible(true); 393 actions_recent_files[i]->setVisible(true);
405 } 394 }
406 395
@@ -421,36 +410,28 @@ void GMainWindow::OnGameListLoadFile(QString game_path) {
421} 410}
422 411
423void GMainWindow::OnMenuLoadFile() { 412void GMainWindow::OnMenuLoadFile() {
424 QSettings settings; 413 QString filename = QFileDialog::getOpenFileName(this, tr("Load File"), UISettings::values.roms_path, tr("3DS executable (*.3ds *.3dsx *.elf *.axf *.cci *.cxi)"));
425 QString rom_path = settings.value("romsPath", QString()).toString();
426
427 QString filename = QFileDialog::getOpenFileName(this, tr("Load File"), rom_path, tr("3DS executable (*.3ds *.3dsx *.elf *.axf *.cci *.cxi)"));
428 if (!filename.isEmpty()) { 414 if (!filename.isEmpty()) {
429 settings.setValue("romsPath", QFileInfo(filename).path()); 415 UISettings::values.roms_path = QFileInfo(filename).path();
430 416
431 BootGame(filename.toStdString()); 417 BootGame(filename.toStdString());
432 } 418 }
433} 419}
434 420
435void GMainWindow::OnMenuLoadSymbolMap() { 421void GMainWindow::OnMenuLoadSymbolMap() {
436 QSettings settings; 422 QString filename = QFileDialog::getOpenFileName(this, tr("Load Symbol Map"), UISettings::values.symbols_path, tr("Symbol map (*)"));
437 QString symbol_path = settings.value("symbolsPath", QString()).toString();
438
439 QString filename = QFileDialog::getOpenFileName(this, tr("Load Symbol Map"), symbol_path, tr("Symbol map (*)"));
440 if (!filename.isEmpty()) { 423 if (!filename.isEmpty()) {
441 settings.setValue("symbolsPath", QFileInfo(filename).path()); 424 UISettings::values.symbols_path = QFileInfo(filename).path();
442 425
443 LoadSymbolMap(filename.toStdString()); 426 LoadSymbolMap(filename.toStdString());
444 } 427 }
445} 428}
446 429
447void GMainWindow::OnMenuSelectGameListRoot() { 430void GMainWindow::OnMenuSelectGameListRoot() {
448 QSettings settings;
449
450 QString dir_path = QFileDialog::getExistingDirectory(this, tr("Select Directory")); 431 QString dir_path = QFileDialog::getExistingDirectory(this, tr("Select Directory"));
451 if (!dir_path.isEmpty()) { 432 if (!dir_path.isEmpty()) {
452 settings.setValue("gameListRootDir", dir_path); 433 UISettings::values.gamedir = dir_path;
453 game_list->PopulateAsync(dir_path, settings.value("gameListDeepScan").toBool()); 434 game_list->PopulateAsync(dir_path, UISettings::values.gamedir_deepscan);
454 } 435 }
455} 436}
456 437
@@ -466,10 +447,7 @@ void GMainWindow::OnMenuRecentFile() {
466 // Display an error message and remove the file from the list. 447 // Display an error message and remove the file from the list.
467 QMessageBox::information(this, tr("File not found"), tr("File \"%1\" not found").arg(filename)); 448 QMessageBox::information(this, tr("File not found"), tr("File \"%1\" not found").arg(filename));
468 449
469 QSettings settings; 450 UISettings::values.recent_files.removeOne(filename);
470 QStringList recent_files = settings.value("recentFiles").toStringList();
471 recent_files.removeOne(filename);
472 settings.setValue("recentFiles", recent_files);
473 UpdateRecentFiles(); 451 UpdateRecentFiles();
474 } 452 }
475} 453}
@@ -496,31 +474,6 @@ void GMainWindow::OnStopGame() {
496 ShutdownGame(); 474 ShutdownGame();
497} 475}
498 476
499void GMainWindow::OnOpenHotkeysDialog() {
500 GHotkeysDialog dialog(this);
501 dialog.exec();
502}
503
504void GMainWindow::SetHardwareRendererEnabled(bool enabled) {
505 VideoCore::g_hw_renderer_enabled = enabled;
506
507 Config config;
508 Settings::values.use_hw_renderer = enabled;
509 config.Save();
510}
511
512void GMainWindow::SetGdbstubEnabled(bool enabled) {
513 GDBStub::ToggleServer(enabled);
514}
515
516void GMainWindow::SetShaderJITEnabled(bool enabled) {
517 VideoCore::g_shader_jit_enabled = enabled;
518
519 Config config;
520 Settings::values.use_shader_jit = enabled;
521 config.Save();
522}
523
524void GMainWindow::ToggleWindowMode() { 477void GMainWindow::ToggleWindowMode() {
525 if (ui.action_Single_Window_Mode->isChecked()) { 478 if (ui.action_Single_Window_Mode->isChecked()) {
526 // Render in the main window... 479 // Render in the main window...
@@ -547,11 +500,17 @@ void GMainWindow::ToggleWindowMode() {
547} 500}
548 501
549void GMainWindow::OnConfigure() { 502void GMainWindow::OnConfigure() {
550 //GControllerConfigDialog* dialog = new GControllerConfigDialog(controller_ports, this); 503 ConfigureDialog configureDialog(this);
504 auto result = configureDialog.exec();
505 if (result == QDialog::Accepted)
506 {
507 configureDialog.applyConfiguration();
508 config->Save();
509 }
551} 510}
552 511
553bool GMainWindow::ConfirmClose() { 512bool GMainWindow::ConfirmClose() {
554 if (emu_thread == nullptr || !confirm_before_closing) 513 if (emu_thread == nullptr || !UISettings::values.confirm_before_closing)
555 return true; 514 return true;
556 515
557 auto answer = QMessageBox::question(this, tr("Citra"), 516 auto answer = QMessageBox::question(this, tr("Citra"),
@@ -566,23 +525,19 @@ void GMainWindow::closeEvent(QCloseEvent* event) {
566 return; 525 return;
567 } 526 }
568 527
569 // Save window layout 528 UISettings::values.geometry = saveGeometry();
570 QSettings settings(QSettings::IniFormat, QSettings::UserScope, "Citra team", "Citra"); 529 UISettings::values.state = saveState();
571 530 UISettings::values.renderwindow_geometry = render_window->saveGeometry();
572 settings.beginGroup("UILayout"); 531#if MICROPROFILE_ENABLED
573 settings.setValue("geometry", saveGeometry()); 532 UISettings::values.microprofile_geometry = microProfileDialog->saveGeometry();
574 settings.setValue("state", saveState()); 533 UISettings::values.microprofile_visible = microProfileDialog->isVisible();
575 settings.setValue("geometryRenderWindow", render_window->saveGeometry()); 534#endif
576 settings.setValue("microProfileDialogGeometry", microProfileDialog->saveGeometry()); 535 UISettings::values.single_window_mode = ui.action_Single_Window_Mode->isChecked();
577 settings.setValue("microProfileDialogVisible", microProfileDialog->isVisible()); 536 UISettings::values.display_titlebar = ui.actionDisplay_widget_title_bars->isChecked();
578 settings.endGroup(); 537 UISettings::values.first_start = false;
579 538
580 settings.setValue("singleWindowMode", ui.action_Single_Window_Mode->isChecked()); 539 game_list->SaveInterfaceLayout();
581 settings.setValue("displayTitleBars", ui.actionDisplay_widget_title_bars->isChecked()); 540 SaveHotkeys();
582 settings.setValue("firstStart", false);
583 settings.setValue("confirmClose", confirm_before_closing);
584 game_list->SaveInterfaceLayout(settings);
585 SaveHotkeys(settings);
586 541
587 // Shutdown session if the emu thread is active... 542 // Shutdown session if the emu thread is active...
588 if (emu_thread != nullptr) 543 if (emu_thread != nullptr)
@@ -607,7 +562,6 @@ int main(int argc, char* argv[]) {
607 }); 562 });
608 563
609 // Init settings params 564 // Init settings params
610 QSettings::setDefaultFormat(QSettings::IniFormat);
611 QCoreApplication::setOrganizationName("Citra team"); 565 QCoreApplication::setOrganizationName("Citra team");
612 QCoreApplication::setApplicationName("Citra"); 566 QCoreApplication::setApplicationName("Citra");
613 567
diff --git a/src/citra_qt/main.h b/src/citra_qt/main.h
index 6e4e56689..477db5c5c 100644
--- a/src/citra_qt/main.h
+++ b/src/citra_qt/main.h
@@ -10,6 +10,7 @@
10 10
11#include "ui_main.h" 11#include "ui_main.h"
12 12
13class Config;
13class GameList; 14class GameList;
14class GImageInfo; 15class GImageInfo;
15class GRenderWindow; 16class GRenderWindow;
@@ -104,12 +105,8 @@ private slots:
104 /// Called whenever a user selects the "File->Select Game List Root" menu item 105 /// Called whenever a user selects the "File->Select Game List Root" menu item
105 void OnMenuSelectGameListRoot(); 106 void OnMenuSelectGameListRoot();
106 void OnMenuRecentFile(); 107 void OnMenuRecentFile();
107 void OnOpenHotkeysDialog();
108 void OnConfigure(); 108 void OnConfigure();
109 void OnDisplayTitleBars(bool); 109 void OnDisplayTitleBars(bool);
110 void SetHardwareRendererEnabled(bool);
111 void SetGdbstubEnabled(bool);
112 void SetShaderJITEnabled(bool);
113 void ToggleWindowMode(); 110 void ToggleWindowMode();
114 111
115private: 112private:
@@ -118,6 +115,8 @@ private:
118 GRenderWindow* render_window; 115 GRenderWindow* render_window;
119 GameList* game_list; 116 GameList* game_list;
120 117
118 std::unique_ptr<Config> config;
119
121 // Whether emulation is currently running in Citra. 120 // Whether emulation is currently running in Citra.
122 bool emulation_running = false; 121 bool emulation_running = false;
123 std::unique_ptr<EmuThread> emu_thread; 122 std::unique_ptr<EmuThread> emu_thread;
@@ -131,7 +130,6 @@ private:
131 GPUCommandListWidget* graphicsCommandsWidget; 130 GPUCommandListWidget* graphicsCommandsWidget;
132 131
133 QAction* actions_recent_files[max_recent_files_item]; 132 QAction* actions_recent_files[max_recent_files_item];
134 bool confirm_before_closing;
135}; 133};
136 134
137#endif // _CITRA_QT_MAIN_HXX_ 135#endif // _CITRA_QT_MAIN_HXX_
diff --git a/src/citra_qt/main.ui b/src/citra_qt/main.ui
index 1e8a07cfb..441e0b81e 100644
--- a/src/citra_qt/main.ui
+++ b/src/citra_qt/main.ui
@@ -45,7 +45,7 @@
45 <x>0</x> 45 <x>0</x>
46 <y>0</y> 46 <y>0</y>
47 <width>1081</width> 47 <width>1081</width>
48 <height>22</height> 48 <height>19</height>
49 </rect> 49 </rect>
50 </property> 50 </property>
51 <widget class="QMenu" name="menu_File"> 51 <widget class="QMenu" name="menu_File">
@@ -73,9 +73,6 @@
73 <addaction name="action_Pause"/> 73 <addaction name="action_Pause"/>
74 <addaction name="action_Stop"/> 74 <addaction name="action_Stop"/>
75 <addaction name="separator"/> 75 <addaction name="separator"/>
76 <addaction name="action_Use_Hardware_Renderer"/>
77 <addaction name="action_Use_Shader_JIT"/>
78 <addaction name="action_Use_Gdbstub"/>
79 <addaction name="action_Configure"/> 76 <addaction name="action_Configure"/>
80 </widget> 77 </widget>
81 <widget class="QMenu" name="menu_View"> 78 <widget class="QMenu" name="menu_View">
@@ -84,7 +81,6 @@
84 </property> 81 </property>
85 <addaction name="action_Single_Window_Mode"/> 82 <addaction name="action_Single_Window_Mode"/>
86 <addaction name="actionDisplay_widget_title_bars"/> 83 <addaction name="actionDisplay_widget_title_bars"/>
87 <addaction name="action_Hotkeys"/>
88 </widget> 84 </widget>
89 <widget class="QMenu" name="menu_Help"> 85 <widget class="QMenu" name="menu_Help">
90 <property name="title"> 86 <property name="title">
@@ -150,35 +146,6 @@
150 <string>Single Window Mode</string> 146 <string>Single Window Mode</string>
151 </property> 147 </property>
152 </action> 148 </action>
153 <action name="action_Hotkeys">
154 <property name="text">
155 <string>Configure &amp;Hotkeys ...</string>
156 </property>
157 </action>
158 <action name="action_Use_Hardware_Renderer">
159 <property name="checkable">
160 <bool>true</bool>
161 </property>
162 <property name="text">
163 <string>Use Hardware Renderer</string>
164 </property>
165 </action>
166 <action name="action_Use_Shader_JIT">
167 <property name="checkable">
168 <bool>true</bool>
169 </property>
170 <property name="text">
171 <string>Use Shader JIT</string>
172 </property>
173 </action>
174 <action name="action_Use_Gdbstub">
175 <property name="checkable">
176 <bool>true</bool>
177 </property>
178 <property name="text">
179 <string>Use Gdbstub</string>
180 </property>
181 </action>
182 <action name="action_Configure"> 149 <action name="action_Configure">
183 <property name="text"> 150 <property name="text">
184 <string>Configure ...</string> 151 <string>Configure ...</string>
@@ -220,22 +187,6 @@
220 </hints> 187 </hints>
221 </connection> 188 </connection>
222 <connection> 189 <connection>
223 <sender>action_Configure</sender>
224 <signal>triggered()</signal>
225 <receiver>MainWindow</receiver>
226 <slot>OnConfigure()</slot>
227 <hints>
228 <hint type="sourcelabel">
229 <x>-1</x>
230 <y>-1</y>
231 </hint>
232 <hint type="destinationlabel">
233 <x>540</x>
234 <y>364</y>
235 </hint>
236 </hints>
237 </connection>
238 <connection>
239 <sender>actionDisplay_widget_title_bars</sender> 190 <sender>actionDisplay_widget_title_bars</sender>
240 <signal>triggered(bool)</signal> 191 <signal>triggered(bool)</signal>
241 <receiver>MainWindow</receiver> 192 <receiver>MainWindow</receiver>
diff --git a/src/citra_qt/ui_settings.cpp b/src/citra_qt/ui_settings.cpp
new file mode 100644
index 000000000..5f2215899
--- /dev/null
+++ b/src/citra_qt/ui_settings.cpp
@@ -0,0 +1,11 @@
1// Copyright 2016 Citra Emulator Project
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#include "ui_settings.h"
6
7namespace UISettings {
8
9Values values = {};
10
11}
diff --git a/src/citra_qt/ui_settings.h b/src/citra_qt/ui_settings.h
new file mode 100644
index 000000000..62db4a73e
--- /dev/null
+++ b/src/citra_qt/ui_settings.h
@@ -0,0 +1,47 @@
1// Copyright 2016 Citra Emulator Project
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#pragma once
6
7#include <QByteArray>
8#include <QStringList>
9#include <QString>
10
11#include <vector>
12
13namespace UISettings {
14
15using ContextualShortcut = std::pair<QString, int> ;
16using Shortcut = std::pair<QString, ContextualShortcut>;
17
18struct Values {
19 QByteArray geometry;
20 QByteArray state;
21
22 QByteArray renderwindow_geometry;
23
24 QByteArray gamelist_header_state;
25
26 QByteArray microprofile_geometry;
27 bool microprofile_visible;
28
29 bool single_window_mode;
30 bool display_titlebar;
31
32 bool confirm_before_closing;
33 bool first_start;
34
35 QString roms_path;
36 QString symbols_path;
37 QString gamedir;
38 bool gamedir_deepscan;
39 QStringList recent_files;
40
41 // Shortcut name <Shortcut, context>
42 std::vector<Shortcut> shortcuts;
43};
44
45extern Values values;
46
47}
diff --git a/src/citra_qt/util/util.cpp b/src/citra_qt/util/util.cpp
index 8734a8efd..2f9beb5cc 100644
--- a/src/citra_qt/util/util.cpp
+++ b/src/citra_qt/util/util.cpp
@@ -19,7 +19,7 @@ QString ReadableByteSize(qulonglong size) {
19 static const std::array<const char*, 6> units = { "B", "KiB", "MiB", "GiB", "TiB", "PiB" }; 19 static const std::array<const char*, 6> units = { "B", "KiB", "MiB", "GiB", "TiB", "PiB" };
20 if (size == 0) 20 if (size == 0)
21 return "0"; 21 return "0";
22 int digit_groups = std::min<int>((int)(std::log10(size) / std::log10(1024)), units.size()); 22 int digit_groups = std::min<int>(static_cast<int>(std::log10(size) / std::log10(1024)), static_cast<int>(units.size()));
23 return QString("%L1 %2").arg(size / std::pow(1024, digit_groups), 0, 'f', 1) 23 return QString("%L1 %2").arg(size / std::pow(1024, digit_groups), 0, 'f', 1)
24 .arg(units[digit_groups]); 24 .arg(units[digit_groups]);
25} 25}