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 };