Commit 9531ebfd authored by Simon Eugster's avatar Simon Eugster
Browse files

Abstract scope class AbstractScopeWidget added.

* 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
parent 9a05afbe
......@@ -93,6 +93,7 @@ kde4_add_ui_files(kdenlive_UI
widgets/vectorscope_ui.ui
widgets/colorplaneexport_ui.ui
widgets/waveform_ui.ui
widgets/testwidget_ui.ui
)
set(kdenlive_SRCS
......@@ -194,12 +195,14 @@ 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
)
......
/***************************************************************************
* 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.
}
}
}
/***************************************************************************
* 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
......@@ -54,6 +54,7 @@
#include "ui_templateclip_ui.h"
#include "vectorscope.h"
#include "waveform.h"
#include "testwidget.h"
#include <KApplication>
#include <KAction>
......@@ -226,6 +227,12 @@ MainWindow::MainWindow(const QString &MltPath, const KUrl & Url, QWidget *parent
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");
......
......@@ -63,6 +63,7 @@ class Render;
class Transition;
class Vectorscope;
class Waveform;
class TestWidget;
class KActionCollection;
class MainWindow : public KXmlGuiWindow
......@@ -158,6 +159,9 @@ private:
QDockWidget *m_waveformDock;
Waveform *m_waveform;
QDockWidget *m_testDock;
TestWidget *m_test;
QDockWidget *m_undoViewDock;
QUndoView *m_undoView;
QUndoGroup *m_commandStack;
......
/***************************************************************************
* 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";
}
/***************************************************************************
* 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
......@@ -12,17 +12,18 @@
#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)));
......@@ -35,14 +36,41 @@ Waveform::~Waveform()
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();
}
......@@ -55,7 +83,7 @@ void Waveform::paintEvent(QPaintEvent *)
// 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;
}
......@@ -69,18 +97,18 @@ void Waveform::paintEvent(QPaintEvent *)
}
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 /////
......@@ -92,19 +120,6 @@ void Waveform::slotWaveformCalculated(QImage waveform, const uint &msec)
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;
......
......@@ -11,45 +11,43 @@
#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