diff options
Diffstat (limited to 'src/citra_qt')
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() | |||
| 81 | endif() | 96 | endif() |
| 82 | target_link_libraries(citra-qt core video_core audio_core common qhexedit) | 97 | target_link_libraries(citra-qt core video_core audio_core common qhexedit) |
| 83 | target_link_libraries(citra-qt ${OPENGL_gl_LIBRARY} ${CITRA_QT_LIBS}) | 98 | target_link_libraries(citra-qt ${OPENGL_gl_LIBRARY} ${CITRA_QT_LIBS}) |
| 84 | target_link_libraries(citra-qt ${PLATFORM_LIBRARIES}) | 99 | target_link_libraries(citra-qt ${PLATFORM_LIBRARIES} Threads::Threads) |
| 85 | 100 | ||
| 86 | if(${CMAKE_SYSTEM_NAME} MATCHES "Linux|FreeBSD|OpenBSD|NetBSD") | 101 | if(${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 | ||
| 14 | Config::Config() { | 15 | Config::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 | ||
| 73 | void Config::SaveValues() { | 123 | void 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 | ||
| 114 | void Config::Reload() { | 202 | void Config::Reload() { |
| 115 | ReadValues(); | 203 | ReadValues(); |
| 204 | Settings::Apply(); | ||
| 116 | } | 205 | } |
| 117 | 206 | ||
| 118 | void Config::Save() { | 207 | void 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 | |||
| 12 | ConfigureAudio::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 | |||
| 27 | ConfigureAudio::~ConfigureAudio() { | ||
| 28 | } | ||
| 29 | |||
| 30 | void 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 | |||
| 41 | void 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 | |||
| 10 | namespace Ui { | ||
| 11 | class ConfigureAudio; | ||
| 12 | } | ||
| 13 | |||
| 14 | class ConfigureAudio : public QWidget { | ||
| 15 | Q_OBJECT | ||
| 16 | |||
| 17 | public: | ||
| 18 | explicit ConfigureAudio(QWidget* parent = nullptr); | ||
| 19 | ~ConfigureAudio(); | ||
| 20 | |||
| 21 | void applyConfiguration(); | ||
| 22 | |||
| 23 | private: | ||
| 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 | |||
| 10 | ConfigureDebug::ConfigureDebug(QWidget *parent) : | ||
| 11 | QWidget(parent), | ||
| 12 | ui(new Ui::ConfigureDebug) | ||
| 13 | { | ||
| 14 | ui->setupUi(this); | ||
| 15 | this->setConfiguration(); | ||
| 16 | } | ||
| 17 | |||
| 18 | ConfigureDebug::~ConfigureDebug() { | ||
| 19 | } | ||
| 20 | |||
| 21 | void 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 | |||
| 27 | void 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 | |||
| 10 | namespace Ui { | ||
| 11 | class ConfigureDebug; | ||
| 12 | } | ||
| 13 | |||
| 14 | class ConfigureDebug : public QWidget | ||
| 15 | { | ||
| 16 | Q_OBJECT | ||
| 17 | |||
| 18 | public: | ||
| 19 | explicit ConfigureDebug(QWidget *parent = nullptr); | ||
| 20 | ~ConfigureDebug(); | ||
| 21 | |||
| 22 | void applyConfiguration(); | ||
| 23 | |||
| 24 | private: | ||
| 25 | void setConfiguration(); | ||
| 26 | |||
| 27 | private: | ||
| 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 | |||
| 12 | ConfigureDialog::ConfigureDialog(QWidget *parent) : | ||
| 13 | QDialog(parent), | ||
| 14 | ui(new Ui::ConfigureDialog) | ||
| 15 | { | ||
| 16 | ui->setupUi(this); | ||
| 17 | this->setConfiguration(); | ||
| 18 | } | ||
| 19 | |||
| 20 | ConfigureDialog::~ConfigureDialog() { | ||
| 21 | } | ||
| 22 | |||
| 23 | void ConfigureDialog::setConfiguration() { | ||
| 24 | } | ||
| 25 | |||
| 26 | void 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 | |||
| 10 | namespace Ui { | ||
| 11 | class ConfigureDialog; | ||
| 12 | } | ||
| 13 | |||
| 14 | class ConfigureDialog : public QDialog | ||
| 15 | { | ||
| 16 | Q_OBJECT | ||
| 17 | |||
| 18 | public: | ||
| 19 | explicit ConfigureDialog(QWidget *parent = nullptr); | ||
| 20 | ~ConfigureDialog(); | ||
| 21 | |||
| 22 | void applyConfiguration(); | ||
| 23 | |||
| 24 | private: | ||
| 25 | void setConfiguration(); | ||
| 26 | |||
| 27 | private: | ||
| 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 | |||
| 11 | ConfigureGeneral::ConfigureGeneral(QWidget *parent) : | ||
| 12 | QWidget(parent), | ||
| 13 | ui(new Ui::ConfigureGeneral) | ||
| 14 | { | ||
| 15 | ui->setupUi(this); | ||
| 16 | this->setConfiguration(); | ||
| 17 | } | ||
| 18 | |||
| 19 | ConfigureGeneral::~ConfigureGeneral() { | ||
| 20 | } | ||
| 21 | |||
| 22 | void 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 | |||
| 31 | void 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 | |||
| 10 | namespace Ui { | ||
| 11 | class ConfigureGeneral; | ||
| 12 | } | ||
| 13 | |||
| 14 | class ConfigureGeneral : public QWidget | ||
| 15 | { | ||
| 16 | Q_OBJECT | ||
| 17 | |||
| 18 | public: | ||
| 19 | explicit ConfigureGeneral(QWidget *parent = nullptr); | ||
| 20 | ~ConfigureGeneral(); | ||
| 21 | |||
| 22 | void applyConfiguration(); | ||
| 23 | |||
| 24 | private: | ||
| 25 | void setConfiguration(); | ||
| 26 | |||
| 27 | private: | ||
| 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 | ||
| 455 | void GraphicsVertexShaderWidget::OnBreakPointHit(Pica::DebugContext::Event event, void* data) { | 455 | void 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 | ||
| 20 | using namespace Common::Profiling; | 23 | using namespace Common::Profiling; |
| 21 | 24 | ||
| @@ -34,21 +37,9 @@ static QVariant GetDataForColumn(int col, const AggregatedDuration& duration) | |||
| 34 | } | 37 | } |
| 35 | } | 38 | } |
| 36 | 39 | ||
| 37 | static 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 | |||
| 47 | ProfilerModel::ProfilerModel(QObject* parent) : QAbstractItemModel(parent) | 40 | ProfilerModel::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 | ||
| 54 | QVariant ProfilerModel::headerData(int section, Qt::Orientation orientation, int role) const | 45 | QVariant 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 | |||
| 151 | class MicroProfileWidget : public QWidget { | 133 | class MicroProfileWidget : public QWidget { |
| 152 | public: | 134 | public: |
| 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 | |||
| 174 | MicroProfileDialog::MicroProfileDialog(QWidget* parent) | 160 | MicroProfileDialog::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 | ||
| 196 | QAction* MicroProfileDialog::toggleViewAction() { | 185 | QAction* 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. |
| 223 | static QPainter* mp_painter = nullptr; | 215 | static 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 | ||
| 235 | void MicroProfileWidget::paintEvent(QPaintEvent* ev) { | 231 | void 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 | ||
| 260 | void MicroProfileWidget::mouseMoveEvent(QMouseEvent* ev) { | 258 | void 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 | ||
| 265 | void MicroProfileWidget::mousePressEvent(QMouseEvent* ev) { | 263 | void 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 | ||
| 271 | void MicroProfileWidget::mouseReleaseEvent(QMouseEvent* ev) { | 269 | void 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 | ||
| 277 | void MicroProfileWidget::wheelEvent(QWheelEvent* ev) { | 275 | void 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 | ||
| 14 | class ProfilerModel : public QAbstractItemModel | 16 | class ProfilerModel : public QAbstractItemModel |
| @@ -49,6 +51,7 @@ private: | |||
| 49 | QTimer update_timer; | 51 | QTimer update_timer; |
| 50 | }; | 52 | }; |
| 51 | 53 | ||
| 54 | |||
| 52 | class MicroProfileDialog : public QWidget { | 55 | class 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 | ||
| 103 | void GameList::SaveInterfaceLayout(QSettings& settings) | 104 | void 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 | ||
| 110 | void GameList::LoadInterfaceLayout(QSettings& settings) | 109 | void 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 | ||
| 21 | public: | 21 | public: |
| 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 | ||
| 37 | public slots: | 37 | public 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 | */ | ||
| 27 | static 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 | */ | ||
| 43 | static 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 | */ | ||
| 72 | static 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 | */ | ||
| 85 | static 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 | ||
| 17 | class GameListItem : public QStandardItem { | 89 | class 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 | */ |
| 31 | class GameListItemPath : public GameListItem { | 104 | class GameListItemPath : public GameListItem { |
| 32 | 105 | ||
| 33 | public: | 106 | public: |
| 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 | ||
| 13 | struct Hotkey | 14 | struct Hotkey |
| 14 | { | 15 | { |
| @@ -24,54 +25,39 @@ typedef std::map<QString, HotkeyMap> HotkeyGroupMap; | |||
| 24 | 25 | ||
| 25 | HotkeyGroupMap hotkey_groups; | 26 | HotkeyGroupMap hotkey_groups; |
| 26 | 27 | ||
| 27 | void SaveHotkeys(QSettings& settings) | 28 | void 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 | ||
| 46 | void LoadHotkeys(QSettings& settings) | 43 | void 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 | ||
| 77 | void RegisterHotkey(const QString& group, const QString& action, const QKeySequence& default_keyseq, Qt::ShortcutContext default_context) | 63 | void 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 | ||
| 97 | GHotkeysDialog::GHotkeysDialog(QWidget* parent): QDialog(parent) | 83 | GHotkeysDialog::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 | ||
| 7 | class QDialog; | 9 | class 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 | */ |
| 36 | void SaveHotkeys(QSettings& settings); | 38 | void 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 | */ |
| 43 | void LoadHotkeys(QSettings& settings); | 45 | void LoadHotkeys(); |
| 44 | 46 | ||
| 45 | class GHotkeysDialog : public QDialog | 47 | class 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 | ||
| 53 | GMainWindow::GMainWindow() : emu_thread(nullptr) | 58 | GMainWindow::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 | ||
| 378 | void GMainWindow::StoreRecentFile(const std::string& filename) | 375 | void 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 | ||
| 393 | void GMainWindow::UpdateRecentFiles() { | 385 | void 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 | ||
| 423 | void GMainWindow::OnMenuLoadFile() { | 412 | void 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 | ||
| 435 | void GMainWindow::OnMenuLoadSymbolMap() { | 421 | void 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 | ||
| 447 | void GMainWindow::OnMenuSelectGameListRoot() { | 430 | void 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 | ||
| 499 | void GMainWindow::OnOpenHotkeysDialog() { | ||
| 500 | GHotkeysDialog dialog(this); | ||
| 501 | dialog.exec(); | ||
| 502 | } | ||
| 503 | |||
| 504 | void 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 | |||
| 512 | void GMainWindow::SetGdbstubEnabled(bool enabled) { | ||
| 513 | GDBStub::ToggleServer(enabled); | ||
| 514 | } | ||
| 515 | |||
| 516 | void 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 | |||
| 524 | void GMainWindow::ToggleWindowMode() { | 477 | void 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 | ||
| 549 | void GMainWindow::OnConfigure() { | 502 | void 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 | ||
| 553 | bool GMainWindow::ConfirmClose() { | 512 | bool 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 | ||
| 13 | class Config; | ||
| 13 | class GameList; | 14 | class GameList; |
| 14 | class GImageInfo; | 15 | class GImageInfo; |
| 15 | class GRenderWindow; | 16 | class 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 | ||
| 115 | private: | 112 | private: |
| @@ -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 &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 | |||
| 7 | namespace UISettings { | ||
| 8 | |||
| 9 | Values 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 | |||
| 13 | namespace UISettings { | ||
| 14 | |||
| 15 | using ContextualShortcut = std::pair<QString, int> ; | ||
| 16 | using Shortcut = std::pair<QString, ContextualShortcut>; | ||
| 17 | |||
| 18 | struct 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 | |||
| 45 | extern 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 | } |