File indexing completed on 2024-04-28 04:52:04
0001 /* 0002 SPDX-FileCopyrightText: 2015 Meltytech LLC 0003 SPDX-FileCopyrightText: 2015 Brian Matherly <code@brianmatherly.com> 0004 0005 SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-KDE-Accepted-GPL 0006 */ 0007 0008 #pragma once 0009 0010 #include "dataqueue.h" 0011 #include "sharedframe.h" 0012 #include <QFuture> 0013 #include <QMutex> 0014 #include <QString> 0015 #include <QThread> 0016 #include <QWidget> 0017 0018 /*! 0019 \class ScopeWidget 0020 \brief The ScopeWidget provides a common interface for all scopes in Shotcut. 0021 0022 ScopeWidget is a QWidget that provides some additional functionality that is 0023 common to all scopes. One common function is a queue that can receive and 0024 store frames until they can be processed by the scope. Another common function 0025 is the ability to trigger the "heavy lifting" to be done in a worker thread. 0026 0027 Frames are received by the onNewFrame() slot. The ScopeWidget automatically 0028 places new frames in the DataQueue (m_queue). Subclasses shall implement the 0029 refreshScope() function and can check for new frames in m_queue. 0030 0031 refreshScope() is run from a separate thread. Therefore, any members that are 0032 accessed by both the worker thread (refreshScope) and the GUI thread 0033 (paintEvent(), resizeEvent(), etc) must be protected by a mutex. After the 0034 refreshScope() function returns, the ScopeWidget will automatically request 0035 the GUI thread to update(). A well implemented ScopeWidget will be designed 0036 such that most of the CPU intensive work will be done in refreshScope() and 0037 the paintEvent() implementation will complete quickly to avoid hanging up the 0038 GUI thread. 0039 0040 Subclasses shall also implement getTitle() so that the application can display 0041 an appropriate title for the scope. 0042 */ 0043 0044 class ScopeWidget : public QWidget 0045 { 0046 Q_OBJECT 0047 0048 public: 0049 /*! 0050 Constructs an ScopeWidget. 0051 0052 The \a name will be set as the objectName and should be initialized by 0053 subclasses. 0054 */ 0055 explicit ScopeWidget(QWidget *parent = nullptr); 0056 0057 //! Destructs a ScopeWidget. 0058 ~ScopeWidget() override; 0059 0060 /*! 0061 Returns the title of the scope to be displayed by the application. 0062 This virtual function must be implemented by subclasses. 0063 */ 0064 // virtual QString getTitle() = 0; 0065 0066 /*! 0067 Sets the preferred orientation on the scope. 0068 This virtual function may be reimplemented by subclasses. 0069 */ 0070 // virtual void setOrientation(Qt::Orientation) {}; 0071 0072 public Q_SLOTS: 0073 //! Provides a new frame to the scope. Should be called by the application. 0074 void onNewFrame(const SharedFrame &frame); 0075 0076 protected: 0077 /*! 0078 Triggers refreshScope() to be called in a new thread context. 0079 Typically requestRefresh would be called from the GUI thread 0080 (e.g. in resizeEvent()). onNewFrame() also calls requestRefresh(). 0081 */ 0082 void requestRefresh(); 0083 0084 /*! 0085 Performs the main, CPU intensive, scope drawing in a new thread. 0086 0087 refreshScope() Shall be implemented by subclasses. Care must be taken to 0088 protect any members that may be accessed concurrently by the refresh 0089 thread and the GUI thread. 0090 */ 0091 virtual void refreshScope(const QSize &size, bool full) = 0; 0092 0093 /*! 0094 Stores frames received by onNewFrame(). 0095 0096 Subclasses should check this queue for new frames in the refreshScope() 0097 implementation. 0098 */ 0099 DataQueue<SharedFrame> m_queue; 0100 0101 void resizeEvent(QResizeEvent *) override; 0102 void changeEvent(QEvent *) override; 0103 0104 private: 0105 Q_INVOKABLE void onRefreshThreadComplete(); 0106 void refreshInThread(); 0107 QFuture<void> m_future; 0108 bool m_refreshPending{false}; 0109 0110 // Members accessed in multiple threads (mutex protected). 0111 QMutex m_mutex; 0112 bool m_forceRefresh{false}; 0113 QSize m_size; 0114 };