mirror of
				https://github.com/dolphin-emu/dolphin.git
				synced 2025-10-25 01:19:19 +00:00 
			
		
		
		
	
		
			
				
	
	
		
			131 lines
		
	
	
	
		
			4.6 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			131 lines
		
	
	
	
		
			4.6 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
| // Copyright 2020 Dolphin Emulator Project
 | |
| // SPDX-License-Identifier: GPL-2.0-or-later
 | |
| 
 | |
| #pragma once
 | |
| 
 | |
| #include <utility>
 | |
| 
 | |
| #include <QObject>
 | |
| #include <QProgressDialog>
 | |
| #include <QString>
 | |
| 
 | |
| #include "Common/Flag.h"
 | |
| 
 | |
| class ParallelProgressDialog final : public QObject
 | |
| {
 | |
|   Q_OBJECT
 | |
| 
 | |
| public:
 | |
|   ParallelProgressDialog(const ParallelProgressDialog&) = delete;
 | |
|   ParallelProgressDialog& operator=(const ParallelProgressDialog&) = delete;
 | |
|   ParallelProgressDialog(ParallelProgressDialog&&) = delete;
 | |
|   ParallelProgressDialog& operator=(ParallelProgressDialog&&) = delete;
 | |
| 
 | |
|   // Only use this from the main thread
 | |
|   template <typename... Args>
 | |
|   ParallelProgressDialog(Args&&... args) : m_dialog{std::forward<Args>(args)...}
 | |
|   {
 | |
|     setParent(m_dialog.parent());
 | |
|     m_dialog.setWindowFlags(m_dialog.windowFlags() & ~Qt::WindowContextHelpButtonHint);
 | |
|     ConnectSignalsAndSlots();
 | |
|   }
 | |
| 
 | |
|   // Only use this from the main thread
 | |
|   QProgressDialog* GetRaw() { return &m_dialog; }
 | |
| 
 | |
|   // All of the following can be called from any thread
 | |
|   void Cancel() { emit CancelSignal(); }
 | |
|   void Reset() { emit ResetSignal(); }
 | |
|   void SetCancelButtonText(const QString& text) { emit SetCancelButtonTextSignal(text); }
 | |
|   void SetLabelText(const QString& text) { emit SetLabelTextSignal(text); }
 | |
|   void SetMaximum(int maximum) { emit SetMaximumSignal(maximum); }
 | |
|   void SetMinimum(int minimum) { emit SetMinimumSignal(minimum); }
 | |
|   void SetMinimumDuration(int ms) { emit SetMinimumDurationSignal(ms); }
 | |
|   void SetRange(int minimum, int maximum) { emit SetRangeSignal(minimum, maximum); }
 | |
|   void SetValue(int progress) { emit SetValueSignal(progress); }
 | |
| 
 | |
|   // Can be called from any thread
 | |
|   bool WasCanceled() const { return m_was_cancelled.IsSet(); }
 | |
| 
 | |
| signals:
 | |
|   void CancelSignal();
 | |
|   void ResetSignal();
 | |
|   void SetCancelButtonTextSignal(const QString& cancel_button_text);
 | |
|   void SetLabelTextSignal(const QString& text);
 | |
|   void SetMaximumSignal(int maximum);
 | |
|   void SetMinimumSignal(int minimum);
 | |
|   void SetMinimumDurationSignal(int ms);
 | |
|   void SetRangeSignal(int minimum, int maximum);
 | |
|   void SetValueSignal(int progress);
 | |
| 
 | |
|   void Canceled();
 | |
|   void Finished(int result);
 | |
| 
 | |
| private slots:
 | |
|   void OnCancelled() { m_was_cancelled.Set(); }
 | |
| 
 | |
|   void SetValueSlot(int progress)
 | |
|   {
 | |
|     // Normally we would've been able to just call setValue instead of having this wrapper
 | |
|     // around it, but due to the https://bugreports.qt.io/browse/QTBUG-10561 stack overflow,
 | |
|     // we can't. Short summary of the stack overflow: setValue calls processEvents,
 | |
|     // which calls SetValueSlot if there is another SetValueSlot event in the queue,
 | |
|     // which would call setValue if it wasn't for the check below, and so on.
 | |
| 
 | |
|     m_last_received_progress = progress;
 | |
| 
 | |
|     if (m_is_setting_value)
 | |
|       return;
 | |
| 
 | |
|     m_is_setting_value = true;
 | |
| 
 | |
|     int last_set_progress;
 | |
|     do
 | |
|     {
 | |
|       last_set_progress = m_last_received_progress;
 | |
|       m_dialog.setValue(m_last_received_progress);
 | |
|     } while (m_last_received_progress != last_set_progress);
 | |
| 
 | |
|     m_is_setting_value = false;
 | |
|   }
 | |
| 
 | |
| private:
 | |
|   template <typename Func1, typename Func2>
 | |
|   void ConnectSignal(Func1 signal, Func2 slot)
 | |
|   {
 | |
|     QObject::connect(this, signal, &m_dialog, slot);
 | |
|   }
 | |
| 
 | |
|   template <typename Func1, typename Func2>
 | |
|   void ConnectSlot(Func1 signal, Func2 slot)
 | |
|   {
 | |
|     QObject::connect(&m_dialog, signal, this, slot);
 | |
|   }
 | |
| 
 | |
|   void ConnectSignalsAndSlots()
 | |
|   {
 | |
|     ConnectSignal(&ParallelProgressDialog::CancelSignal, &QProgressDialog::cancel);
 | |
|     ConnectSignal(&ParallelProgressDialog::ResetSignal, &QProgressDialog::reset);
 | |
|     ConnectSignal(&ParallelProgressDialog::SetCancelButtonTextSignal,
 | |
|                   &QProgressDialog::setCancelButtonText);
 | |
|     ConnectSignal(&ParallelProgressDialog::SetLabelTextSignal, &QProgressDialog::setLabelText);
 | |
|     ConnectSignal(&ParallelProgressDialog::SetMaximumSignal, &QProgressDialog::setMaximum);
 | |
|     ConnectSignal(&ParallelProgressDialog::SetMinimumSignal, &QProgressDialog::setMinimum);
 | |
|     ConnectSignal(&ParallelProgressDialog::SetMinimumDurationSignal,
 | |
|                   &QProgressDialog::setMinimumDuration);
 | |
|     ConnectSignal(&ParallelProgressDialog::SetRangeSignal, &QProgressDialog::setRange);
 | |
| 
 | |
|     QObject::connect(this, &ParallelProgressDialog::SetValueSignal, this,
 | |
|                      &ParallelProgressDialog::SetValueSlot);
 | |
| 
 | |
|     ConnectSlot(&QProgressDialog::canceled, &ParallelProgressDialog::OnCancelled);
 | |
| 
 | |
|     ConnectSlot(&QProgressDialog::canceled, &ParallelProgressDialog::Canceled);
 | |
|     ConnectSlot(&QProgressDialog::finished, &ParallelProgressDialog::Finished);
 | |
|   }
 | |
| 
 | |
|   QProgressDialog m_dialog;
 | |
|   Common::Flag m_was_cancelled;
 | |
|   int m_last_received_progress = 0;
 | |
|   bool m_is_setting_value = false;
 | |
| };
 |