* Scopes (Waveform, Vectorscope, Parades, etc.) can inherit from AbstractScopeWidget
* Takes care of widget appearance (like colors)
* Manages multi-threading
* Will manage realtime updates and other things that make sense
Waveform is already inheriting from AbstractScopeWidget.
svn path=/trunk/kdenlive/; revision=4602
widgets/vectorscope_ui.ui
widgets/colorplaneexport_ui.ui
widgets/waveform_ui.ui
+ widgets/testwidget_ui.ui
)
set(kdenlive_SRCS
timecodedisplay.cpp
tracksconfigdialog.cpp
configtrackscommand.cpp
+ abstractscopewidget.cpp
vectorscope.cpp
colorplaneexport.cpp
colortools.cpp
rebuildgroupcommand.cpp
waveform.cpp
colorcorrection/waveformgenerator.cpp
+ testwidget.cpp
)
--- /dev/null
+/***************************************************************************
+ * Copyright (C) 2010 by Simon Andreas Eugster (simon.eu@gmail.com) *
+ * This file is part of kdenlive. See www.kdenlive.org. *
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ ***************************************************************************/
+
+#include "qtconcurrentrun.h"
+
+#include "abstractscopewidget.h"
+#include "renderer.h"
+#include "monitor.h"
+
+#include <QFuture>
+#include <QColor>
+#include <QDebug>
+#include <QMenu>
+#include <QPainter>
+
+const QColor light(250, 238, 226, 255);
+const QColor dark ( 40, 40, 39, 255);
+const QColor dark2( 25, 25, 23, 255);
+
+AbstractScopeWidget::AbstractScopeWidget(Monitor *projMonitor, Monitor *clipMonitor, QWidget *parent) :
+ QWidget(parent),
+ m_projMonitor(projMonitor),
+ m_clipMonitor(clipMonitor),
+ offset(5),
+ m_semaphoreHUD(1),
+ m_semaphoreScope(1),
+ m_semaphoreBackground(1)
+
+{
+ m_scopePalette = QPalette();
+ m_scopePalette.setBrush(QPalette::Window, QBrush(dark2));
+ m_scopePalette.setBrush(QPalette::Base, QBrush(dark));
+ m_scopePalette.setBrush(QPalette::Button, QBrush(dark));
+ m_scopePalette.setBrush(QPalette::Text, QBrush(light));
+ m_scopePalette.setBrush(QPalette::WindowText, QBrush(light));
+ m_scopePalette.setBrush(QPalette::ButtonText, QBrush(light));
+ this->setPalette(m_scopePalette);
+ this->setAutoFillBackground(true);
+
+ m_aAutoRefresh = new QAction(i18n("Auto Refresh"), this);
+ m_aAutoRefresh->setCheckable(true);
+ m_aRealtime = new QAction(i18n("Realtime (with precision loss)"), this);
+ m_aRealtime->setCheckable(true);
+
+ m_menu = new QMenu(this);
+ m_menu->setPalette(m_scopePalette);
+ m_menu->addAction(m_aAutoRefresh);
+ m_menu->addAction(m_aRealtime);
+
+ this->setContextMenuPolicy(Qt::CustomContextMenu);
+
+ if (m_projMonitor->isActive()) {
+ m_activeRender = m_projMonitor->render;
+ } else {
+ m_activeRender = m_clipMonitor->render;
+ }
+
+ connect(m_activeRender, SIGNAL(rendererPosition(int)), this, SLOT(slotRenderZoneUpdated()));
+ connect(this, SIGNAL(customContextMenuRequested(QPoint)), this, SLOT(customContextMenuRequested(QPoint)));
+ connect(this, SIGNAL(signalScopeRenderingFinished()), this, SLOT(slotScopeRenderingFinished()));
+
+
+}
+
+AbstractScopeWidget::~AbstractScopeWidget()
+{
+ delete m_menu;
+ delete m_aAutoRefresh;
+}
+
+void AbstractScopeWidget::prodScopeThread()
+{
+ if (m_semaphoreScope.tryAcquire(1)) {
+ Q_ASSERT(!m_threadScope.isRunning());
+
+ m_threadScope = QtConcurrent::run(this, &AbstractScopeWidget::renderScope);
+ qDebug() << "Scope thread started in " << widgetName();
+
+ } else {
+ qDebug() << "Scope semaphore locked, not prodding in " << widgetName() << ". Thread running: " << m_threadScope.isRunning();
+ }
+}
+
+
+///// Events /////
+
+void AbstractScopeWidget::mouseReleaseEvent(QMouseEvent *event)
+{
+ // TODO Render again
+ prodScopeThread();
+ QWidget::mouseReleaseEvent(event);
+}
+
+void AbstractScopeWidget::resizeEvent(QResizeEvent *event)
+{
+ // Update the dimension of the available rect for painting
+ m_scopeRect = scopeRect();
+
+ m_newHUDUpdates.fetchAndAddRelaxed(1);
+ m_newScopeUpdates.fetchAndAddRelaxed(1);
+ m_newBackgroundUpdates.fetchAndAddRelaxed(1);
+
+ QWidget::resizeEvent(event);
+ // TODO Calculation
+}
+
+void AbstractScopeWidget::paintEvent(QPaintEvent *)
+{
+ QPainter davinci(this);
+ davinci.drawImage(scopeRect().topLeft(), m_imgBackground);
+ davinci.drawImage(scopeRect().topLeft(), m_imgScope);
+ davinci.drawImage(scopeRect().topLeft(), m_imgHUD);
+ davinci.fillRect(scopeRect(), QBrush(QColor(200, 100, 0, 16)));
+}
+
+void AbstractScopeWidget::customContextMenuRequested(const QPoint &pos)
+{
+ m_menu->exec(this->mapToGlobal(pos));
+}
+
+
+///// Slots /////
+
+void AbstractScopeWidget::slotHUDRenderingFinished()
+{
+
+}
+
+void AbstractScopeWidget::slotScopeRenderingFinished()
+{
+ qDebug() << "Scope rendering has finished, waiting for termination in " << widgetName();
+ m_threadScope.waitForFinished();
+ m_imgScope = m_threadScope.result();
+ m_semaphoreScope.release(1);
+ this->update();
+}
+
+void AbstractScopeWidget::slotBackgroundRenderingFinished()
+{
+
+}
+
+void AbstractScopeWidget::slotActiveMonitorChanged(bool isClipMonitor)
+{
+ if (isClipMonitor) {
+ m_activeRender = m_clipMonitor->render;
+ disconnect(this, SLOT(slotRenderZoneUpdated()));
+ connect(m_activeRender, SIGNAL(rendererPosition(int)), this, SLOT(slotRenderZoneUpdated()));
+ } else {
+ m_activeRender = m_projMonitor->render;
+ disconnect(this, SLOT(slotRenderZoneUpdated()));
+ connect(m_activeRender, SIGNAL(rendererPosition(int)), this, SLOT(slotRenderZoneUpdated()));
+ }
+}
+
+void AbstractScopeWidget::slotRenderZoneUpdated()
+{
+ m_newHUDFrames.fetchAndAddRelaxed(1);
+ m_newScopeFrames.fetchAndAddRelaxed(1);
+ m_newBackgroundFrames.fetchAndAddRelaxed(1);
+
+ qDebug() << "Monitor incoming. New frames total HUD/Scope/Background: " << m_newHUDFrames
+ << "/" << m_newScopeFrames << "/" << m_newBackgroundFrames;
+
+ if (this->visibleRegion().isEmpty()) {
+ qDebug() << "Scope of widget " << widgetName() << " is not at the top, not rendering.";
+ } else {
+ if (m_aAutoRefresh->isChecked()) {
+ // TODO run the updater functions here.
+ }
+ }
+}
--- /dev/null
+/***************************************************************************
+ * Copyright (C) 2010 by Simon Andreas Eugster (simon.eu@gmail.com) *
+ * This file is part of kdenlive. See www.kdenlive.org. *
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ ***************************************************************************/
+
+/**
+ _____________________
+ / \
+ / HUD Layer \
+ / \
+ ---------------------------
+ _____________________
+ / \
+ / Scope Layer \
+ / \
+ ---------------------------
+ _____________________
+ / \
+ / Background Layer \
+ / \
+ ---------------------------
+ */
+
+#ifndef ABSTRACTSCOPEWIDGET_H
+#define ABSTRACTSCOPEWIDGET_H
+
+#include <QtCore>
+#include <QWidget>
+
+class QMenu;
+
+class Monitor;
+class Render;
+
+class AbstractScopeWidget : public QWidget
+{
+ Q_OBJECT
+
+public:
+ AbstractScopeWidget(Monitor *projMonitor, Monitor *clipMonitor, QWidget *parent = 0);
+ virtual ~AbstractScopeWidget(); // Must be virtual because of inheritance, to avoid memory leaks
+ QPalette m_scopePalette;
+
+ virtual QString widgetName() const = 0;
+
+protected:
+ ///// Variables /////
+
+ Monitor *m_projMonitor;
+ Monitor *m_clipMonitor;
+ Render *m_activeRender;
+
+ QMenu *m_menu;
+ QAction *m_aAutoRefresh;
+ QAction *m_aRealtime;
+
+ /** Offset from the widget's borders */
+ const uchar offset;
+
+ QRect m_scopeRect;
+ QImage m_imgHUD;
+ QImage m_imgScope;
+ QImage m_imgBackground;
+
+ /** Counts the number of frames that have been rendered in the active monitor.
+ The frame number will be reset when the calculation starts for the current frame. */
+ QAtomicInt m_newHUDFrames;
+ QAtomicInt m_newScopeFrames;
+ QAtomicInt m_newBackgroundFrames;
+
+ /** Counts the number of updates that, unlike new frames, force a recalculation
+ of the scope, like for example a resize event. */
+ QAtomicInt m_newHUDUpdates;
+ QAtomicInt m_newScopeUpdates;
+ QAtomicInt m_newBackgroundUpdates;
+
+ QFuture<QImage> m_threadHUD;
+ QFuture<QImage> m_threadScope;
+ QFuture<QImage> m_threadBackground;
+
+ QSemaphore m_semaphoreHUD;
+ QSemaphore m_semaphoreScope;
+ QSemaphore m_semaphoreBackground;
+
+
+ ///// Unimplemented Methods /////
+
+ /** Where on the widget we can paint in */
+ virtual QRect scopeRect() = 0;
+
+ /** HUD renderer. Must emit signalHUDRenderingFinished(). */
+ virtual QImage renderHUD() = 0;
+ /** Scope renderer. Must emit signalScopeRenderingFinished(). */
+ virtual QImage renderScope() = 0;
+ /** Background renderer. Must emit signalBackgroundRenderingFinished(). */
+ virtual QImage renderBackground() = 0;
+
+ ///// Methods /////
+
+ void mouseReleaseEvent(QMouseEvent *);
+ void paintEvent(QPaintEvent *);
+ void resizeEvent(QResizeEvent *);
+
+
+protected slots:
+ /** Called when the active monitor has shown a new frame. */
+ void slotRenderZoneUpdated();
+ void slotHUDRenderingFinished();
+ void slotScopeRenderingFinished();
+ void slotBackgroundRenderingFinished();
+
+signals:
+ void signalHUDRenderingFinished();
+ void signalScopeRenderingFinished();
+ void signalBackgroundRenderingFinished();
+
+private:
+ void prodScopeThread();
+
+private slots:
+ void customContextMenuRequested(const QPoint &pos);
+ void slotActiveMonitorChanged(bool isClipMonitor);
+
+};
+
+#endif // ABSTRACTSCOPEWIDGET_H
#include "ui_templateclip_ui.h"
#include "vectorscope.h"
#include "waveform.h"
+#include "testwidget.h"
#include <KApplication>
#include <KAction>
m_waveformDock->setWidget(m_waveform);
addDockWidget(Qt::TopDockWidgetArea, m_waveformDock);
+ m_test = new TestWidget(m_projectMonitor, m_clipMonitor, this);
+ m_testDock = new QDockWidget("Test", this);
+ m_testDock->setObjectName("test");
+ m_testDock->setWidget(m_test);
+ addDockWidget(Qt::TopDockWidgetArea, m_testDock);
+
m_undoViewDock = new QDockWidget(i18n("Undo History"), this);
m_undoViewDock->setObjectName("undo_history");
class Transition;
class Vectorscope;
class Waveform;
+class TestWidget;
class KActionCollection;
class MainWindow : public KXmlGuiWindow
QDockWidget *m_waveformDock;
Waveform *m_waveform;
+ QDockWidget *m_testDock;
+ TestWidget *m_test;
+
QDockWidget *m_undoViewDock;
QUndoView *m_undoView;
QUndoGroup *m_commandStack;
--- /dev/null
+/***************************************************************************
+ * Copyright (C) 2010 by Simon Andreas Eugster (simon.eu@gmail.com) *
+ * This file is part of kdenlive. See www.kdenlive.org. *
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ ***************************************************************************/
+
+#include "testwidget.h"
+#include "ui_testwidget_ui.h"
+
+#include <QMenu>
+#include <QDebug>
+
+TestWidget::TestWidget(Monitor *projMonitor, Monitor *clipMonitor, QWidget *parent) :
+ AbstractScopeWidget(projMonitor, clipMonitor, parent)
+{
+ ui = new Ui::TestWidget_UI();
+ ui->setupUi(this);
+
+ m_aTest = new QAction("Hallo. ", this);
+ m_menu->addAction(m_aTest);
+}
+
+TestWidget::~TestWidget()
+{
+ delete ui;
+ delete m_aTest;
+}
+
+///// Implemented Methods /////
+
+QImage TestWidget::renderHUD()
+{
+ emit signalHUDRenderingFinished();
+ return QImage();
+}
+
+QImage TestWidget::renderScope()
+{
+ emit signalScopeRenderingFinished();
+ return QImage();
+}
+
+QImage TestWidget::renderBackground()
+{
+ emit signalBackgroundRenderingFinished();
+ return QImage();
+}
+
+
+QRect TestWidget::scopeRect()
+{
+ return QRect(QPoint(offset, ui->line->y() + 2*offset), this->rect().bottomRight() - QPoint(offset, offset));
+}
+
+QString TestWidget::widgetName() const
+{
+ return "Testwidget";
+}
--- /dev/null
+/***************************************************************************
+ * Copyright (C) 2010 by Simon Andreas Eugster (simon.eu@gmail.com) *
+ * This file is part of kdenlive. See www.kdenlive.org. *
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ ***************************************************************************/
+
+#ifndef TESTWIDGET_H
+#define TESTWIDGET_H
+
+#include <QWidget>
+#include "abstractscopewidget.h"
+#include "ui_testwidget_ui.h"
+
+class AbstractScopeWidget;
+class TestWidget_UI;
+
+class TestWidget : public AbstractScopeWidget {
+ Q_OBJECT
+public:
+ TestWidget(Monitor *projMonitor, Monitor *clipMonitor, QWidget *parent = 0);
+ virtual ~TestWidget();
+
+ QString widgetName() const;
+
+ /// Implemented methods ///
+ QImage renderHUD();
+ QImage renderScope();
+ QImage renderBackground();
+
+protected:
+ QRect scopeRect();
+
+private:
+ Ui::TestWidget_UI *ui;
+
+ QAction *m_aTest;
+
+};
+
+#endif // TESTWIDGET_H
#include <QPoint>
#include <QDebug>
+#include "renderer.h"
#include "waveform.h"
+#include "waveformgenerator.h"
Waveform::Waveform(Monitor *projMonitor, Monitor *clipMonitor, QWidget *parent) :
- QWidget(parent),
- m_projMonitor(projMonitor),
- m_clipMonitor(clipMonitor),
- m_activeRender(clipMonitor->render),
+ AbstractScopeWidget(projMonitor, clipMonitor, parent),
initialDimensionUpdateDone(false)
{
- setupUi(this);
+ ui = new Ui::Waveform_UI();
+ ui->setupUi(this);
+
m_waveformGenerator = new WaveformGenerator();
connect(m_waveformGenerator, SIGNAL(signalCalculationFinished(QImage,uint)), this, SLOT(slotWaveformCalculated(QImage,uint)));
-void Waveform::updateDimensions()
+QRect Waveform::scopeRect()
{
// Distance from top/left/right
int offset = 6;
- QPoint topleft(offset, line->y()+offset);
+ QPoint topleft(offset, ui->line->y()+offset);
+
+ return QRect(topleft, this->size() - QSize(offset+topleft.x(), offset+topleft.y()));
+}
+
+QString Waveform::widgetName() const
+{
+ return QString("Waveform");
+}
+
+
+///// Implemented methods /////
+QImage Waveform::renderHUD()
+{
+ emit signalHUDRenderingFinished();
+ return QImage();
+}
+
+QImage Waveform::renderScope()
+{
+ QImage wave = m_waveformGenerator->calculateWaveform(scopeRect().size(),
+ m_activeRender->extractFrame(m_activeRender->seekFramePosition()), true);
+ emit signalScopeRenderingFinished();
+ return wave;
+}
- m_scopeRect = QRect(topleft, this->size() - QSize(offset+topleft.x(), offset+topleft.y()));
+QImage Waveform::renderBackground()
+{
+ emit signalBackgroundRenderingFinished();
+ return QImage();
}
// When updating the dimensions in the constructor, the size
// of the control items at the top are simply ignored! So do
// it here instead.
- updateDimensions();
+ scopeRect();
initialDimensionUpdateDone = true;
}
}
-void Waveform::resizeEvent(QResizeEvent *event)
-{
- updateDimensions();
- m_waveformGenerator->calculateWaveform(m_scopeRect.size(), m_activeRender->extractFrame(m_activeRender->seekFramePosition()), true);
- QWidget::resizeEvent(event);
-}
+//void Waveform::resizeEvent(QResizeEvent *event)
+//{
+// updateDimensions();
+// m_waveformGenerator->calculateWaveform(m_scopeRect.size(), m_activeRender->extractFrame(m_activeRender->seekFramePosition()), true);
+// QWidget::resizeEvent(event);
+//}
-void Waveform::mouseReleaseEvent(QMouseEvent *)
-{
- qDebug() << "Calculating scope now. Size: " << m_scopeRect.size().width() << "x" << m_scopeRect.size().height();
- m_waveformGenerator->calculateWaveform(m_scopeRect.size(), m_activeRender->extractFrame(m_activeRender->seekFramePosition()), true);
-}
+//void Waveform::mouseReleaseEvent(QMouseEvent *)
+//{
+// qDebug() << "Calculating scope now. Size: " << m_scopeRect.size().width() << "x" << m_scopeRect.size().height();
+// m_waveformGenerator->calculateWaveform(m_scopeRect.size(), m_activeRender->extractFrame(m_activeRender->seekFramePosition()), true);
+//}
///// Slots /////
this->update();
}
-void Waveform::slotActiveMonitorChanged(bool isClipMonitor)
-{
- if (isClipMonitor) {
- m_activeRender = m_clipMonitor->render;
- disconnect(this, SLOT(slotRenderZoneUpdated()));
- connect(m_activeRender, SIGNAL(rendererPosition(int)), this, SLOT(slotRenderZoneUpdated()));
- } else {
- m_activeRender = m_projMonitor->render;
- disconnect(this, SLOT(slotRenderZoneUpdated()));
- connect(m_activeRender, SIGNAL(rendererPosition(int)), this, SLOT(slotRenderZoneUpdated()));
- }
-}
-
void Waveform::slotRenderZoneUpdated()
{
qDebug() << "Monitor incoming.";//New frames total: " << newFrames;
#ifndef WAVEFORM_H
#define WAVEFORM_H
-#include <QWidget>
+#include "abstractscopewidget.h"
#include "ui_waveform_ui.h"
-#include "renderer.h"
-#include "monitor.h"
-#include "waveformgenerator.h"
class Waveform_UI;
class WaveformGenerator;
-class Render;
-class Monitor;
-class Waveform : public QWidget, public Ui::Waveform_UI {
+class Waveform : public AbstractScopeWidget {
Q_OBJECT
public:
Waveform(Monitor *projMonitor, Monitor *clipMonitor, QWidget *parent = 0);
~Waveform();
+ virtual QString widgetName() const;
+
protected:
void paintEvent(QPaintEvent *);
- void resizeEvent(QResizeEvent *);
- void mouseReleaseEvent(QMouseEvent *);
+// void resizeEvent(QResizeEvent *);
+// void mouseReleaseEvent(QMouseEvent *);
private:
- Monitor *m_projMonitor;
- Monitor *m_clipMonitor;
- Render *m_activeRender;
+ Ui::Waveform_UI *ui;
WaveformGenerator *m_waveformGenerator;
- void updateDimensions();
bool initialDimensionUpdateDone;
- QRect m_scopeRect;
QImage m_waveform;
+ /// Implemented methods ///
+ QRect scopeRect();
+ QImage renderHUD();
+ QImage renderScope();
+ QImage renderBackground();
+
private slots:
- void slotActiveMonitorChanged(bool isClipMonitor);
void slotRenderZoneUpdated();
void slotWaveformCalculated(QImage waveform, const uint &msec);
--- /dev/null
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>TestWidget_UI</class>
+ <widget class="QWidget" name="TestWidget_UI">
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>400</width>
+ <height>300</height>
+ </rect>
+ </property>
+ <property name="windowTitle">
+ <string>Form</string>
+ </property>
+ <layout class="QGridLayout" name="gridLayout">
+ <item row="0" column="0">
+ <widget class="QComboBox" name="comboBox"/>
+ </item>
+ <item row="2" column="0">
+ <spacer name="verticalSpacer">
+ <property name="orientation">
+ <enum>Qt::Vertical</enum>
+ </property>
+ <property name="sizeHint" stdset="0">
+ <size>
+ <width>20</width>
+ <height>40</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ <item row="1" column="0">
+ <widget class="Line" name="line">
+ <property name="orientation">
+ <enum>Qt::Horizontal</enum>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ <resources/>
+ <connections/>
+</ui>