mirror of
				https://github.com/PabloMK7/citra.git
				synced 2025-10-30 21:30:04 +00:00 
			
		
		
		
	Merge branch 'master' into feature/savestates-2
This commit is contained in:
		
						commit
						828f88d20a
					
				
					 76 changed files with 3507 additions and 1369 deletions
				
			
		|  | @ -162,6 +162,20 @@ add_executable(citra-qt | |||
|     util/util.h | ||||
| ) | ||||
| 
 | ||||
| if (ENABLE_FFMPEG_VIDEO_DUMPER) | ||||
|     target_sources(citra-qt PRIVATE | ||||
|         dumping/dumping_dialog.cpp | ||||
|         dumping/dumping_dialog.h | ||||
|         dumping/dumping_dialog.ui | ||||
|         dumping/option_set_dialog.cpp | ||||
|         dumping/option_set_dialog.h | ||||
|         dumping/option_set_dialog.ui | ||||
|         dumping/options_dialog.cpp | ||||
|         dumping/options_dialog.h | ||||
|         dumping/options_dialog.ui | ||||
|     ) | ||||
| endif() | ||||
| 
 | ||||
| file(GLOB COMPAT_LIST | ||||
|      ${PROJECT_BINARY_DIR}/dist/compatibility_list/compatibility_list.qrc | ||||
|      ${PROJECT_BINARY_DIR}/dist/compatibility_list/compatibility_list.json) | ||||
|  |  | |||
|  | @ -104,8 +104,8 @@ void EmuThread::run() { | |||
| } | ||||
| 
 | ||||
| OpenGLWindow::OpenGLWindow(QWindow* parent, QWidget* event_handler, QOpenGLContext* shared_context) | ||||
|     : QWindow(parent), event_handler(event_handler), | ||||
|       context(new QOpenGLContext(shared_context->parent())) { | ||||
|     : QWindow(parent), context(new QOpenGLContext(shared_context->parent())), | ||||
|       event_handler(event_handler) { | ||||
| 
 | ||||
|     // disable vsync for any shared contexts
 | ||||
|     auto format = shared_context->format(); | ||||
|  | @ -201,6 +201,8 @@ GRenderWindow::GRenderWindow(QWidget* parent_, EmuThread* emu_thread) | |||
|     setLayout(layout); | ||||
|     InputCommon::Init(); | ||||
| 
 | ||||
|     this->setMouseTracking(true); | ||||
| 
 | ||||
|     GMainWindow* parent = GetMainWindow(); | ||||
|     connect(this, &GRenderWindow::FirstFrameDisplayed, parent, &GMainWindow::OnLoadComplete); | ||||
| } | ||||
|  | @ -297,6 +299,7 @@ void GRenderWindow::mousePressEvent(QMouseEvent* event) { | |||
|     } else if (event->button() == Qt::RightButton) { | ||||
|         InputCommon::GetMotionEmu()->BeginTilt(pos.x(), pos.y()); | ||||
|     } | ||||
|     QWidget::mouseMoveEvent(event); | ||||
| } | ||||
| 
 | ||||
| void GRenderWindow::mouseMoveEvent(QMouseEvent* event) { | ||||
|  | @ -307,6 +310,7 @@ void GRenderWindow::mouseMoveEvent(QMouseEvent* event) { | |||
|     const auto [x, y] = ScaleTouch(pos); | ||||
|     this->TouchMoved(x, y); | ||||
|     InputCommon::GetMotionEmu()->Tilt(pos.x(), pos.y()); | ||||
|     QWidget::mouseMoveEvent(event); | ||||
| } | ||||
| 
 | ||||
| void GRenderWindow::mouseReleaseEvent(QMouseEvent* event) { | ||||
|  |  | |||
|  | @ -95,6 +95,7 @@ void Config::ReadValues() { | |||
|     ReadMiscellaneousValues(); | ||||
|     ReadDebuggingValues(); | ||||
|     ReadWebServiceValues(); | ||||
|     ReadVideoDumpingValues(); | ||||
|     ReadUIValues(); | ||||
|     ReadUtilityValues(); | ||||
| } | ||||
|  | @ -456,8 +457,6 @@ void Config::ReadRendererValues() { | |||
|         ReadSetting(QStringLiteral("texture_filter_name"), QStringLiteral("none")) | ||||
|             .toString() | ||||
|             .toStdString(); | ||||
|     Settings::values.texture_filter_factor = | ||||
|         ReadSetting(QStringLiteral("texture_filter_factor"), 1).toInt(); | ||||
| 
 | ||||
|     qt_config->endGroup(); | ||||
| } | ||||
|  | @ -484,7 +483,7 @@ void Config::ReadShortcutValues() { | |||
| void Config::ReadSystemValues() { | ||||
|     qt_config->beginGroup(QStringLiteral("System")); | ||||
| 
 | ||||
|     Settings::values.is_new_3ds = ReadSetting(QStringLiteral("is_new_3ds"), false).toBool(); | ||||
|     Settings::values.is_new_3ds = ReadSetting(QStringLiteral("is_new_3ds"), true).toBool(); | ||||
|     Settings::values.region_value = | ||||
|         ReadSetting(QStringLiteral("region_value"), Settings::REGION_VALUE_AUTO_SELECT).toInt(); | ||||
|     Settings::values.init_clock = static_cast<Settings::InitClock>( | ||||
|  | @ -496,6 +495,49 @@ void Config::ReadSystemValues() { | |||
|     qt_config->endGroup(); | ||||
| } | ||||
| 
 | ||||
| // Options for variable bit rate live streaming taken from here:
 | ||||
| // https://developers.google.com/media/vp9/live-encoding
 | ||||
| const QString DEFAULT_VIDEO_ENCODER_OPTIONS = | ||||
|     QStringLiteral("quality:realtime,speed:6,tile-columns:4,frame-parallel:1,threads:8,row-mt:1"); | ||||
| const QString DEFAULT_AUDIO_ENCODER_OPTIONS = QString{}; | ||||
| 
 | ||||
| void Config::ReadVideoDumpingValues() { | ||||
|     qt_config->beginGroup(QStringLiteral("VideoDumping")); | ||||
| 
 | ||||
|     Settings::values.output_format = | ||||
|         ReadSetting(QStringLiteral("output_format"), QStringLiteral("webm")) | ||||
|             .toString() | ||||
|             .toStdString(); | ||||
|     Settings::values.format_options = | ||||
|         ReadSetting(QStringLiteral("format_options")).toString().toStdString(); | ||||
| 
 | ||||
|     Settings::values.video_encoder = | ||||
|         ReadSetting(QStringLiteral("video_encoder"), QStringLiteral("libvpx-vp9")) | ||||
|             .toString() | ||||
|             .toStdString(); | ||||
| 
 | ||||
|     Settings::values.video_encoder_options = | ||||
|         ReadSetting(QStringLiteral("video_encoder_options"), DEFAULT_VIDEO_ENCODER_OPTIONS) | ||||
|             .toString() | ||||
|             .toStdString(); | ||||
| 
 | ||||
|     Settings::values.video_bitrate = | ||||
|         ReadSetting(QStringLiteral("video_bitrate"), 2500000).toULongLong(); | ||||
| 
 | ||||
|     Settings::values.audio_encoder = | ||||
|         ReadSetting(QStringLiteral("audio_encoder"), QStringLiteral("libvorbis")) | ||||
|             .toString() | ||||
|             .toStdString(); | ||||
|     Settings::values.audio_encoder_options = | ||||
|         ReadSetting(QStringLiteral("audio_encoder_options"), DEFAULT_AUDIO_ENCODER_OPTIONS) | ||||
|             .toString() | ||||
|             .toStdString(); | ||||
|     Settings::values.audio_bitrate = | ||||
|         ReadSetting(QStringLiteral("audio_bitrate"), 64000).toULongLong(); | ||||
| 
 | ||||
|     qt_config->endGroup(); | ||||
| } | ||||
| 
 | ||||
| void Config::ReadUIValues() { | ||||
|     qt_config->beginGroup(QStringLiteral("UI")); | ||||
| 
 | ||||
|  | @ -530,6 +572,8 @@ void Config::ReadUIValues() { | |||
|     UISettings::values.show_console = ReadSetting(QStringLiteral("showConsole"), false).toBool(); | ||||
|     UISettings::values.pause_when_in_background = | ||||
|         ReadSetting(QStringLiteral("pauseWhenInBackground"), false).toBool(); | ||||
|     UISettings::values.hide_mouse = | ||||
|         ReadSetting(QStringLiteral("hideInactiveMouse"), false).toBool(); | ||||
| 
 | ||||
|     qt_config->endGroup(); | ||||
| } | ||||
|  | @ -628,6 +672,7 @@ void Config::SaveValues() { | |||
|     SaveMiscellaneousValues(); | ||||
|     SaveDebuggingValues(); | ||||
|     SaveWebServiceValues(); | ||||
|     SaveVideoDumpingValues(); | ||||
|     SaveUIValues(); | ||||
|     SaveUtilityValues(); | ||||
| } | ||||
|  | @ -895,8 +940,6 @@ void Config::SaveRendererValues() { | |||
|     WriteSetting(QStringLiteral("texture_filter_name"), | ||||
|                  QString::fromStdString(Settings::values.texture_filter_name), | ||||
|                  QStringLiteral("none")); | ||||
|     WriteSetting(QStringLiteral("texture_filter_factor"), Settings::values.texture_filter_factor, | ||||
|                  1); | ||||
| 
 | ||||
|     qt_config->endGroup(); | ||||
| } | ||||
|  | @ -923,7 +966,7 @@ void Config::SaveShortcutValues() { | |||
| void Config::SaveSystemValues() { | ||||
|     qt_config->beginGroup(QStringLiteral("System")); | ||||
| 
 | ||||
|     WriteSetting(QStringLiteral("is_new_3ds"), Settings::values.is_new_3ds, false); | ||||
|     WriteSetting(QStringLiteral("is_new_3ds"), Settings::values.is_new_3ds, true); | ||||
|     WriteSetting(QStringLiteral("region_value"), Settings::values.region_value, | ||||
|                  Settings::REGION_VALUE_AUTO_SELECT); | ||||
|     WriteSetting(QStringLiteral("init_clock"), static_cast<u32>(Settings::values.init_clock), | ||||
|  | @ -934,6 +977,33 @@ void Config::SaveSystemValues() { | |||
|     qt_config->endGroup(); | ||||
| } | ||||
| 
 | ||||
| void Config::SaveVideoDumpingValues() { | ||||
|     qt_config->beginGroup(QStringLiteral("VideoDumping")); | ||||
| 
 | ||||
|     WriteSetting(QStringLiteral("output_format"), | ||||
|                  QString::fromStdString(Settings::values.output_format), QStringLiteral("webm")); | ||||
|     WriteSetting(QStringLiteral("format_options"), | ||||
|                  QString::fromStdString(Settings::values.format_options)); | ||||
|     WriteSetting(QStringLiteral("video_encoder"), | ||||
|                  QString::fromStdString(Settings::values.video_encoder), | ||||
|                  QStringLiteral("libvpx-vp9")); | ||||
|     WriteSetting(QStringLiteral("video_encoder_options"), | ||||
|                  QString::fromStdString(Settings::values.video_encoder_options), | ||||
|                  DEFAULT_VIDEO_ENCODER_OPTIONS); | ||||
|     WriteSetting(QStringLiteral("video_bitrate"), | ||||
|                  static_cast<unsigned long long>(Settings::values.video_bitrate), 2500000); | ||||
|     WriteSetting(QStringLiteral("audio_encoder"), | ||||
|                  QString::fromStdString(Settings::values.audio_encoder), | ||||
|                  QStringLiteral("libvorbis")); | ||||
|     WriteSetting(QStringLiteral("audio_encoder_options"), | ||||
|                  QString::fromStdString(Settings::values.audio_encoder_options), | ||||
|                  DEFAULT_AUDIO_ENCODER_OPTIONS); | ||||
|     WriteSetting(QStringLiteral("audio_bitrate"), | ||||
|                  static_cast<unsigned long long>(Settings::values.audio_bitrate), 64000); | ||||
| 
 | ||||
|     qt_config->endGroup(); | ||||
| } | ||||
| 
 | ||||
| void Config::SaveUIValues() { | ||||
|     qt_config->beginGroup(QStringLiteral("UI")); | ||||
| 
 | ||||
|  | @ -962,6 +1032,7 @@ void Config::SaveUIValues() { | |||
|     WriteSetting(QStringLiteral("showConsole"), UISettings::values.show_console, false); | ||||
|     WriteSetting(QStringLiteral("pauseWhenInBackground"), | ||||
|                  UISettings::values.pause_when_in_background, false); | ||||
|     WriteSetting(QStringLiteral("hideInactiveMouse"), UISettings::values.hide_mouse, false); | ||||
| 
 | ||||
|     qt_config->endGroup(); | ||||
| } | ||||
|  |  | |||
|  | @ -44,6 +44,7 @@ private: | |||
|     void ReadUpdaterValues(); | ||||
|     void ReadUtilityValues(); | ||||
|     void ReadWebServiceValues(); | ||||
|     void ReadVideoDumpingValues(); | ||||
| 
 | ||||
|     void SaveValues(); | ||||
|     void SaveAudioValues(); | ||||
|  | @ -65,6 +66,7 @@ private: | |||
|     void SaveUpdaterValues(); | ||||
|     void SaveUtilityValues(); | ||||
|     void SaveWebServiceValues(); | ||||
|     void SaveVideoDumpingValues(); | ||||
| 
 | ||||
|     QVariant ReadSetting(const QString& name) const; | ||||
|     QVariant ReadSetting(const QString& name, const QVariant& default_value) const; | ||||
|  |  | |||
|  | @ -8,17 +8,14 @@ | |||
| #include "core/settings.h" | ||||
| #include "ui_configure_enhancements.h" | ||||
| #include "video_core/renderer_opengl/post_processing_opengl.h" | ||||
| #include "video_core/renderer_opengl/texture_filters/texture_filter_manager.h" | ||||
| #include "video_core/renderer_opengl/texture_filters/texture_filterer.h" | ||||
| 
 | ||||
| ConfigureEnhancements::ConfigureEnhancements(QWidget* parent) | ||||
|     : QWidget(parent), ui(new Ui::ConfigureEnhancements) { | ||||
|     ui->setupUi(this); | ||||
| 
 | ||||
|     for (const auto& filter : OpenGL::TextureFilterManager::TextureFilterMap()) | ||||
|         ui->texture_filter_combobox->addItem(QString::fromStdString(filter.first.data())); | ||||
| 
 | ||||
|     connect(ui->texture_filter_combobox, QOverload<int>::of(&QComboBox::currentIndexChanged), this, | ||||
|             &ConfigureEnhancements::updateTextureFilter); | ||||
|     for (const auto& filter : OpenGL::TextureFilterer::GetFilterNames()) | ||||
|         ui->texture_filter_combobox->addItem(QString::fromStdString(filter.data())); | ||||
| 
 | ||||
|     SetConfiguration(); | ||||
| 
 | ||||
|  | @ -60,7 +57,6 @@ void ConfigureEnhancements::SetConfiguration() { | |||
|     ui->factor_3d->setValue(Settings::values.factor_3d); | ||||
|     updateShaders(Settings::values.render_3d); | ||||
|     ui->toggle_linear_filter->setChecked(Settings::values.filter_mode); | ||||
|     ui->texture_scale_spinbox->setValue(Settings::values.texture_filter_factor); | ||||
|     int tex_filter_idx = ui->texture_filter_combobox->findText( | ||||
|         QString::fromStdString(Settings::values.texture_filter_name)); | ||||
|     if (tex_filter_idx == -1) { | ||||
|  | @ -68,7 +64,6 @@ void ConfigureEnhancements::SetConfiguration() { | |||
|     } else { | ||||
|         ui->texture_filter_combobox->setCurrentIndex(tex_filter_idx); | ||||
|     } | ||||
|     updateTextureFilter(tex_filter_idx); | ||||
|     ui->layout_combobox->setCurrentIndex(static_cast<int>(Settings::values.layout_option)); | ||||
|     ui->swap_screen->setChecked(Settings::values.swap_screen); | ||||
|     ui->toggle_disk_shader_cache->setChecked(Settings::values.use_hw_shader && | ||||
|  | @ -105,17 +100,6 @@ void ConfigureEnhancements::updateShaders(Settings::StereoRenderOption stereo_op | |||
|     } | ||||
| } | ||||
| 
 | ||||
| void ConfigureEnhancements::updateTextureFilter(int index) { | ||||
|     if (index == -1) | ||||
|         return; | ||||
|     ui->texture_filter_group->setEnabled(index != 0); | ||||
|     const auto& clamp = OpenGL::TextureFilterManager::TextureFilterMap() | ||||
|                             .at(ui->texture_filter_combobox->currentText().toStdString()) | ||||
|                             .clamp_scale; | ||||
|     ui->texture_scale_spinbox->setMinimum(clamp.min); | ||||
|     ui->texture_scale_spinbox->setMaximum(clamp.max); | ||||
| } | ||||
| 
 | ||||
| void ConfigureEnhancements::RetranslateUI() { | ||||
|     ui->retranslateUi(this); | ||||
| } | ||||
|  | @ -130,7 +114,6 @@ void ConfigureEnhancements::ApplyConfiguration() { | |||
|         ui->shader_combobox->itemText(ui->shader_combobox->currentIndex()).toStdString(); | ||||
|     Settings::values.filter_mode = ui->toggle_linear_filter->isChecked(); | ||||
|     Settings::values.texture_filter_name = ui->texture_filter_combobox->currentText().toStdString(); | ||||
|     Settings::values.texture_filter_factor = ui->texture_scale_spinbox->value(); | ||||
|     Settings::values.layout_option = | ||||
|         static_cast<Settings::LayoutOption>(ui->layout_combobox->currentIndex()); | ||||
|     Settings::values.swap_screen = ui->swap_screen->isChecked(); | ||||
|  |  | |||
|  | @ -131,42 +131,6 @@ | |||
|         </item> | ||||
|        </layout> | ||||
|       </item> | ||||
|       <item> | ||||
|        <widget class="QWidget" name="texture_filter_group" native="true"> | ||||
|         <layout class="QVBoxLayout" name="verticalLayout_7"> | ||||
|          <property name="leftMargin"> | ||||
|           <number>16</number> | ||||
|          </property> | ||||
|          <property name="topMargin"> | ||||
|           <number>0</number> | ||||
|          </property> | ||||
|          <property name="rightMargin"> | ||||
|           <number>0</number> | ||||
|          </property> | ||||
|          <property name="bottomMargin"> | ||||
|           <number>0</number> | ||||
|          </property> | ||||
|          <item> | ||||
|           <layout class="QHBoxLayout" name="horizontalLayout_8"> | ||||
|            <item> | ||||
|             <widget class="QLabel" name="label_6"> | ||||
|              <property name="text"> | ||||
|               <string>Texture Scale Factor</string> | ||||
|              </property> | ||||
|             </widget> | ||||
|            </item> | ||||
|            <item> | ||||
|             <widget class="QSpinBox" name="texture_scale_spinbox"> | ||||
|              <property name="minimum"> | ||||
|               <number>1</number> | ||||
|              </property> | ||||
|             </widget> | ||||
|            </item> | ||||
|           </layout> | ||||
|          </item> | ||||
|         </layout> | ||||
|        </widget> | ||||
|       </item> | ||||
|      </layout> | ||||
|     </widget> | ||||
|    </item> | ||||
|  |  | |||
|  | @ -27,6 +27,7 @@ ConfigureGeneral::~ConfigureGeneral() = default; | |||
| void ConfigureGeneral::SetConfiguration() { | ||||
|     ui->toggle_check_exit->setChecked(UISettings::values.confirm_before_closing); | ||||
|     ui->toggle_background_pause->setChecked(UISettings::values.pause_when_in_background); | ||||
|     ui->toggle_hide_mouse->setChecked(UISettings::values.hide_mouse); | ||||
| 
 | ||||
|     ui->toggle_update_check->setChecked(UISettings::values.check_for_update_on_start); | ||||
|     ui->toggle_auto_update->setChecked(UISettings::values.update_on_close); | ||||
|  | @ -55,6 +56,7 @@ void ConfigureGeneral::ResetDefaults() { | |||
| void ConfigureGeneral::ApplyConfiguration() { | ||||
|     UISettings::values.confirm_before_closing = ui->toggle_check_exit->isChecked(); | ||||
|     UISettings::values.pause_when_in_background = ui->toggle_background_pause->isChecked(); | ||||
|     UISettings::values.hide_mouse = ui->toggle_hide_mouse->isChecked(); | ||||
| 
 | ||||
|     UISettings::values.check_for_update_on_start = ui->toggle_update_check->isChecked(); | ||||
|     UISettings::values.update_on_close = ui->toggle_auto_update->isChecked(); | ||||
|  |  | |||
|  | @ -36,6 +36,13 @@ | |||
|           </property> | ||||
|          </widget> | ||||
|         </item> | ||||
|         <item> | ||||
|          <widget class="QCheckBox" name="toggle_hide_mouse"> | ||||
|           <property name="text"> | ||||
|            <string>Hide mouse on inactivity</string> | ||||
|           </property> | ||||
|          </widget> | ||||
|         </item> | ||||
|        </layout> | ||||
|       </widget> | ||||
|      </item> | ||||
|  |  | |||
|  | @ -30,7 +30,7 @@ CalibrationConfigurationDialog::CalibrationConfigurationDialog(QWidget* parent, | |||
|     setLayout(layout); | ||||
| 
 | ||||
|     using namespace InputCommon::CemuhookUDP; | ||||
|     job = std::move(std::make_unique<CalibrationConfigurationJob>( | ||||
|     job = std::make_unique<CalibrationConfigurationJob>( | ||||
|         host, port, pad_index, client_id, | ||||
|         [this](CalibrationConfigurationJob::Status status) { | ||||
|             QString text; | ||||
|  | @ -56,7 +56,7 @@ CalibrationConfigurationDialog::CalibrationConfigurationDialog(QWidget* parent, | |||
|             min_y = min_y_; | ||||
|             max_x = max_x_; | ||||
|             max_y = max_y_; | ||||
|         })); | ||||
|         }); | ||||
| } | ||||
| 
 | ||||
| CalibrationConfigurationDialog::~CalibrationConfigurationDialog() = default; | ||||
|  |  | |||
|  | @ -277,6 +277,8 @@ void ConfigureSystem::SetConfiguration() { | |||
|     ui->slider_clock_speed->setValue(SettingsToSlider(Settings::values.cpu_clock_percentage)); | ||||
|     ui->clock_display_label->setText( | ||||
|         QStringLiteral("%1%").arg(Settings::values.cpu_clock_percentage)); | ||||
| 
 | ||||
|     ui->toggle_new_3ds->setChecked(Settings::values.is_new_3ds); | ||||
| } | ||||
| 
 | ||||
| void ConfigureSystem::ReadSystemSettings() { | ||||
|  | @ -374,6 +376,8 @@ void ConfigureSystem::ApplyConfiguration() { | |||
|         Settings::values.init_clock = | ||||
|             static_cast<Settings::InitClock>(ui->combo_init_clock->currentIndex()); | ||||
|         Settings::values.init_time = ui->edit_init_time->dateTime().toTime_t(); | ||||
| 
 | ||||
|         Settings::values.is_new_3ds = ui->toggle_new_3ds->isChecked(); | ||||
|     } | ||||
| 
 | ||||
|     Settings::values.cpu_clock_percentage = SliderToSettings(ui->slider_clock_speed->value()); | ||||
|  |  | |||
|  | @ -22,14 +22,74 @@ | |||
|         <string>System Settings</string> | ||||
|        </property> | ||||
|        <layout class="QGridLayout" name="gridLayout"> | ||||
|         <item row="0" column="0"> | ||||
|          <widget class="QLabel" name="label_username"> | ||||
|           <property name="text"> | ||||
|            <string>Username</string> | ||||
|         <item row="4" column="1"> | ||||
|          <widget class="QComboBox" name="combo_language"> | ||||
|           <property name="toolTip"> | ||||
|            <string>Note: this can be overridden when region setting is auto-select</string> | ||||
|           </property> | ||||
|           <item> | ||||
|            <property name="text"> | ||||
|             <string>Japanese (日本語)</string> | ||||
|            </property> | ||||
|           </item> | ||||
|           <item> | ||||
|            <property name="text"> | ||||
|             <string>English</string> | ||||
|            </property> | ||||
|           </item> | ||||
|           <item> | ||||
|            <property name="text"> | ||||
|             <string>French (français)</string> | ||||
|            </property> | ||||
|           </item> | ||||
|           <item> | ||||
|            <property name="text"> | ||||
|             <string>German (Deutsch)</string> | ||||
|            </property> | ||||
|           </item> | ||||
|           <item> | ||||
|            <property name="text"> | ||||
|             <string>Italian (italiano)</string> | ||||
|            </property> | ||||
|           </item> | ||||
|           <item> | ||||
|            <property name="text"> | ||||
|             <string>Spanish (español)</string> | ||||
|            </property> | ||||
|           </item> | ||||
|           <item> | ||||
|            <property name="text"> | ||||
|             <string>Simplified Chinese (简体中文)</string> | ||||
|            </property> | ||||
|           </item> | ||||
|           <item> | ||||
|            <property name="text"> | ||||
|             <string>Korean (한국어)</string> | ||||
|            </property> | ||||
|           </item> | ||||
|           <item> | ||||
|            <property name="text"> | ||||
|             <string>Dutch (Nederlands)</string> | ||||
|            </property> | ||||
|           </item> | ||||
|           <item> | ||||
|            <property name="text"> | ||||
|             <string>Portuguese (português)</string> | ||||
|            </property> | ||||
|           </item> | ||||
|           <item> | ||||
|            <property name="text"> | ||||
|             <string>Russian (Русский)</string> | ||||
|            </property> | ||||
|           </item> | ||||
|           <item> | ||||
|            <property name="text"> | ||||
|             <string>Traditional Chinese (正體中文)</string> | ||||
|            </property> | ||||
|           </item> | ||||
|          </widget> | ||||
|         </item> | ||||
|         <item row="0" column="1"> | ||||
|         <item row="2" column="1"> | ||||
|          <widget class="QLineEdit" name="edit_username"> | ||||
|           <property name="sizePolicy"> | ||||
|            <sizepolicy hsizetype="Preferred" vsizetype="Fixed"> | ||||
|  | @ -42,14 +102,33 @@ | |||
|           </property> | ||||
|          </widget> | ||||
|         </item> | ||||
|         <item row="1" column="0"> | ||||
|          <widget class="QLabel" name="label_birthday"> | ||||
|         <item row="2" column="0"> | ||||
|          <widget class="QLabel" name="label_username"> | ||||
|           <property name="text"> | ||||
|            <string>Birthday</string> | ||||
|            <string>Username</string> | ||||
|           </property> | ||||
|          </widget> | ||||
|         </item> | ||||
|         <item row="1" column="1"> | ||||
|         <item row="5" column="1"> | ||||
|          <widget class="QComboBox" name="combo_sound"> | ||||
|           <item> | ||||
|            <property name="text"> | ||||
|             <string>Mono</string> | ||||
|            </property> | ||||
|           </item> | ||||
|           <item> | ||||
|            <property name="text"> | ||||
|             <string>Stereo</string> | ||||
|            </property> | ||||
|           </item> | ||||
|           <item> | ||||
|            <property name="text"> | ||||
|             <string>Surround</string> | ||||
|            </property> | ||||
|           </item> | ||||
|          </widget> | ||||
|         </item> | ||||
|         <item row="3" column="1"> | ||||
|          <layout class="QHBoxLayout" name="horizontalLayout_birthday2"> | ||||
|           <item> | ||||
|            <widget class="QComboBox" name="combo_birthmonth"> | ||||
|  | @ -120,124 +199,38 @@ | |||
|           </item> | ||||
|          </layout> | ||||
|         </item> | ||||
|         <item row="2" column="0"> | ||||
|         <item row="4" column="0"> | ||||
|          <widget class="QLabel" name="label_language"> | ||||
|           <property name="text"> | ||||
|            <string>Language</string> | ||||
|           </property> | ||||
|          </widget> | ||||
|         </item> | ||||
|         <item row="2" column="1"> | ||||
|          <widget class="QComboBox" name="combo_language"> | ||||
|           <property name="toolTip"> | ||||
|            <string>Note: this can be overridden when region setting is auto-select</string> | ||||
|         <item row="3" column="0"> | ||||
|          <widget class="QLabel" name="label_birthday"> | ||||
|           <property name="text"> | ||||
|            <string>Birthday</string> | ||||
|           </property> | ||||
|           <item> | ||||
|            <property name="text"> | ||||
|             <string>Japanese (日本語)</string> | ||||
|            </property> | ||||
|           </item> | ||||
|           <item> | ||||
|            <property name="text"> | ||||
|             <string>English</string> | ||||
|            </property> | ||||
|           </item> | ||||
|           <item> | ||||
|            <property name="text"> | ||||
|             <string>French (français)</string> | ||||
|            </property> | ||||
|           </item> | ||||
|           <item> | ||||
|            <property name="text"> | ||||
|             <string>German (Deutsch)</string> | ||||
|            </property> | ||||
|           </item> | ||||
|           <item> | ||||
|            <property name="text"> | ||||
|             <string>Italian (italiano)</string> | ||||
|            </property> | ||||
|           </item> | ||||
|           <item> | ||||
|            <property name="text"> | ||||
|             <string>Spanish (español)</string> | ||||
|            </property> | ||||
|           </item> | ||||
|           <item> | ||||
|            <property name="text"> | ||||
|             <string>Simplified Chinese (简体中文)</string> | ||||
|            </property> | ||||
|           </item> | ||||
|           <item> | ||||
|            <property name="text"> | ||||
|             <string>Korean (한국어)</string> | ||||
|            </property> | ||||
|           </item> | ||||
|           <item> | ||||
|            <property name="text"> | ||||
|             <string>Dutch (Nederlands)</string> | ||||
|            </property> | ||||
|           </item> | ||||
|           <item> | ||||
|            <property name="text"> | ||||
|             <string>Portuguese (português)</string> | ||||
|            </property> | ||||
|           </item> | ||||
|           <item> | ||||
|            <property name="text"> | ||||
|             <string>Russian (Русский)</string> | ||||
|            </property> | ||||
|           </item> | ||||
|           <item> | ||||
|            <property name="text"> | ||||
|             <string>Traditional Chinese (正體中文)</string> | ||||
|            </property> | ||||
|           </item> | ||||
|          </widget> | ||||
|         </item> | ||||
|         <item row="3" column="0"> | ||||
|         <item row="5" column="0"> | ||||
|          <widget class="QLabel" name="label_sound"> | ||||
|           <property name="text"> | ||||
|            <string>Sound output mode</string> | ||||
|           </property> | ||||
|          </widget> | ||||
|         </item> | ||||
|         <item row="3" column="1"> | ||||
|          <widget class="QComboBox" name="combo_sound"> | ||||
|           <item> | ||||
|            <property name="text"> | ||||
|             <string>Mono</string> | ||||
|            </property> | ||||
|           </item> | ||||
|           <item> | ||||
|            <property name="text"> | ||||
|             <string>Stereo</string> | ||||
|            </property> | ||||
|           </item> | ||||
|           <item> | ||||
|            <property name="text"> | ||||
|             <string>Surround</string> | ||||
|            </property> | ||||
|           </item> | ||||
|          </widget> | ||||
|         <item row="6" column="1"> | ||||
|          <widget class="QComboBox" name="combo_country"/> | ||||
|         </item> | ||||
|         <item row="4" column="0"> | ||||
|         <item row="6" column="0"> | ||||
|          <widget class="QLabel" name="label_country"> | ||||
|           <property name="text"> | ||||
|            <string>Country</string> | ||||
|           </property> | ||||
|          </widget> | ||||
|         </item> | ||||
|         <item row="4" column="1"> | ||||
|          <widget class="QComboBox" name="combo_country"/> | ||||
|         </item> | ||||
|         <item row="5" column="0"> | ||||
|          <widget class="QLabel" name="label_init_clock"> | ||||
|           <property name="text"> | ||||
|            <string>Clock</string> | ||||
|           </property> | ||||
|          </widget> | ||||
|         </item> | ||||
|         <item row="5" column="1"> | ||||
|         <item row="7" column="1"> | ||||
|          <widget class="QComboBox" name="combo_init_clock"> | ||||
|           <item> | ||||
|            <property name="text"> | ||||
|  | @ -251,42 +244,35 @@ | |||
|           </item> | ||||
|          </widget> | ||||
|         </item> | ||||
|         <item row="6" column="0"> | ||||
|         <item row="7" column="0"> | ||||
|          <widget class="QLabel" name="label_init_clock"> | ||||
|           <property name="text"> | ||||
|            <string>Clock</string> | ||||
|           </property> | ||||
|          </widget> | ||||
|         </item> | ||||
|         <item row="8" column="0"> | ||||
|          <widget class="QLabel" name="label_init_time"> | ||||
|           <property name="text"> | ||||
|            <string>Startup time</string> | ||||
|           </property> | ||||
|          </widget> | ||||
|         </item> | ||||
|         <item row="6" column="1"> | ||||
|          <widget class="QDateTimeEdit" name="edit_init_time"> | ||||
|           <property name="displayFormat"> | ||||
|            <string>yyyy-MM-ddTHH:mm:ss</string> | ||||
|           </property> | ||||
|          </widget> | ||||
|         </item> | ||||
|         <item row="7" column="0"> | ||||
|          <widget class="QLabel" name="label_play_coins"> | ||||
|           <property name="text"> | ||||
|            <string>Play Coins:</string> | ||||
|           </property> | ||||
|          </widget> | ||||
|         </item> | ||||
|         <item row="7" column="1"> | ||||
|         <item row="9" column="1"> | ||||
|          <widget class="QSpinBox" name="spinBox_play_coins"> | ||||
|           <property name="maximum"> | ||||
|            <number>300</number> | ||||
|           </property> | ||||
|          </widget> | ||||
|         </item> | ||||
|         <item row="8" column="0"> | ||||
|          <widget class="QLabel" name="label_console_id"> | ||||
|         <item row="9" column="0"> | ||||
|          <widget class="QLabel" name="label_play_coins"> | ||||
|           <property name="text"> | ||||
|            <string>Console ID:</string> | ||||
|            <string>Play Coins:</string> | ||||
|           </property> | ||||
|          </widget> | ||||
|         </item> | ||||
|         <item row="8" column="1"> | ||||
|         <item row="12" column="1"> | ||||
|          <widget class="QPushButton" name="button_regenerate_console_id"> | ||||
|           <property name="sizePolicy"> | ||||
|            <sizepolicy hsizetype="Fixed" vsizetype="Fixed"> | ||||
|  | @ -302,6 +288,27 @@ | |||
|           </property> | ||||
|          </widget> | ||||
|         </item> | ||||
|         <item row="12" column="0"> | ||||
|          <widget class="QLabel" name="label_console_id"> | ||||
|           <property name="text"> | ||||
|            <string>Console ID:</string> | ||||
|           </property> | ||||
|          </widget> | ||||
|         </item> | ||||
|         <item row="8" column="1"> | ||||
|          <widget class="QDateTimeEdit" name="edit_init_time"> | ||||
|           <property name="displayFormat"> | ||||
|            <string>yyyy-MM-ddTHH:mm:ss</string> | ||||
|           </property> | ||||
|          </widget> | ||||
|         </item> | ||||
|         <item row="1" column="0"> | ||||
|          <widget class="QCheckBox" name="toggle_new_3ds"> | ||||
|           <property name="text"> | ||||
|            <string>Enable New 3DS mode</string> | ||||
|           </property> | ||||
|          </widget> | ||||
|         </item> | ||||
|        </layout> | ||||
|       </widget> | ||||
|      </item> | ||||
|  |  | |||
							
								
								
									
										220
									
								
								src/citra_qt/dumping/dumping_dialog.cpp
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										220
									
								
								src/citra_qt/dumping/dumping_dialog.cpp
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,220 @@ | |||
| // Copyright 2020 Citra Emulator Project
 | ||||
| // Licensed under GPLv2 or any later version
 | ||||
| // Refer to the license.txt file included.
 | ||||
| 
 | ||||
| #include <QFileDialog> | ||||
| #include <QMessageBox> | ||||
| #include "citra_qt/dumping/dumping_dialog.h" | ||||
| #include "citra_qt/dumping/options_dialog.h" | ||||
| #include "citra_qt/uisettings.h" | ||||
| #include "core/settings.h" | ||||
| #include "ui_dumping_dialog.h" | ||||
| 
 | ||||
| DumpingDialog::DumpingDialog(QWidget* parent) | ||||
|     : QDialog(parent), ui(std::make_unique<Ui::DumpingDialog>()) { | ||||
| 
 | ||||
|     ui->setupUi(this); | ||||
| 
 | ||||
|     format_generic_options = VideoDumper::GetFormatGenericOptions(); | ||||
|     encoder_generic_options = VideoDumper::GetEncoderGenericOptions(); | ||||
| 
 | ||||
|     connect(ui->pathExplore, &QToolButton::clicked, this, &DumpingDialog::OnToolButtonClicked); | ||||
|     connect(ui->buttonBox, &QDialogButtonBox::accepted, [this] { | ||||
|         if (ui->pathLineEdit->text().isEmpty()) { | ||||
|             QMessageBox::critical(this, tr("Citra"), tr("Please specify the output path.")); | ||||
|             return; | ||||
|         } | ||||
|         ApplyConfiguration(); | ||||
|         accept(); | ||||
|     }); | ||||
|     connect(ui->buttonBox, &QDialogButtonBox::rejected, this, &DumpingDialog::reject); | ||||
|     connect(ui->formatOptionsButton, &QToolButton::clicked, [this] { | ||||
|         OpenOptionsDialog(formats.at(ui->formatComboBox->currentData().toUInt()).options, | ||||
|                           format_generic_options, ui->formatOptionsLineEdit); | ||||
|     }); | ||||
|     connect(ui->videoEncoderOptionsButton, &QToolButton::clicked, [this] { | ||||
|         OpenOptionsDialog( | ||||
|             video_encoders.at(ui->videoEncoderComboBox->currentData().toUInt()).options, | ||||
|             encoder_generic_options, ui->videoEncoderOptionsLineEdit); | ||||
|     }); | ||||
|     connect(ui->audioEncoderOptionsButton, &QToolButton::clicked, [this] { | ||||
|         OpenOptionsDialog( | ||||
|             audio_encoders.at(ui->audioEncoderComboBox->currentData().toUInt()).options, | ||||
|             encoder_generic_options, ui->audioEncoderOptionsLineEdit); | ||||
|     }); | ||||
| 
 | ||||
|     SetConfiguration(); | ||||
| 
 | ||||
|     connect(ui->formatComboBox, qOverload<int>(&QComboBox::currentIndexChanged), [this] { | ||||
|         ui->pathLineEdit->setText(QString{}); | ||||
|         ui->formatOptionsLineEdit->clear(); | ||||
|         PopulateEncoders(); | ||||
|     }); | ||||
| 
 | ||||
|     connect(ui->videoEncoderComboBox, qOverload<int>(&QComboBox::currentIndexChanged), | ||||
|             [this] { ui->videoEncoderOptionsLineEdit->clear(); }); | ||||
|     connect(ui->audioEncoderComboBox, qOverload<int>(&QComboBox::currentIndexChanged), | ||||
|             [this] { ui->audioEncoderOptionsLineEdit->clear(); }); | ||||
| } | ||||
| 
 | ||||
| DumpingDialog::~DumpingDialog() = default; | ||||
| 
 | ||||
| QString DumpingDialog::GetFilePath() const { | ||||
|     return ui->pathLineEdit->text(); | ||||
| } | ||||
| 
 | ||||
| void DumpingDialog::Populate() { | ||||
|     formats = VideoDumper::ListFormats(); | ||||
|     video_encoders = VideoDumper::ListEncoders(AVMEDIA_TYPE_VIDEO); | ||||
|     audio_encoders = VideoDumper::ListEncoders(AVMEDIA_TYPE_AUDIO); | ||||
| 
 | ||||
|     // Check that these are not empty
 | ||||
|     QString missing; | ||||
|     if (formats.empty()) { | ||||
|         missing = tr("output formats"); | ||||
|     } | ||||
|     if (video_encoders.empty()) { | ||||
|         missing = tr("video encoders"); | ||||
|     } | ||||
|     if (audio_encoders.empty()) { | ||||
|         missing = tr("audio encoders"); | ||||
|     } | ||||
| 
 | ||||
|     if (!missing.isEmpty()) { | ||||
|         QMessageBox::critical(this, tr("Citra"), | ||||
|                               tr("Could not find any available %1.\nPlease check your FFmpeg " | ||||
|                                  "installation used for compilation.") | ||||
|                                   .arg(missing)); | ||||
|         reject(); | ||||
|         return; | ||||
|     } | ||||
| 
 | ||||
|     // Populate formats
 | ||||
|     for (std::size_t i = 0; i < formats.size(); ++i) { | ||||
|         const auto& format = formats[i]; | ||||
| 
 | ||||
|         // Check format: only formats that have video encoders and audio encoders are displayed
 | ||||
|         bool has_video = false; | ||||
|         for (const auto& video_encoder : video_encoders) { | ||||
|             if (format.supported_video_codecs.count(video_encoder.codec)) { | ||||
|                 has_video = true; | ||||
|                 break; | ||||
|             } | ||||
|         } | ||||
|         if (!has_video) | ||||
|             continue; | ||||
| 
 | ||||
|         bool has_audio = false; | ||||
|         for (const auto& audio_encoder : audio_encoders) { | ||||
|             if (format.supported_audio_codecs.count(audio_encoder.codec)) { | ||||
|                 has_audio = true; | ||||
|                 break; | ||||
|             } | ||||
|         } | ||||
|         if (!has_audio) | ||||
|             continue; | ||||
| 
 | ||||
|         ui->formatComboBox->addItem(tr("%1 (%2)").arg(QString::fromStdString(format.long_name), | ||||
|                                                       QString::fromStdString(format.name)), | ||||
|                                     static_cast<unsigned long long>(i)); | ||||
|         if (format.name == Settings::values.output_format) { | ||||
|             ui->formatComboBox->setCurrentIndex(ui->formatComboBox->count() - 1); | ||||
|         } | ||||
|     } | ||||
|     PopulateEncoders(); | ||||
| } | ||||
| 
 | ||||
| void DumpingDialog::PopulateEncoders() { | ||||
|     const auto& format = formats.at(ui->formatComboBox->currentData().toUInt()); | ||||
| 
 | ||||
|     ui->videoEncoderComboBox->clear(); | ||||
|     for (std::size_t i = 0; i < video_encoders.size(); ++i) { | ||||
|         const auto& video_encoder = video_encoders[i]; | ||||
|         if (!format.supported_video_codecs.count(video_encoder.codec)) { | ||||
|             continue; | ||||
|         } | ||||
| 
 | ||||
|         ui->videoEncoderComboBox->addItem( | ||||
|             tr("%1 (%2)").arg(QString::fromStdString(video_encoder.long_name), | ||||
|                               QString::fromStdString(video_encoder.name)), | ||||
|             static_cast<unsigned long long>(i)); | ||||
|         if (video_encoder.name == Settings::values.video_encoder) { | ||||
|             ui->videoEncoderComboBox->setCurrentIndex(ui->videoEncoderComboBox->count() - 1); | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     ui->audioEncoderComboBox->clear(); | ||||
|     for (std::size_t i = 0; i < audio_encoders.size(); ++i) { | ||||
|         const auto& audio_encoder = audio_encoders[i]; | ||||
|         if (!format.supported_audio_codecs.count(audio_encoder.codec)) { | ||||
|             continue; | ||||
|         } | ||||
| 
 | ||||
|         ui->audioEncoderComboBox->addItem( | ||||
|             tr("%1 (%2)").arg(QString::fromStdString(audio_encoder.long_name), | ||||
|                               QString::fromStdString(audio_encoder.name)), | ||||
|             static_cast<unsigned long long>(i)); | ||||
|         if (audio_encoder.name == Settings::values.audio_encoder) { | ||||
|             ui->audioEncoderComboBox->setCurrentIndex(ui->audioEncoderComboBox->count() - 1); | ||||
|         } | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| void DumpingDialog::OnToolButtonClicked() { | ||||
|     const auto& format = formats.at(ui->formatComboBox->currentData().toUInt()); | ||||
| 
 | ||||
|     QString extensions; | ||||
|     for (const auto& ext : format.extensions) { | ||||
|         if (!extensions.isEmpty()) { | ||||
|             extensions.append(QLatin1Char{' '}); | ||||
|         } | ||||
|         extensions.append(QStringLiteral("*.%1").arg(QString::fromStdString(ext))); | ||||
|     } | ||||
| 
 | ||||
|     const auto path = QFileDialog::getSaveFileName( | ||||
|         this, tr("Select Video Output Path"), last_path, | ||||
|         tr("%1 (%2)").arg(QString::fromStdString(format.long_name), extensions)); | ||||
|     if (!path.isEmpty()) { | ||||
|         last_path = QFileInfo(ui->pathLineEdit->text()).path(); | ||||
|         ui->pathLineEdit->setText(path); | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| void DumpingDialog::OpenOptionsDialog(const std::vector<VideoDumper::OptionInfo>& specific_options, | ||||
|                                       const std::vector<VideoDumper::OptionInfo>& generic_options, | ||||
|                                       QLineEdit* line_edit) { | ||||
|     OptionsDialog dialog(this, specific_options, generic_options, line_edit->text().toStdString()); | ||||
|     if (dialog.exec() != QDialog::DialogCode::Accepted) { | ||||
|         return; | ||||
|     } | ||||
| 
 | ||||
|     line_edit->setText(QString::fromStdString(dialog.GetCurrentValue())); | ||||
| } | ||||
| 
 | ||||
| void DumpingDialog::SetConfiguration() { | ||||
|     Populate(); | ||||
| 
 | ||||
|     ui->formatOptionsLineEdit->setText(QString::fromStdString(Settings::values.format_options)); | ||||
|     ui->videoEncoderOptionsLineEdit->setText( | ||||
|         QString::fromStdString(Settings::values.video_encoder_options)); | ||||
|     ui->audioEncoderOptionsLineEdit->setText( | ||||
|         QString::fromStdString(Settings::values.audio_encoder_options)); | ||||
|     last_path = UISettings::values.video_dumping_path; | ||||
|     ui->videoBitrateSpinBox->setValue(static_cast<int>(Settings::values.video_bitrate)); | ||||
|     ui->audioBitrateSpinBox->setValue(static_cast<int>(Settings::values.audio_bitrate)); | ||||
| } | ||||
| 
 | ||||
| void DumpingDialog::ApplyConfiguration() { | ||||
|     Settings::values.output_format = formats.at(ui->formatComboBox->currentData().toUInt()).name; | ||||
|     Settings::values.format_options = ui->formatOptionsLineEdit->text().toStdString(); | ||||
|     Settings::values.video_encoder = | ||||
|         video_encoders.at(ui->videoEncoderComboBox->currentData().toUInt()).name; | ||||
|     Settings::values.video_encoder_options = ui->videoEncoderOptionsLineEdit->text().toStdString(); | ||||
|     Settings::values.video_bitrate = ui->videoBitrateSpinBox->value(); | ||||
|     Settings::values.audio_encoder = | ||||
|         audio_encoders.at(ui->audioEncoderComboBox->currentData().toUInt()).name; | ||||
|     Settings::values.audio_encoder_options = ui->audioEncoderOptionsLineEdit->text().toStdString(); | ||||
|     Settings::values.audio_bitrate = ui->audioBitrateSpinBox->value(); | ||||
|     UISettings::values.video_dumping_path = last_path; | ||||
|     Settings::Apply(); | ||||
| } | ||||
							
								
								
									
										43
									
								
								src/citra_qt/dumping/dumping_dialog.h
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										43
									
								
								src/citra_qt/dumping/dumping_dialog.h
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,43 @@ | |||
| // Copyright 2020 Citra Emulator Project
 | ||||
| // Licensed under GPLv2 or any later version
 | ||||
| // Refer to the license.txt file included.
 | ||||
| 
 | ||||
| #include <memory> | ||||
| #include <QDialog> | ||||
| #include "core/dumping/ffmpeg_backend.h" | ||||
| 
 | ||||
| namespace Ui { | ||||
| class DumpingDialog; | ||||
| } | ||||
| 
 | ||||
| class QLineEdit; | ||||
| 
 | ||||
| class DumpingDialog : public QDialog { | ||||
|     Q_OBJECT | ||||
| 
 | ||||
| public: | ||||
|     explicit DumpingDialog(QWidget* parent); | ||||
|     ~DumpingDialog() override; | ||||
| 
 | ||||
|     QString GetFilePath() const; | ||||
|     void ApplyConfiguration(); | ||||
| 
 | ||||
| private: | ||||
|     void Populate(); | ||||
|     void PopulateEncoders(); | ||||
|     void SetConfiguration(); | ||||
|     void OnToolButtonClicked(); | ||||
|     void OpenOptionsDialog(const std::vector<VideoDumper::OptionInfo>& specific_options, | ||||
|                            const std::vector<VideoDumper::OptionInfo>& generic_options, | ||||
|                            QLineEdit* line_edit); | ||||
| 
 | ||||
|     std::unique_ptr<Ui::DumpingDialog> ui; | ||||
| 
 | ||||
|     QString last_path; | ||||
| 
 | ||||
|     std::vector<VideoDumper::FormatInfo> formats; | ||||
|     std::vector<VideoDumper::OptionInfo> format_generic_options; | ||||
|     std::vector<VideoDumper::EncoderInfo> video_encoders; | ||||
|     std::vector<VideoDumper::EncoderInfo> audio_encoders; | ||||
|     std::vector<VideoDumper::OptionInfo> encoder_generic_options; | ||||
| }; | ||||
							
								
								
									
										213
									
								
								src/citra_qt/dumping/dumping_dialog.ui
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										213
									
								
								src/citra_qt/dumping/dumping_dialog.ui
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,213 @@ | |||
| <?xml version="1.0" encoding="UTF-8"?> | ||||
| <ui version="4.0"> | ||||
|  <class>DumpingDialog</class> | ||||
|  <widget class="QDialog" name="DumpingDialog"> | ||||
|   <property name="geometry"> | ||||
|    <rect> | ||||
|     <x>0</x> | ||||
|     <y>0</y> | ||||
|     <width>600</width> | ||||
|     <height>420</height> | ||||
|    </rect> | ||||
|   </property> | ||||
|   <property name="windowTitle"> | ||||
|    <string>Dump Video</string> | ||||
|   </property> | ||||
|   <layout class="QVBoxLayout"> | ||||
|    <item> | ||||
|     <widget class="QGroupBox"> | ||||
|      <property name="title"> | ||||
|       <string>Output</string> | ||||
|      </property> | ||||
|      <layout class="QGridLayout"> | ||||
|       <item row="0" column="0"> | ||||
|        <widget class="QLabel"> | ||||
|         <property name="text"> | ||||
|          <string>Format:</string> | ||||
|         </property> | ||||
|        </widget> | ||||
|       </item> | ||||
|       <item row="0" column="1"> | ||||
|        <widget class="QComboBox" name="formatComboBox"/> | ||||
|       </item> | ||||
|       <item row="1" column="0"> | ||||
|        <widget class="QLabel"> | ||||
|         <property name="text"> | ||||
|          <string>Options:</string> | ||||
|         </property> | ||||
|        </widget> | ||||
|       </item> | ||||
|       <item row="1" column="1"> | ||||
|        <widget class="QLineEdit" name="formatOptionsLineEdit"/> | ||||
|       </item> | ||||
|       <item row="1" column="2"> | ||||
|        <widget class="QToolButton" name="formatOptionsButton"> | ||||
|         <property name="text"> | ||||
|          <string>...</string> | ||||
|         </property> | ||||
|        </widget> | ||||
|       </item> | ||||
|       <item row="2" column="0"> | ||||
|        <widget class="QLabel"> | ||||
|         <property name="text"> | ||||
|          <string>Path:</string> | ||||
|         </property> | ||||
|        </widget> | ||||
|       </item> | ||||
|       <item row="2" column="1"> | ||||
|        <widget class="QLineEdit" name="pathLineEdit"/> | ||||
|       </item> | ||||
|       <item row="2" column="2"> | ||||
|        <widget class="QToolButton" name="pathExplore"> | ||||
|         <property name="text"> | ||||
|          <string>...</string> | ||||
|         </property> | ||||
|        </widget> | ||||
|       </item> | ||||
|      </layout> | ||||
|     </widget> | ||||
|    </item> | ||||
|    <item> | ||||
|     <widget class="QGroupBox"> | ||||
|      <property name="title"> | ||||
|       <string>Video</string> | ||||
|      </property> | ||||
|      <layout class="QGridLayout"> | ||||
|       <item row="0" column="0"> | ||||
|        <widget class="QLabel"> | ||||
|         <property name="text"> | ||||
|          <string>Encoder:</string> | ||||
|         </property> | ||||
|        </widget> | ||||
|       </item> | ||||
|       <item row="0" column="1"> | ||||
|        <widget class="QComboBox" name="videoEncoderComboBox"> | ||||
|         <property name="sizePolicy"> | ||||
|          <sizepolicy hsizetype="MinimumExpanding" vsizetype="Fixed"> | ||||
|           <horstretch>0</horstretch> | ||||
|           <verstretch>0</verstretch> | ||||
|          </sizepolicy> | ||||
|         </property> | ||||
|        </widget> | ||||
|       </item> | ||||
|       <item row="1" column="0"> | ||||
|        <widget class="QLabel"> | ||||
|         <property name="text"> | ||||
|          <string>Options:</string> | ||||
|         </property> | ||||
|        </widget> | ||||
|       </item> | ||||
|       <item row="1" column="1"> | ||||
|        <widget class="QLineEdit" name="videoEncoderOptionsLineEdit"/> | ||||
|       </item> | ||||
|       <item row="1" column="2"> | ||||
|        <widget class="QToolButton" name="videoEncoderOptionsButton"> | ||||
|         <property name="text"> | ||||
|          <string>...</string> | ||||
|         </property> | ||||
|        </widget> | ||||
|       </item> | ||||
|       <item row="2" column="0"> | ||||
|        <widget class="QLabel"> | ||||
|         <property name="text"> | ||||
|          <string>Bitrate:</string> | ||||
|         </property> | ||||
|        </widget> | ||||
|       </item> | ||||
|       <item row="2" column="1"> | ||||
|        <widget class="QSpinBox" name="videoBitrateSpinBox"> | ||||
|         <property name="maximum"> | ||||
|          <number>10000000</number> | ||||
|         </property> | ||||
|         <property name="singleStep"> | ||||
|          <number>1000</number> | ||||
|         </property> | ||||
|        </widget> | ||||
|       </item> | ||||
|       <item row="2" column="2"> | ||||
|        <widget class="QLabel"> | ||||
|         <property name="text"> | ||||
|          <string>bps</string> | ||||
|         </property> | ||||
|        </widget> | ||||
|       </item> | ||||
|      </layout> | ||||
|     </widget> | ||||
|    </item> | ||||
|    <item> | ||||
|     <widget class="QGroupBox"> | ||||
|      <property name="title"> | ||||
|       <string>Audio</string> | ||||
|      </property> | ||||
|      <layout class="QGridLayout"> | ||||
|       <item row="0" column="0"> | ||||
|        <widget class="QLabel"> | ||||
|         <property name="text"> | ||||
|          <string>Encoder:</string> | ||||
|         </property> | ||||
|        </widget> | ||||
|       </item> | ||||
|       <item row="0" column="1"> | ||||
|        <widget class="QComboBox" name="audioEncoderComboBox"> | ||||
|         <property name="sizePolicy"> | ||||
|          <sizepolicy hsizetype="MinimumExpanding" vsizetype="Fixed"> | ||||
|           <horstretch>0</horstretch> | ||||
|           <verstretch>0</verstretch> | ||||
|          </sizepolicy> | ||||
|         </property> | ||||
|        </widget> | ||||
|       </item> | ||||
|       <item row="1" column="0"> | ||||
|        <widget class="QLabel"> | ||||
|         <property name="text"> | ||||
|          <string>Options:</string> | ||||
|         </property> | ||||
|        </widget> | ||||
|       </item> | ||||
|       <item row="1" column="1"> | ||||
|        <widget class="QLineEdit" name="audioEncoderOptionsLineEdit"/> | ||||
|       </item> | ||||
|       <item row="1" column="2"> | ||||
|        <widget class="QToolButton" name="audioEncoderOptionsButton"> | ||||
|         <property name="text"> | ||||
|          <string>...</string> | ||||
|         </property> | ||||
|        </widget> | ||||
|       </item> | ||||
|       <item row="2" column="0"> | ||||
|        <widget class="QLabel"> | ||||
|         <property name="text"> | ||||
|          <string>Bitrate:</string> | ||||
|         </property> | ||||
|        </widget> | ||||
|       </item> | ||||
|       <item row="2" column="1"> | ||||
|        <widget class="QSpinBox" name="audioBitrateSpinBox"> | ||||
|         <property name="maximum"> | ||||
|          <number>1000000</number> | ||||
|         </property> | ||||
|         <property name="singleStep"> | ||||
|          <number>100</number> | ||||
|         </property> | ||||
|        </widget> | ||||
|       </item> | ||||
|       <item row="2" column="2"> | ||||
|        <widget class="QLabel"> | ||||
|         <property name="text"> | ||||
|          <string>bps</string> | ||||
|         </property> | ||||
|        </widget> | ||||
|       </item> | ||||
|      </layout> | ||||
|     </widget> | ||||
|    </item> | ||||
|    <item> | ||||
|     <widget class="QDialogButtonBox" name="buttonBox"> | ||||
|      <property name="standardButtons"> | ||||
|       <set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set> | ||||
|      </property> | ||||
|     </widget> | ||||
|    </item> | ||||
|   </layout> | ||||
|  </widget> | ||||
| </ui> | ||||
							
								
								
									
										299
									
								
								src/citra_qt/dumping/option_set_dialog.cpp
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										299
									
								
								src/citra_qt/dumping/option_set_dialog.cpp
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,299 @@ | |||
| // Copyright 2020 Citra Emulator Project
 | ||||
| // Licensed under GPLv2 or any later version
 | ||||
| // Refer to the license.txt file included.
 | ||||
| 
 | ||||
| #include <unordered_map> | ||||
| #include <QCheckBox> | ||||
| #include <QStringList> | ||||
| #include "citra_qt/dumping/option_set_dialog.h" | ||||
| #include "common/logging/log.h" | ||||
| #include "common/string_util.h" | ||||
| #include "ui_option_set_dialog.h" | ||||
| 
 | ||||
| extern "C" { | ||||
| #include <libavutil/pixdesc.h> | ||||
| } | ||||
| 
 | ||||
| static const std::unordered_map<AVOptionType, const char*> TypeNameMap{{ | ||||
|     {AV_OPT_TYPE_BOOL, QT_TR_NOOP("boolean")}, | ||||
|     {AV_OPT_TYPE_FLAGS, QT_TR_NOOP("flags")}, | ||||
|     {AV_OPT_TYPE_DURATION, QT_TR_NOOP("duration")}, | ||||
|     {AV_OPT_TYPE_INT, QT_TR_NOOP("int")}, | ||||
|     {AV_OPT_TYPE_UINT64, QT_TR_NOOP("uint64")}, | ||||
|     {AV_OPT_TYPE_INT64, QT_TR_NOOP("int64")}, | ||||
|     {AV_OPT_TYPE_DOUBLE, QT_TR_NOOP("double")}, | ||||
|     {AV_OPT_TYPE_FLOAT, QT_TR_NOOP("float")}, | ||||
|     {AV_OPT_TYPE_RATIONAL, QT_TR_NOOP("rational")}, | ||||
|     {AV_OPT_TYPE_PIXEL_FMT, QT_TR_NOOP("pixel format")}, | ||||
|     {AV_OPT_TYPE_SAMPLE_FMT, QT_TR_NOOP("sample format")}, | ||||
|     {AV_OPT_TYPE_COLOR, QT_TR_NOOP("color")}, | ||||
|     {AV_OPT_TYPE_IMAGE_SIZE, QT_TR_NOOP("image size")}, | ||||
|     {AV_OPT_TYPE_STRING, QT_TR_NOOP("string")}, | ||||
|     {AV_OPT_TYPE_DICT, QT_TR_NOOP("dictionary")}, | ||||
|     {AV_OPT_TYPE_VIDEO_RATE, QT_TR_NOOP("video rate")}, | ||||
|     {AV_OPT_TYPE_CHANNEL_LAYOUT, QT_TR_NOOP("channel layout")}, | ||||
| }}; | ||||
| 
 | ||||
| static const std::unordered_map<AVOptionType, const char*> TypeDescriptionMap{{ | ||||
|     {AV_OPT_TYPE_DURATION, QT_TR_NOOP("[<hours (integer)>:][<minutes (integer):]<seconds " | ||||
|                                       "(decimal)> e.g. 03:00.5 (3min 500ms)")}, | ||||
|     {AV_OPT_TYPE_RATIONAL, QT_TR_NOOP("<num>/<den>")}, | ||||
|     {AV_OPT_TYPE_COLOR, QT_TR_NOOP("0xRRGGBBAA")}, | ||||
|     {AV_OPT_TYPE_IMAGE_SIZE, QT_TR_NOOP("<width>x<height>, or preset values like 'vga'.")}, | ||||
|     {AV_OPT_TYPE_DICT, | ||||
|      QT_TR_NOOP("Comma-splitted list of <key>=<value>. Do not put spaces.")}, | ||||
|     {AV_OPT_TYPE_VIDEO_RATE, QT_TR_NOOP("<num>/<den>, or preset values like 'pal'.")}, | ||||
|     {AV_OPT_TYPE_CHANNEL_LAYOUT, QT_TR_NOOP("Hexadecimal channel layout mask starting with '0x'.")}, | ||||
| }}; | ||||
| 
 | ||||
| /// Get the preset values of an option. returns {display value, real value}
 | ||||
| std::vector<std::pair<QString, QString>> GetPresetValues(const VideoDumper::OptionInfo& option) { | ||||
|     switch (option.type) { | ||||
|     case AV_OPT_TYPE_BOOL: { | ||||
|         return {{QObject::tr("auto"), QStringLiteral("auto")}, | ||||
|                 {QObject::tr("true"), QStringLiteral("true")}, | ||||
|                 {QObject::tr("false"), QStringLiteral("false")}}; | ||||
|     } | ||||
|     case AV_OPT_TYPE_PIXEL_FMT: { | ||||
|         std::vector<std::pair<QString, QString>> out{{QObject::tr("none"), QStringLiteral("none")}}; | ||||
|         // List all pixel formats
 | ||||
|         const AVPixFmtDescriptor* current = nullptr; | ||||
|         while ((current = av_pix_fmt_desc_next(current))) { | ||||
|             out.emplace_back(QString::fromUtf8(current->name), QString::fromUtf8(current->name)); | ||||
|         } | ||||
|         return out; | ||||
|     } | ||||
|     case AV_OPT_TYPE_SAMPLE_FMT: { | ||||
|         std::vector<std::pair<QString, QString>> out{{QObject::tr("none"), QStringLiteral("none")}}; | ||||
|         // List all sample formats
 | ||||
|         int current = 0; | ||||
|         while (true) { | ||||
|             const char* name = av_get_sample_fmt_name(static_cast<AVSampleFormat>(current)); | ||||
|             if (name == nullptr) | ||||
|                 break; | ||||
|             out.emplace_back(QString::fromUtf8(name), QString::fromUtf8(name)); | ||||
|         } | ||||
|         return out; | ||||
|     } | ||||
|     case AV_OPT_TYPE_INT: | ||||
|     case AV_OPT_TYPE_INT64: | ||||
|     case AV_OPT_TYPE_UINT64: { | ||||
|         std::vector<std::pair<QString, QString>> out; | ||||
|         // Add in all named constants
 | ||||
|         for (const auto& constant : option.named_constants) { | ||||
|             out.emplace_back(QObject::tr("%1 (0x%2)") | ||||
|                                  .arg(QString::fromStdString(constant.name)) | ||||
|                                  .arg(constant.value, 0, 16), | ||||
|                              QString::fromStdString(constant.name)); | ||||
|         } | ||||
|         return out; | ||||
|     } | ||||
|     default: | ||||
|         return {}; | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| void OptionSetDialog::InitializeUI(const std::string& initial_value) { | ||||
|     const QString type_name = | ||||
|         TypeNameMap.count(option.type) ? tr(TypeNameMap.at(option.type)) : tr("unknown"); | ||||
|     ui->nameLabel->setText(tr("%1 <%2> %3") | ||||
|                                .arg(QString::fromStdString(option.name), type_name, | ||||
|                                     QString::fromStdString(option.description))); | ||||
|     if (TypeDescriptionMap.count(option.type)) { | ||||
|         ui->formatLabel->setVisible(true); | ||||
|         ui->formatLabel->setText(tr(TypeDescriptionMap.at(option.type))); | ||||
|     } | ||||
| 
 | ||||
|     if (option.type == AV_OPT_TYPE_INT || option.type == AV_OPT_TYPE_INT64 || | ||||
|         option.type == AV_OPT_TYPE_UINT64 || option.type == AV_OPT_TYPE_FLOAT || | ||||
|         option.type == AV_OPT_TYPE_DOUBLE || option.type == AV_OPT_TYPE_DURATION || | ||||
|         option.type == AV_OPT_TYPE_RATIONAL) { // scalar types
 | ||||
| 
 | ||||
|         ui->formatLabel->setVisible(true); | ||||
|         if (!ui->formatLabel->text().isEmpty()) { | ||||
|             ui->formatLabel->text().append(QStringLiteral("\n")); | ||||
|         } | ||||
|         ui->formatLabel->setText( | ||||
|             ui->formatLabel->text().append(tr("Range: %1 - %2").arg(option.min).arg(option.max))); | ||||
|     } | ||||
| 
 | ||||
|     // Decide and initialize layout
 | ||||
|     if (option.type == AV_OPT_TYPE_BOOL || option.type == AV_OPT_TYPE_PIXEL_FMT || | ||||
|         option.type == AV_OPT_TYPE_SAMPLE_FMT || | ||||
|         ((option.type == AV_OPT_TYPE_INT || option.type == AV_OPT_TYPE_INT64 || | ||||
|           option.type == AV_OPT_TYPE_UINT64) && | ||||
|          !option.named_constants.empty())) { // Use the combobox layout
 | ||||
| 
 | ||||
|         layout_type = 1; | ||||
|         ui->comboBox->setVisible(true); | ||||
|         ui->comboBoxHelpLabel->setVisible(true); | ||||
| 
 | ||||
|         QString real_initial_value = QString::fromStdString(initial_value); | ||||
|         if (option.type == AV_OPT_TYPE_INT || option.type == AV_OPT_TYPE_INT64 || | ||||
|             option.type == AV_OPT_TYPE_UINT64) { | ||||
| 
 | ||||
|             // Get the name of the initial value
 | ||||
|             try { | ||||
|                 s64 initial_value_integer = std::stoll(initial_value, nullptr, 0); | ||||
|                 for (const auto& constant : option.named_constants) { | ||||
|                     if (constant.value == initial_value_integer) { | ||||
|                         real_initial_value = QString::fromStdString(constant.name); | ||||
|                         break; | ||||
|                     } | ||||
|                 } | ||||
|             } catch (...) { | ||||
|                 // Not convertible to integer, ignore
 | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
|         bool found = false; | ||||
|         for (const auto& [display, value] : GetPresetValues(option)) { | ||||
|             ui->comboBox->addItem(display, value); | ||||
|             if (value == real_initial_value) { | ||||
|                 found = true; | ||||
|                 ui->comboBox->setCurrentIndex(ui->comboBox->count() - 1); | ||||
|             } | ||||
|         } | ||||
|         ui->comboBox->addItem(tr("custom")); | ||||
| 
 | ||||
|         if (!found) { | ||||
|             ui->comboBox->setCurrentIndex(ui->comboBox->count() - 1); | ||||
|             ui->lineEdit->setText(QString::fromStdString(initial_value)); | ||||
|         } | ||||
| 
 | ||||
|         UpdateUIDisplay(); | ||||
| 
 | ||||
|         connect(ui->comboBox, &QComboBox::currentTextChanged, this, | ||||
|                 &OptionSetDialog::UpdateUIDisplay); | ||||
|     } else if (option.type == AV_OPT_TYPE_FLAGS && | ||||
|                !option.named_constants.empty()) { // Use the check boxes layout
 | ||||
| 
 | ||||
|         layout_type = 2; | ||||
| 
 | ||||
|         for (const auto& constant : option.named_constants) { | ||||
|             auto* checkBox = new QCheckBox(tr("%1 (0x%2) %3") | ||||
|                                                .arg(QString::fromStdString(constant.name)) | ||||
|                                                .arg(constant.value, 0, 16) | ||||
|                                                .arg(QString::fromStdString(constant.description))); | ||||
|             checkBox->setProperty("value", static_cast<unsigned long long>(constant.value)); | ||||
|             checkBox->setProperty("name", QString::fromStdString(constant.name)); | ||||
|             ui->checkBoxLayout->addWidget(checkBox); | ||||
|         } | ||||
|         SetCheckBoxDefaults(initial_value); | ||||
|     } else { // Use the line edit layout
 | ||||
|         layout_type = 0; | ||||
|         ui->lineEdit->setVisible(true); | ||||
|         ui->lineEdit->setText(QString::fromStdString(initial_value)); | ||||
|     } | ||||
| 
 | ||||
|     adjustSize(); | ||||
| } | ||||
| 
 | ||||
| void OptionSetDialog::SetCheckBoxDefaults(const std::string& initial_value) { | ||||
|     if (initial_value.size() >= 2 && | ||||
|         (initial_value.substr(0, 2) == "0x" || initial_value.substr(0, 2) == "0X")) { | ||||
|         // This is a hex mask
 | ||||
|         try { | ||||
|             u64 value = std::stoull(initial_value, nullptr, 16); | ||||
|             for (int i = 0; i < ui->checkBoxLayout->count(); ++i) { | ||||
|                 auto* checkBox = qobject_cast<QCheckBox*>(ui->checkBoxLayout->itemAt(i)->widget()); | ||||
|                 if (checkBox) { | ||||
|                     checkBox->setChecked(value & checkBox->property("value").toULongLong()); | ||||
|                 } | ||||
|             } | ||||
|         } catch (...) { | ||||
|             LOG_ERROR(Frontend, "Could not convert {} to number", initial_value); | ||||
|         } | ||||
|     } else { | ||||
|         // This is a combination of constants, splitted with + or |
 | ||||
|         std::vector<std::string> tmp; | ||||
|         Common::SplitString(initial_value, '+', tmp); | ||||
| 
 | ||||
|         std::vector<std::string> out; | ||||
|         std::vector<std::string> tmp2; | ||||
|         for (const auto& str : tmp) { | ||||
|             Common::SplitString(str, '|', tmp2); | ||||
|             out.insert(out.end(), tmp2.begin(), tmp2.end()); | ||||
|         } | ||||
|         for (int i = 0; i < ui->checkBoxLayout->count(); ++i) { | ||||
|             auto* checkBox = qobject_cast<QCheckBox*>(ui->checkBoxLayout->itemAt(i)->widget()); | ||||
|             if (checkBox) { | ||||
|                 checkBox->setChecked( | ||||
|                     std::find(out.begin(), out.end(), | ||||
|                               checkBox->property("name").toString().toStdString()) != out.end()); | ||||
|             } | ||||
|         } | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| void OptionSetDialog::UpdateUIDisplay() { | ||||
|     if (layout_type != 1) | ||||
|         return; | ||||
| 
 | ||||
|     if (ui->comboBox->currentIndex() == ui->comboBox->count() - 1) { // custom
 | ||||
|         ui->comboBoxHelpLabel->setVisible(false); | ||||
|         ui->lineEdit->setVisible(true); | ||||
|         adjustSize(); | ||||
|         return; | ||||
|     } | ||||
| 
 | ||||
|     ui->lineEdit->setVisible(false); | ||||
|     for (const auto& constant : option.named_constants) { | ||||
|         if (constant.name == ui->comboBox->currentData().toString().toStdString()) { | ||||
|             ui->comboBoxHelpLabel->setVisible(true); | ||||
|             ui->comboBoxHelpLabel->setText(QString::fromStdString(constant.description)); | ||||
|             return; | ||||
|         } | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| std::pair<bool, std::string> OptionSetDialog::GetCurrentValue() { | ||||
|     if (!is_set) { | ||||
|         return {}; | ||||
|     } | ||||
| 
 | ||||
|     switch (layout_type) { | ||||
|     case 0: // line edit layout
 | ||||
|         return {true, ui->lineEdit->text().toStdString()}; | ||||
|     case 1: // combo box layout
 | ||||
|         if (ui->comboBox->currentIndex() == ui->comboBox->count() - 1) { | ||||
|             return {true, ui->lineEdit->text().toStdString()}; // custom
 | ||||
|         } | ||||
|         return {true, ui->comboBox->currentData().toString().toStdString()}; | ||||
|     case 2: { // check boxes layout
 | ||||
|         std::string out; | ||||
|         for (int i = 0; i < ui->checkBoxLayout->count(); ++i) { | ||||
|             auto* checkBox = qobject_cast<QCheckBox*>(ui->checkBoxLayout->itemAt(i)->widget()); | ||||
|             if (checkBox && checkBox->isChecked()) { | ||||
|                 if (!out.empty()) { | ||||
|                     out.append("+"); | ||||
|                 } | ||||
|                 out.append(checkBox->property("name").toString().toStdString()); | ||||
|             } | ||||
|         } | ||||
|         if (out.empty()) { | ||||
|             out = "0x0"; | ||||
|         } | ||||
|         return {true, out}; | ||||
|     } | ||||
|     default: | ||||
|         return {}; | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| OptionSetDialog::OptionSetDialog(QWidget* parent, VideoDumper::OptionInfo option_, | ||||
|                                  const std::string& initial_value) | ||||
|     : QDialog(parent), ui(std::make_unique<Ui::OptionSetDialog>()), option(std::move(option_)) { | ||||
| 
 | ||||
|     ui->setupUi(this); | ||||
|     InitializeUI(initial_value); | ||||
| 
 | ||||
|     connect(ui->unsetButton, &QPushButton::clicked, [this] { | ||||
|         is_set = false; | ||||
|         accept(); | ||||
|     }); | ||||
|     connect(ui->buttonBox, &QDialogButtonBox::accepted, this, &OptionSetDialog::accept); | ||||
|     connect(ui->buttonBox, &QDialogButtonBox::rejected, this, &OptionSetDialog::reject); | ||||
| } | ||||
| 
 | ||||
| OptionSetDialog::~OptionSetDialog() = default; | ||||
							
								
								
									
										33
									
								
								src/citra_qt/dumping/option_set_dialog.h
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										33
									
								
								src/citra_qt/dumping/option_set_dialog.h
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,33 @@ | |||
| // Copyright 2020 Citra Emulator Project
 | ||||
| // Licensed under GPLv2 or any later version
 | ||||
| // Refer to the license.txt file included.
 | ||||
| 
 | ||||
| #include <memory> | ||||
| #include <QDialog> | ||||
| #include "core/dumping/ffmpeg_backend.h" | ||||
| 
 | ||||
| namespace Ui { | ||||
| class OptionSetDialog; | ||||
| } | ||||
| 
 | ||||
| class OptionSetDialog : public QDialog { | ||||
|     Q_OBJECT | ||||
| 
 | ||||
| public: | ||||
|     explicit OptionSetDialog(QWidget* parent, VideoDumper::OptionInfo option, | ||||
|                              const std::string& initial_value); | ||||
|     ~OptionSetDialog() override; | ||||
| 
 | ||||
|     // {is_set, value}
 | ||||
|     std::pair<bool, std::string> GetCurrentValue(); | ||||
| 
 | ||||
| private: | ||||
|     void InitializeUI(const std::string& initial_value); | ||||
|     void SetCheckBoxDefaults(const std::string& initial_value); | ||||
|     void UpdateUIDisplay(); | ||||
| 
 | ||||
|     std::unique_ptr<Ui::OptionSetDialog> ui; | ||||
|     VideoDumper::OptionInfo option; | ||||
|     bool is_set = true; | ||||
|     int layout_type = -1; // 0 - line edit, 1 - combo box, 2 - flags (check boxes)
 | ||||
| }; | ||||
							
								
								
									
										89
									
								
								src/citra_qt/dumping/option_set_dialog.ui
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										89
									
								
								src/citra_qt/dumping/option_set_dialog.ui
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,89 @@ | |||
| <?xml version="1.0" encoding="UTF-8"?> | ||||
| <ui version="4.0"> | ||||
|  <class>OptionSetDialog</class> | ||||
|  <widget class="QDialog" name="OptionSetDialog"> | ||||
|   <property name="geometry"> | ||||
|    <rect> | ||||
|     <x>0</x> | ||||
|     <y>0</y> | ||||
|     <width>600</width> | ||||
|     <height>150</height> | ||||
|    </rect> | ||||
|   </property> | ||||
|   <property name="windowTitle"> | ||||
|    <string>Options</string> | ||||
|   </property> | ||||
|   <layout class="QVBoxLayout"> | ||||
|    <item> | ||||
|     <widget class="QLabel" name="nameLabel"/> | ||||
|    </item> | ||||
|    <item> | ||||
|     <widget class="QLabel" name="formatLabel"> | ||||
|      <property name="visible"> | ||||
|       <bool>false</bool> | ||||
|      </property> | ||||
|     </widget> | ||||
|    </item> | ||||
|    <item> | ||||
|     <layout class="QVBoxLayout" name="comboBoxLayout"> | ||||
|      <item> | ||||
|       <widget class="QComboBox" name="comboBox"> | ||||
|        <property name="visible"> | ||||
|         <bool>false</bool> | ||||
|        </property> | ||||
|       </widget> | ||||
|      </item> | ||||
|      <item> | ||||
|       <widget class="QLabel" name="comboBoxHelpLabel"> | ||||
|        <property name="visible"> | ||||
|         <bool>false</bool> | ||||
|        </property> | ||||
|       </widget> | ||||
|      </item> | ||||
|     </layout> | ||||
|    </item> | ||||
|    <item> | ||||
|     <widget class="QLineEdit" name="lineEdit"> | ||||
|      <property name="visible"> | ||||
|       <bool>false</bool> | ||||
|      </property> | ||||
|     </widget> | ||||
|    </item> | ||||
|    <item> | ||||
|     <layout class="QVBoxLayout" name="checkBoxLayout"/> | ||||
|    </item> | ||||
|    <item> | ||||
|     <spacer> | ||||
|      <property name="orientation"> | ||||
|       <enum>Qt::Vertical</enum> | ||||
|      </property> | ||||
|     </spacer> | ||||
|    </item> | ||||
|    <item> | ||||
|     <layout class="QHBoxLayout"> | ||||
|      <item> | ||||
|       <widget class="QPushButton" name="unsetButton"> | ||||
|        <property name="text"> | ||||
|         <string>Unset</string> | ||||
|        </property> | ||||
|       </widget> | ||||
|      </item> | ||||
|      <item> | ||||
|       <spacer> | ||||
|        <property name="orientation"> | ||||
|         <enum>Qt::Horizontal</enum> | ||||
|        </property> | ||||
|       </spacer> | ||||
|      </item> | ||||
|      <item> | ||||
|       <widget class="QDialogButtonBox" name="buttonBox"> | ||||
|        <property name="standardButtons"> | ||||
|         <set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set> | ||||
|        </property> | ||||
|       </widget> | ||||
|      </item> | ||||
|     </layout> | ||||
|    </item> | ||||
|   </layout> | ||||
|  </widget> | ||||
| </ui> | ||||
							
								
								
									
										68
									
								
								src/citra_qt/dumping/options_dialog.cpp
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										68
									
								
								src/citra_qt/dumping/options_dialog.cpp
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,68 @@ | |||
| // Copyright 2020 Citra Emulator Project
 | ||||
| // Licensed under GPLv2 or any later version
 | ||||
| // Refer to the license.txt file included.
 | ||||
| 
 | ||||
| #include <QTreeWidgetItem> | ||||
| #include "citra_qt/dumping/option_set_dialog.h" | ||||
| #include "citra_qt/dumping/options_dialog.h" | ||||
| #include "ui_options_dialog.h" | ||||
| 
 | ||||
| constexpr char UNSET_TEXT[] = QT_TR_NOOP("[not set]"); | ||||
| 
 | ||||
| void OptionsDialog::PopulateOptions() { | ||||
|     const auto& options = ui->specificRadioButton->isChecked() ? specific_options : generic_options; | ||||
|     ui->main->clear(); | ||||
|     ui->main->setSortingEnabled(false); | ||||
|     for (std::size_t i = 0; i < options.size(); ++i) { | ||||
|         const auto& option = options.at(i); | ||||
|         auto* item = new QTreeWidgetItem( | ||||
|             {QString::fromStdString(option.name), QString::fromStdString(current_values.Get( | ||||
|                                                       option.name, tr(UNSET_TEXT).toStdString()))}); | ||||
|         item->setData(1, Qt::UserRole, static_cast<unsigned long long>(i)); // ID
 | ||||
|         ui->main->addTopLevelItem(item); | ||||
|     } | ||||
|     ui->main->setSortingEnabled(true); | ||||
|     ui->main->sortItems(0, Qt::AscendingOrder); | ||||
| } | ||||
| 
 | ||||
| void OptionsDialog::OnSetOptionValue(QTreeWidgetItem* item) { | ||||
|     const auto& options = ui->specificRadioButton->isChecked() ? specific_options : generic_options; | ||||
|     const int id = item->data(1, Qt::UserRole).toInt(); | ||||
|     OptionSetDialog dialog(this, options[id], | ||||
|                            current_values.Get(options[id].name, options[id].default_value)); | ||||
|     if (dialog.exec() != QDialog::DialogCode::Accepted) { | ||||
|         return; | ||||
|     } | ||||
| 
 | ||||
|     const auto& [is_set, value] = dialog.GetCurrentValue(); | ||||
|     if (is_set) { | ||||
|         current_values.Set(options[id].name, value); | ||||
|     } else { | ||||
|         current_values.Erase(options[id].name); | ||||
|     } | ||||
|     item->setText(1, is_set ? QString::fromStdString(value) : tr(UNSET_TEXT)); | ||||
| } | ||||
| 
 | ||||
| std::string OptionsDialog::GetCurrentValue() const { | ||||
|     return current_values.Serialize(); | ||||
| } | ||||
| 
 | ||||
| OptionsDialog::OptionsDialog(QWidget* parent, | ||||
|                              std::vector<VideoDumper::OptionInfo> specific_options_, | ||||
|                              std::vector<VideoDumper::OptionInfo> generic_options_, | ||||
|                              const std::string& current_value) | ||||
|     : QDialog(parent), ui(std::make_unique<Ui::OptionsDialog>()), | ||||
|       specific_options(std::move(specific_options_)), generic_options(std::move(generic_options_)), | ||||
|       current_values(current_value) { | ||||
| 
 | ||||
|     ui->setupUi(this); | ||||
|     PopulateOptions(); | ||||
| 
 | ||||
|     connect(ui->main, &QTreeWidget::itemDoubleClicked, | ||||
|             [this](QTreeWidgetItem* item, int column) { OnSetOptionValue(item); }); | ||||
|     connect(ui->buttonBox, &QDialogButtonBox::accepted, this, &OptionsDialog::accept); | ||||
|     connect(ui->buttonBox, &QDialogButtonBox::rejected, this, &OptionsDialog::reject); | ||||
|     connect(ui->specificRadioButton, &QRadioButton::toggled, this, &OptionsDialog::PopulateOptions); | ||||
| } | ||||
| 
 | ||||
| OptionsDialog::~OptionsDialog() = default; | ||||
							
								
								
									
										36
									
								
								src/citra_qt/dumping/options_dialog.h
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										36
									
								
								src/citra_qt/dumping/options_dialog.h
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,36 @@ | |||
| // Copyright 2020 Citra Emulator Project
 | ||||
| // Licensed under GPLv2 or any later version
 | ||||
| // Refer to the license.txt file included.
 | ||||
| 
 | ||||
| #include <memory> | ||||
| #include <vector> | ||||
| #include <QDialog> | ||||
| #include "common/param_package.h" | ||||
| #include "core/dumping/ffmpeg_backend.h" | ||||
| 
 | ||||
| class QTreeWidgetItem; | ||||
| 
 | ||||
| namespace Ui { | ||||
| class OptionsDialog; | ||||
| } | ||||
| 
 | ||||
| class OptionsDialog : public QDialog { | ||||
|     Q_OBJECT | ||||
| 
 | ||||
| public: | ||||
|     explicit OptionsDialog(QWidget* parent, std::vector<VideoDumper::OptionInfo> specific_options, | ||||
|                            std::vector<VideoDumper::OptionInfo> generic_options, | ||||
|                            const std::string& current_value); | ||||
|     ~OptionsDialog() override; | ||||
| 
 | ||||
|     std::string GetCurrentValue() const; | ||||
| 
 | ||||
| private: | ||||
|     void PopulateOptions(); | ||||
|     void OnSetOptionValue(QTreeWidgetItem* item); | ||||
| 
 | ||||
|     std::unique_ptr<Ui::OptionsDialog> ui; | ||||
|     std::vector<VideoDumper::OptionInfo> specific_options; | ||||
|     std::vector<VideoDumper::OptionInfo> generic_options; | ||||
|     Common::ParamPackage current_values; | ||||
| }; | ||||
							
								
								
									
										71
									
								
								src/citra_qt/dumping/options_dialog.ui
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										71
									
								
								src/citra_qt/dumping/options_dialog.ui
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,71 @@ | |||
| <?xml version="1.0" encoding="UTF-8"?> | ||||
| <ui version="4.0"> | ||||
|  <class>OptionsDialog</class> | ||||
|  <widget class="QDialog" name="OptionsDialog"> | ||||
|   <property name="geometry"> | ||||
|    <rect> | ||||
|     <x>0</x> | ||||
|     <y>0</y> | ||||
|     <width>650</width> | ||||
|     <height>350</height> | ||||
|    </rect> | ||||
|   </property> | ||||
|   <property name="windowTitle"> | ||||
|    <string>Options</string> | ||||
|   </property> | ||||
|   <layout class="QVBoxLayout"> | ||||
|    <item> | ||||
|     <widget class="QLabel"> | ||||
|      <property name="wordWrap"> | ||||
|       <bool>true</bool> | ||||
|      </property> | ||||
|      <property name="text"> | ||||
|       <string>Double click to see the description and change the values of the options.</string> | ||||
|      </property> | ||||
|     </widget> | ||||
|    </item> | ||||
|    <item> | ||||
|     <layout class="QHBoxLayout"> | ||||
|      <item> | ||||
|       <widget class="QRadioButton" name="specificRadioButton"> | ||||
|        <property name="text"> | ||||
|         <string>Specific</string> | ||||
|        </property> | ||||
|        <property name="checked"> | ||||
|         <bool>true</bool> | ||||
|        </property> | ||||
|       </widget> | ||||
|      </item> | ||||
|      <item> | ||||
|       <widget class="QRadioButton" name="genericRadioButton"> | ||||
|        <property name="text"> | ||||
|         <string>Generic</string> | ||||
|        </property> | ||||
|       </widget> | ||||
|      </item> | ||||
|     </layout> | ||||
|    </item> | ||||
|    <item> | ||||
|     <widget class="QTreeWidget" name="main"> | ||||
|      <column> | ||||
|       <property name="text"> | ||||
|        <string>Name</string> | ||||
|       </property> | ||||
|      </column> | ||||
|      <column> | ||||
|       <property name="text"> | ||||
|        <string>Value</string> | ||||
|       </property> | ||||
|      </column> | ||||
|     </widget> | ||||
|    </item> | ||||
|    <item> | ||||
|     <widget class="QDialogButtonBox" name="buttonBox"> | ||||
|      <property name="standardButtons"> | ||||
|       <set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set> | ||||
|      </property> | ||||
|     </widget> | ||||
|    </item> | ||||
|   </layout> | ||||
|  </widget> | ||||
| </ui> | ||||
|  | @ -89,6 +89,10 @@ | |||
| #include "citra_qt/discord_impl.h" | ||||
| #endif | ||||
| 
 | ||||
| #ifdef ENABLE_FFMPEG_VIDEO_DUMPER | ||||
| #include "citra_qt/dumping/dumping_dialog.h" | ||||
| #endif | ||||
| 
 | ||||
| #ifdef QT_STATICPLUGIN | ||||
| Q_IMPORT_PLUGIN(QWindowsIntegrationPlugin); | ||||
| #endif | ||||
|  | @ -100,6 +104,8 @@ __declspec(dllexport) unsigned long NvOptimusEnablement = 0x00000001; | |||
| } | ||||
| #endif | ||||
| 
 | ||||
| constexpr int default_mouse_timeout = 2500; | ||||
| 
 | ||||
| /**
 | ||||
|  * "Callouts" are one-time instructional messages shown to the user. In the config settings, there | ||||
|  * is a bitfield "callout_flags" options, used to track if a message has already been shown to the | ||||
|  | @ -193,6 +199,14 @@ GMainWindow::GMainWindow() : config(new Config()), emu_thread(nullptr) { | |||
|     // Show one-time "callout" messages to the user
 | ||||
|     ShowTelemetryCallout(); | ||||
| 
 | ||||
|     // make sure menubar has the arrow cursor instead of inheriting from this
 | ||||
|     ui.menubar->setCursor(QCursor()); | ||||
|     statusBar()->setCursor(QCursor()); | ||||
| 
 | ||||
|     mouse_hide_timer.setInterval(default_mouse_timeout); | ||||
|     connect(&mouse_hide_timer, &QTimer::timeout, this, &GMainWindow::HideMouseCursor); | ||||
|     connect(ui.menubar, &QMenuBar::hovered, this, &GMainWindow::ShowMouseCursor); | ||||
| 
 | ||||
|     if (UISettings::values.check_for_update_on_start) { | ||||
|         CheckForUpdates(); | ||||
|     } | ||||
|  | @ -713,9 +727,7 @@ void GMainWindow::ConnectMenuEvents() { | |||
|     connect(ui.action_Capture_Screenshot, &QAction::triggered, this, | ||||
|             &GMainWindow::OnCaptureScreenshot); | ||||
| 
 | ||||
| #ifndef ENABLE_FFMPEG_VIDEO_DUMPER | ||||
|     ui.action_Dump_Video->setEnabled(false); | ||||
| #endif | ||||
| #ifdef ENABLE_FFMPEG_VIDEO_DUMPER | ||||
|     connect(ui.action_Dump_Video, &QAction::triggered, [this] { | ||||
|         if (ui.action_Dump_Video->isChecked()) { | ||||
|             OnStartVideoDumping(); | ||||
|  | @ -723,6 +735,9 @@ void GMainWindow::ConnectMenuEvents() { | |||
|             OnStopVideoDumping(); | ||||
|         } | ||||
|     }); | ||||
| #else | ||||
|     ui.action_Dump_Video->setEnabled(false); | ||||
| #endif | ||||
| 
 | ||||
|     // Help
 | ||||
|     connect(ui.action_Open_Citra_Folder, &QAction::triggered, this, | ||||
|  | @ -994,6 +1009,13 @@ void GMainWindow::BootGame(const QString& filename) { | |||
|     } | ||||
|     status_bar_update_timer.start(2000); | ||||
| 
 | ||||
|     if (UISettings::values.hide_mouse) { | ||||
|         mouse_hide_timer.start(); | ||||
|         setMouseTracking(true); | ||||
|         ui.centralwidget->setMouseTracking(true); | ||||
|         ui.menubar->setMouseTracking(true); | ||||
|     } | ||||
| 
 | ||||
|     // show and hide the render_window to create the context
 | ||||
|     render_window->show(); | ||||
|     render_window->hide(); | ||||
|  | @ -1009,8 +1031,14 @@ void GMainWindow::BootGame(const QString& filename) { | |||
|     if (video_dumping_on_start) { | ||||
|         Layout::FramebufferLayout layout{ | ||||
|             Layout::FrameLayoutFromResolutionScale(VideoCore::GetResolutionScaleFactor())}; | ||||
|         Core::System::GetInstance().VideoDumper().StartDumping(video_dumping_path.toStdString(), | ||||
|                                                                "webm", layout); | ||||
|         if (!Core::System::GetInstance().VideoDumper().StartDumping( | ||||
|                 video_dumping_path.toStdString(), layout)) { | ||||
| 
 | ||||
|             QMessageBox::critical( | ||||
|                 this, tr("Citra"), | ||||
|                 tr("Could not start video dumping.<br>Refer to the log for details.")); | ||||
|             ui.action_Dump_Video->setChecked(false); | ||||
|         } | ||||
|         video_dumping_on_start = false; | ||||
|         video_dumping_path.clear(); | ||||
|     } | ||||
|  | @ -1026,11 +1054,13 @@ void GMainWindow::ShutdownGame() { | |||
|         HideFullscreen(); | ||||
|     } | ||||
| 
 | ||||
| #ifdef ENABLE_FFMPEG_VIDEO_DUMPER | ||||
|     if (Core::System::GetInstance().VideoDumper().IsDumping()) { | ||||
|         game_shutdown_delayed = true; | ||||
|         OnStopVideoDumping(); | ||||
|         return; | ||||
|     } | ||||
| #endif | ||||
| 
 | ||||
|     AllowOSSleep(); | ||||
| 
 | ||||
|  | @ -1084,6 +1114,10 @@ void GMainWindow::ShutdownGame() { | |||
|         game_list->show(); | ||||
|     game_list->setFilterFocus(); | ||||
| 
 | ||||
|     setMouseTracking(false); | ||||
|     ui.centralwidget->setMouseTracking(false); | ||||
|     ui.menubar->setMouseTracking(false); | ||||
| 
 | ||||
|     // Disable status bar updates
 | ||||
|     status_bar_update_timer.stop(); | ||||
|     message_label->setVisible(false); | ||||
|  | @ -1290,7 +1324,7 @@ void GMainWindow::OnGameListDumpRomFS(QString game_path, u64 program_id) { | |||
|     using FutureWatcher = QFutureWatcher<std::pair<Loader::ResultStatus, Loader::ResultStatus>>; | ||||
|     auto* future_watcher = new FutureWatcher(this); | ||||
|     connect(future_watcher, &FutureWatcher::finished, | ||||
|             [this, program_id, dialog, base_path, update_path, future_watcher] { | ||||
|             [this, dialog, base_path, update_path, future_watcher] { | ||||
|                 dialog->hide(); | ||||
|                 const auto& [base, update] = future_watcher->result(); | ||||
|                 if (base != Loader::ResultStatus::Success) { | ||||
|  | @ -1676,6 +1710,16 @@ void GMainWindow::OnConfigure() { | |||
|         SyncMenuUISettings(); | ||||
|         game_list->RefreshGameDirectory(); | ||||
|         config->Save(); | ||||
|         if (UISettings::values.hide_mouse && emulation_running) { | ||||
|             setMouseTracking(true); | ||||
|             ui.centralwidget->setMouseTracking(true); | ||||
|             ui.menubar->setMouseTracking(true); | ||||
|             mouse_hide_timer.start(); | ||||
|         } else { | ||||
|             setMouseTracking(false); | ||||
|             ui.centralwidget->setMouseTracking(false); | ||||
|             ui.menubar->setMouseTracking(false); | ||||
|         } | ||||
|     } else { | ||||
|         Settings::values.input_profiles = old_input_profiles; | ||||
|         Settings::LoadProfile(old_input_profile_index); | ||||
|  | @ -1915,18 +1959,23 @@ void GMainWindow::OnCaptureScreenshot() { | |||
|     OnStartGame(); | ||||
| } | ||||
| 
 | ||||
| #ifdef ENABLE_FFMPEG_VIDEO_DUMPER | ||||
| void GMainWindow::OnStartVideoDumping() { | ||||
|     const QString path = QFileDialog::getSaveFileName( | ||||
|         this, tr("Save Video"), UISettings::values.video_dumping_path, tr("WebM Videos (*.webm)")); | ||||
|     if (path.isEmpty()) { | ||||
|     DumpingDialog dialog(this); | ||||
|     if (dialog.exec() != QDialog::DialogCode::Accepted) { | ||||
|         ui.action_Dump_Video->setChecked(false); | ||||
|         return; | ||||
|     } | ||||
|     UISettings::values.video_dumping_path = QFileInfo(path).path(); | ||||
|     const auto path = dialog.GetFilePath(); | ||||
|     if (emulation_running) { | ||||
|         Layout::FramebufferLayout layout{ | ||||
|             Layout::FrameLayoutFromResolutionScale(VideoCore::GetResolutionScaleFactor())}; | ||||
|         Core::System::GetInstance().VideoDumper().StartDumping(path.toStdString(), "webm", layout); | ||||
|         if (!Core::System::GetInstance().VideoDumper().StartDumping(path.toStdString(), layout)) { | ||||
|             QMessageBox::critical( | ||||
|                 this, tr("Citra"), | ||||
|                 tr("Could not start video dumping.<br>Refer to the log for details.")); | ||||
|             ui.action_Dump_Video->setChecked(false); | ||||
|         } | ||||
|     } else { | ||||
|         video_dumping_on_start = true; | ||||
|         video_dumping_path = path; | ||||
|  | @ -1943,6 +1992,8 @@ void GMainWindow::OnStopVideoDumping() { | |||
|         const bool was_dumping = Core::System::GetInstance().VideoDumper().IsDumping(); | ||||
|         if (!was_dumping) | ||||
|             return; | ||||
| 
 | ||||
|         game_paused_for_dumping = emu_thread->IsRunning(); | ||||
|         OnPauseGame(); | ||||
| 
 | ||||
|         auto future = | ||||
|  | @ -1952,13 +2003,15 @@ void GMainWindow::OnStopVideoDumping() { | |||
|             if (game_shutdown_delayed) { | ||||
|                 game_shutdown_delayed = false; | ||||
|                 ShutdownGame(); | ||||
|             } else { | ||||
|             } else if (game_paused_for_dumping) { | ||||
|                 game_paused_for_dumping = false; | ||||
|                 OnStartGame(); | ||||
|             } | ||||
|         }); | ||||
|         future_watcher->setFuture(future); | ||||
|     } | ||||
| } | ||||
| #endif | ||||
| 
 | ||||
| void GMainWindow::UpdateStatusBar() { | ||||
|     if (emu_thread == nullptr) { | ||||
|  | @ -1983,6 +2036,30 @@ void GMainWindow::UpdateStatusBar() { | |||
|     emu_frametime_label->setVisible(true); | ||||
| } | ||||
| 
 | ||||
| void GMainWindow::HideMouseCursor() { | ||||
|     if (emu_thread == nullptr || UISettings::values.hide_mouse == false) { | ||||
|         mouse_hide_timer.stop(); | ||||
|         ShowMouseCursor(); | ||||
|         return; | ||||
|     } | ||||
|     setCursor(QCursor(Qt::BlankCursor)); | ||||
| } | ||||
| 
 | ||||
| void GMainWindow::ShowMouseCursor() { | ||||
|     unsetCursor(); | ||||
|     if (emu_thread != nullptr && UISettings::values.hide_mouse) { | ||||
|         mouse_hide_timer.start(); | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| void GMainWindow::mouseMoveEvent(QMouseEvent* event) { | ||||
|     ShowMouseCursor(); | ||||
| } | ||||
| 
 | ||||
| void GMainWindow::mousePressEvent(QMouseEvent* event) { | ||||
|     ShowMouseCursor(); | ||||
| } | ||||
| 
 | ||||
| void GMainWindow::OnCoreError(Core::System::ResultStatus result, std::string details) { | ||||
|     QString status_message; | ||||
| 
 | ||||
|  |  | |||
|  | @ -207,8 +207,10 @@ private slots: | |||
|     void OnPlayMovie(); | ||||
|     void OnStopRecordingPlayback(); | ||||
|     void OnCaptureScreenshot(); | ||||
| #ifdef ENABLE_FFMPEG_VIDEO_DUMPER | ||||
|     void OnStartVideoDumping(); | ||||
|     void OnStopVideoDumping(); | ||||
| #endif | ||||
|     void OnCoreError(Core::System::ResultStatus, std::string); | ||||
|     /// Called whenever a user selects Help->About Citra
 | ||||
|     void OnMenuAboutCitra(); | ||||
|  | @ -225,6 +227,8 @@ private: | |||
|     void UpdateWindowTitle(); | ||||
|     void RetranslateStatusBar(); | ||||
|     void InstallCIA(QStringList filepaths); | ||||
|     void HideMouseCursor(); | ||||
|     void ShowMouseCursor(); | ||||
| 
 | ||||
|     Ui::MainWindow ui; | ||||
| 
 | ||||
|  | @ -253,6 +257,7 @@ private: | |||
|     QString game_path; | ||||
| 
 | ||||
|     bool auto_paused = false; | ||||
|     QTimer mouse_hide_timer; | ||||
| 
 | ||||
|     // Movie
 | ||||
|     bool movie_record_on_start = false; | ||||
|  | @ -263,6 +268,8 @@ private: | |||
|     QString video_dumping_path; | ||||
|     // Whether game shutdown is delayed due to video dumping
 | ||||
|     bool game_shutdown_delayed = false; | ||||
|     // Whether game was paused due to stopping video dumping
 | ||||
|     bool game_paused_for_dumping = false; | ||||
| 
 | ||||
|     // Debugger panes
 | ||||
|     ProfilerWidget* profilerWidget; | ||||
|  | @ -301,6 +308,8 @@ protected: | |||
|     void dropEvent(QDropEvent* event) override; | ||||
|     void dragEnterEvent(QDragEnterEvent* event) override; | ||||
|     void dragMoveEvent(QDragMoveEvent* event) override; | ||||
|     void mouseMoveEvent(QMouseEvent* event) override; | ||||
|     void mousePressEvent(QMouseEvent* event) override; | ||||
| }; | ||||
| 
 | ||||
| Q_DECLARE_METATYPE(std::size_t); | ||||
|  |  | |||
|  | @ -76,6 +76,7 @@ struct Values { | |||
|     bool confirm_before_closing; | ||||
|     bool first_start; | ||||
|     bool pause_when_in_background; | ||||
|     bool hide_mouse; | ||||
| 
 | ||||
|     bool updater_found; | ||||
|     bool update_on_close; | ||||
|  |  | |||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue