]> git.sesse.net Git - kdenlive/commitdiff
NEW: Kdenlive can now create screencasts.
authorJean-Baptiste Mardelle <jb@kdenlive.org>
Wed, 25 Jun 2008 20:22:47 +0000 (20:22 +0000)
committerJean-Baptiste Mardelle <jb@kdenlive.org>
Wed, 25 Jun 2008 20:22:47 +0000 (20:22 +0000)
You can capture video through firewire (with dvgrab), video4linux (with ffmpeg) and x11 video grabbing (with ffmpeg configured with: --enable-x11grab )

svn path=/branches/KDE4/; revision=2276

src/CMakeLists.txt
src/kdenlivedoc.cpp
src/kdenlivesettings.kcfg
src/kdenlivesettingsdialog.cpp
src/mainwindow.cpp
src/recmonitor.cpp
src/recmonitor.h
src/regiongrabber.cpp [new file with mode: 0644]
src/regiongrabber.h [new file with mode: 0644]
src/widgets/configcapture_ui.ui
src/widgets/recmonitor_ui.ui

index e528b552b94d38daee28e611d16e4b1d80ac3248..468cc8adf3de0e83055589a0d312f9682a8cefa9 100644 (file)
@@ -115,6 +115,7 @@ set(kdenlive_SRCS
   guide.cpp
   editguidecommand.cpp
   statusbarmessagelabel.cpp
+  regiongrabber.cpp
 )
 
 kde4_add_kcfg_files(kdenlive_SRCS GENERATE_MOC kdenlivesettings.kcfgc )
index 624a3e93acf082f138b0e39e835d503c9d72826c..4ed2ce67933dc53f9e28053865cf6eb09d90513e 100644 (file)
@@ -37,6 +37,7 @@
 #include "mainwindow.h"
 
 KdenliveDoc::KdenliveDoc(const KUrl &url, const KUrl &projectFolder, MltVideoProfile profile, QUndoGroup *undoGroup, MainWindow *parent): QObject(parent), m_render(NULL), m_url(url), m_projectFolder(projectFolder), m_profile(profile), m_fps((double)profile.frame_rate_num / profile.frame_rate_den), m_width(profile.width), m_height(profile.height), m_commandStack(new KUndoStack(undoGroup)), m_modified(false), m_documentLoadingProgress(0), m_documentLoadingStep(0.0), m_startPos(0) {
+       kDebug()<<"// init profile, ratnum: "<<profile.frame_rate_num<<", "<<profile.frame_rate_num<<", width: "<<profile.width;
     m_clipManager = new ClipManager(this);
     if (!url.isEmpty()) {
         QString tmpFile;
@@ -195,7 +196,7 @@ KdenliveDoc::KdenliveDoc(const KUrl &url, const KUrl &projectFolder, MltVideoPro
         westley.appendChild(tractor);
     }
     m_scenelist = m_document.toString();
-    // kDebug() << "scenelist" << m_scenelist;
+    kDebug() << "KDEnnlive document, init timecode: "<<m_fps;
     if (m_fps == 30000.0 / 1001.0) m_timecode.setFormat(30, true);
     else m_timecode.setFormat((int) m_fps);
 }
@@ -366,6 +367,7 @@ void KdenliveDoc::setProfilePath(QString path) {
     m_fps = (double) m_profile.frame_rate_num / m_profile.frame_rate_den;
     m_width = m_profile.width;
     m_height = m_profile.height;
+    kDebug() << "KDEnnlive document, init timecode from path: "<<path<<",  "<<m_fps;
     if (m_fps == 30000.0 / 1001.0) m_timecode.setFormat(30, true);
     else m_timecode.setFormat((int) m_fps);
 }
index dac1dba791c309e291875cfaf2b1c7d5f2941c0f..4f562eca571f3244bd87aea4c704d7b8a007967b 100644 (file)
       <default></default>
     </entry>
 
+    <entry name="screengrabcapture" type="String">
+      <label>ffmpeg arguments for x11 grab capture.</label>
+      <default>-f x11grab -r 15 -s %size -i :0.0%offset</default>
+    </entry>
+
+    <entry name="screengrabencoding" type="String">
+      <label>ffmpeg arguments for x11 capture encoding.</label>
+      <default>-vcodec mpeg4</default>
+    </entry>
+
+    <entry name="screengrabextension" type="String">
+      <label>file extension for captured file.</label>
+      <default>avi</default>
+    </entry>
+
+    <entry name="fullscreengrab" type="Bool">
+      <label>Capture full screen.</label>
+      <default>false</default>
+    </entry>
+
     <entry name="video4playback" type="String">
       <label>ffplay arguments for video playback.</label>
       <default></default>
index 85651bc08678942edb4768b3d9ea7475270e2d80..1061cc1b47e6dc5e7fd6e8c9dced667b476a495e 100644 (file)
@@ -57,6 +57,7 @@ KdenliveSettingsDialog::KdenliveSettingsDialog(QWidget * parent): KConfigDialog(
     QWidget *p4 = new QWidget;
     m_configCapture.setupUi(p4);
     page4 = addPage(p4, i18n("Capture"), "audio-card");
+       m_configCapture.tabWidget->setCurrentIndex(KdenliveSettings::defaultcapture());
 
     QWidget *p5 = new QWidget;
     m_configShuttle.setupUi(p5);
index 0dd30a9196a231b1e1ae347b4153fdd0b633998a..e8cf95819f9439657bcd9f70458b5c08eee0eec7 100644 (file)
@@ -630,7 +630,9 @@ void MainWindow::newFile() {
         projectFolder = w->selectedFolder();
         delete w;
     }
-    MltVideoProfile prof = ProfilesDialog::getVideoProfile(profileName);
+    MltVideoProfile prof;
+       if (!profileName.isEmpty()) prof = ProfilesDialog::getVideoProfile(profileName);
+       else prof = ProfilesDialog::getVideoProfile("dv_pal");
     if (prof.width == 0) prof = ProfilesDialog::getVideoProfile("dv_pal");
     KdenliveDoc *doc = new KdenliveDoc(KUrl(), projectFolder, prof, m_commandStack, this);
     TrackView *trackView = new TrackView(doc, this);
index 537342d6cd1a16e9e78ea2578b3ad6393c679752..13d9d2253c1b70711fba782d7c65c84d6025e69b 100644 (file)
@@ -24,6 +24,7 @@
 #include <QToolButton>
 #include <QFile>
 #include <QDir>
+#include <QDesktopWidget>
 
 #include <KDebug>
 #include <KLocale>
@@ -103,21 +104,31 @@ QString RecMonitor::name() const {
 }
 
 void RecMonitor::slotVideoDeviceChanged(int ix) {
-
-    if (ix == 1) {
-        m_discAction->setEnabled(false);
-        m_rewAction->setEnabled(false);
-        m_fwdAction->setEnabled(false);
-        m_recAction->setEnabled(true);
-        m_stopAction->setEnabled(false);
-        m_playAction->setEnabled(true);
-    } else {
-        m_discAction->setEnabled(true);
-        m_recAction->setEnabled(false);
-        m_stopAction->setEnabled(false);
-        m_playAction->setEnabled(false);
-        m_rewAction->setEnabled(false);
-        m_fwdAction->setEnabled(false);
+       switch (ix) {
+               case SCREENGRAB:
+                       m_discAction->setEnabled(false);
+                       m_rewAction->setEnabled(false);
+                       m_fwdAction->setEnabled(false);
+                       m_recAction->setEnabled(true);
+                       m_stopAction->setEnabled(false);
+                       m_playAction->setEnabled(false);
+                       break;
+               case VIDEO4LINUX:
+                       m_discAction->setEnabled(false);
+                       m_rewAction->setEnabled(false);
+                       m_fwdAction->setEnabled(false);
+                       m_recAction->setEnabled(true);
+                       m_stopAction->setEnabled(false);
+                       m_playAction->setEnabled(true);
+                       break;
+               default: // FIREWIRE
+                       m_discAction->setEnabled(true);
+                       m_recAction->setEnabled(false);
+                       m_stopAction->setEnabled(false);
+                       m_playAction->setEnabled(false);
+                       m_rewAction->setEnabled(false);
+                       m_fwdAction->setEnabled(false);
+                       break;
     }
 }
 
@@ -153,15 +164,24 @@ void RecMonitor::slotForward() {
 
 void RecMonitor::slotStopCapture() {
     // stop capture
-    if (ui.device_selector->currentIndex() == 0) {
+       switch (ui.device_selector->currentIndex()) {
+    case FIREWIRE:
         captureProcess->write("\e", 2);
         m_playAction->setIcon(m_playIcon);
         m_isPlaying = false;
-    } else {
-        if (m_isCapturing && ui.autoaddbox->isChecked()) emit addProjectClip(m_captureFile);
+               break;
+    case VIDEO4LINUX:
         captureProcess->kill();
         displayProcess->kill();
-    }
+               if (m_isCapturing && ui.autoaddbox->isChecked()) emit addProjectClip(m_captureFile);
+               break;
+    case SCREENGRAB:
+        captureProcess->kill();
+               if (m_isCapturing && ui.autoaddbox->isChecked()) emit addProjectClip(m_captureFile);
+               break;
+       default:
+               break;
+       }
 }
 
 void RecMonitor::slotStartCapture(bool play) {
@@ -205,7 +225,7 @@ void RecMonitor::slotStartCapture(bool play) {
 
 
     if (captureProcess->state() != QProcess::NotRunning) {
-        if (ui.device_selector->currentIndex() == 0) {
+        if (ui.device_selector->currentIndex() == FIREWIRE) {
             if (m_isPlaying) {
                 captureProcess->write("k", 1);
                 //captureProcess->write("\e", 2);
@@ -223,78 +243,120 @@ void RecMonitor::slotStartCapture(bool play) {
     m_displayArgs.clear();
     m_isPlaying = false;
 
-    if (ui.device_selector->currentIndex() == 0) {
+       switch (ui.device_selector->currentIndex()) {
+    case FIREWIRE:
         m_captureArgs << "--format" << "hdv" << "-i" << "capture" << "-";
         m_displayArgs << "-f" << "mpegts" << "-x" << QString::number(ui.video_frame->width()) << "-y" << QString::number(ui.video_frame->height()) << "-";
-    } else {
-        m_captureArgs << KdenliveSettings::video4capture().simplified().split(' ') << "-";
-        m_displayArgs << KdenliveSettings::video4playback().simplified().split(' ') << "-x" << QString::number(ui.video_frame->width()) << "-y" << QString::number(ui.video_frame->height()) << "-";
-    }
-
-    captureProcess->setStandardOutputProcess(displayProcess);
-    if (ui.device_selector->currentIndex() == 0) {
+               captureProcess->setStandardOutputProcess(displayProcess);
         captureProcess->setWorkingDirectory(KdenliveSettings::capturefolder());
         captureProcess->start("dvgrab", m_captureArgs);
         if (play) captureProcess->write(" ", 1);
         m_discAction->setEnabled(true);
-    } else captureProcess->start("ffmpeg", m_captureArgs);
-    displayProcess->start("ffplay", m_displayArgs);
-    ui.video_frame->setText(i18n("Initialising..."));
+               break;
+    case VIDEO4LINUX:
+        m_captureArgs << KdenliveSettings::video4capture().simplified().split(' ') << "-";
+        m_displayArgs << KdenliveSettings::video4playback().simplified().split(' ') << "-x" << QString::number(ui.video_frame->width()) << "-y" << QString::number(ui.video_frame->height()) << "-";
+               captureProcess->setStandardOutputProcess(displayProcess);
+               captureProcess->start("ffmpeg", m_captureArgs);
+               break;
+       default:
+               break;
+    }
 
+    if (ui.device_selector->currentIndex() != SCREENGRAB) {
+               displayProcess->start("ffplay", m_displayArgs);
+               ui.video_frame->setText(i18n("Initialising..."));
+       } else {
+               // do something when starting screen grab
+       }
 }
 
 void RecMonitor::slotRecord() {
-    if (captureProcess->state() == QProcess::NotRunning && ui.device_selector->currentIndex() == 0) {
+    if (captureProcess->state() == QProcess::NotRunning && ui.device_selector->currentIndex() == FIREWIRE) {
         slotStartCapture();
     }
     if (m_isCapturing) {
-        if (ui.device_selector->currentIndex() == 0) {
+               switch (ui.device_selector->currentIndex()) {
+               case FIREWIRE:
             captureProcess->write("\e", 2);
             m_playAction->setIcon(m_playIcon);
             m_isCapturing = false;
             m_isPlaying = false;
             m_recAction->setChecked(false);
-        } else {
+                       break;
+        case VIDEO4LINUX:
             slotStopCapture();
+            m_isCapturing = false;
             QTimer::singleShot(1000, this, SLOT(slotStartCapture()));
+                       break;
+        case SCREENGRAB:
+            slotStopCapture();
+            m_isCapturing = false;
+                       break;
         }
         return;
-    } else if (ui.device_selector->currentIndex() == 0) {
+    } else if (ui.device_selector->currentIndex() == FIREWIRE) {
         m_isCapturing = true;
         captureProcess->write("c\n", 3);
         return;
     }
     if (captureProcess->state() == QProcess::NotRunning) {
         m_recAction->setChecked(true);
-
-        QString path = KdenliveSettings::capturefolder() + "/capture0000.mpg";
+               QString extension = "mpg";
+               if (ui.device_selector->currentIndex() == SCREENGRAB) extension = KdenliveSettings::screengrabextension();
+        QString path = KdenliveSettings::capturefolder() + "/capture0000." + extension;
         int i = 1;
         while (QFile::exists(path)) {
             QString num = QString::number(i).rightJustified(4, '0', false);
-            path = KdenliveSettings::capturefolder() + "/capture" + num + ".mpg";
+            path = KdenliveSettings::capturefolder() + "/capture" + num + "." + extension;
             i++;
         }
 
         m_captureFile = KUrl(path);
 
-        m_isCapturing = true;
         m_captureArgs.clear();
         m_displayArgs.clear();
+               QString args;
 
-        if (ui.device_selector->currentIndex() == 0) {
+               switch (ui.device_selector->currentIndex()) {
+               case FIREWIRE:
             m_captureArgs << "--format" << "hdv" << "-i" << "capture" << "-";
             m_displayArgs << "-f" << "mpegts" << "-x" << QString::number(ui.video_frame->width()) << "-y" << QString::number(ui.video_frame->height()) << "-";
-        } else {
+                       captureProcess->setStandardOutputProcess(displayProcess);
+                       captureProcess->start("dvgrab", m_captureArgs);
+                       break;
+               case VIDEO4LINUX:
             m_captureArgs << KdenliveSettings::video4capture().simplified().split(' ') << "-y" << m_captureFile.path() << "-f" << KdenliveSettings::video4vencoding() << "-";
             m_displayArgs << KdenliveSettings::video4playback().simplified().split(' ') << "-x" << QString::number(ui.video_frame->width()) << "-y" << QString::number(ui.video_frame->height()) << "-";
-        }
+                       captureProcess->setStandardOutputProcess(displayProcess);
+                       captureProcess->start("ffmpeg", m_captureArgs);
+                       break;
+               case SCREENGRAB:
+                       if (KdenliveSettings::fullscreengrab()) {
+                               const QRect rect = QApplication::desktop()->screenGeometry();
+                               args = KdenliveSettings::screengrabcapture().replace("%size", QString::number(rect.width()) + "x" + QString::number(rect.height())).replace("%offset", QString());
+                               kDebug()<<"// capture params: "<<args;
+                               m_captureArgs << args.simplified().split(' ') <<KdenliveSettings::screengrabencoding().simplified().split(' ')<<m_captureFile.path();
+                               ui.video_frame->setText(i18n("Capturing..."));
+                               m_isCapturing = true;
+                               captureProcess->start("ffmpeg", m_captureArgs);
+                       }
+                       else {
+                               ui.video_frame->setText(i18n("Select region..."));
+                               rgnGrab = new RegionGrabber();
+                               connect( rgnGrab, SIGNAL( regionGrabbed( const QRect&) ), SLOT( slotStartGrab( const QRect & ) ) );
+                       }
+                       break;
+               default:
+                       break;
+               }
 
-        captureProcess->setStandardOutputProcess(displayProcess);
         //ui.video_frame->setScaledContents(false);
-        if (ui.device_selector->currentIndex() == 0) captureProcess->start("dvgrab", m_captureArgs);
-        else captureProcess->start("ffmpeg", m_captureArgs);
-        displayProcess->start("ffplay", m_displayArgs);
-        ui.video_frame->setText(i18n("Initialising..."));
+        if (ui.device_selector->currentIndex() != SCREENGRAB) {
+                       m_isCapturing = true;
+                       displayProcess->start("ffplay", m_displayArgs);
+                       ui.video_frame->setText(i18n("Initialising..."));
+               }
     } else {
         // stop capture
         displayProcess->kill();
@@ -303,6 +365,24 @@ void RecMonitor::slotRecord() {
     }
 }
 
+void RecMonitor::slotStartGrab(const QRect &rect)
+{
+       rgnGrab->deleteLater();
+       QApplication::restoreOverrideCursor();
+       show();
+       if (rect.isNull()) return;
+       int width = rect.width();
+       int height = rect.height();
+       if (width % 2 != 0) width--;
+       if (height % 2 != 0) height--;
+       QString args = KdenliveSettings::screengrabcapture().replace("%size", QString::number(width) + "x" + QString::number(height)).replace("%offset", "+" + QString::number(rect.x()) + "," + QString::number(rect.y()));
+       kDebug()<<"// capture params: "<<args;
+       m_captureArgs << args.simplified().split(' ') <<KdenliveSettings::screengrabencoding().simplified().split(' ')<<m_captureFile.path();
+       m_isCapturing = true;
+       ui.video_frame->setText(i18n("Capturing..."));
+       captureProcess->start("ffmpeg", m_captureArgs);
+}
+
 void RecMonitor::slotProcessStatus(QProcess::ProcessState status) {
     if (status == QProcess::NotRunning) {
         m_isCapturing = false;
@@ -311,7 +391,10 @@ void RecMonitor::slotProcessStatus(QProcess::ProcessState status) {
         m_recAction->setChecked(false);
         m_stopAction->setEnabled(false);
         ui.device_selector->setEnabled(true);
-        ui.video_frame->setText(i18n("Not connected"));
+               /*if (captureProcess && captureProcess->exitStatus() == QProcess::CrashExit) {
+                       ui.video_frame->setText(i18n("Capture crashed, please check your parameters"));
+               }
+        else*/ ui.video_frame->setText(i18n("Not connected"));
     } else {
         m_stopAction->setEnabled(true);
         ui.device_selector->setEnabled(false);
index c2f2c37ab3651cff660bd3cc84a0dfc03b2124f1..b783f5379e9fa34dd0eb80396c04d7be26d7ce9e 100644 (file)
@@ -32,6 +32,7 @@
 
 #include "ui_recmonitor_ui.h"
 #include "smallruler.h"
+#include "regiongrabber.h"
 
 class RecMonitor : public QWidget {
     Q_OBJECT
@@ -40,6 +41,7 @@ public:
     RecMonitor(QString name, QWidget *parent = 0);
     QString name() const;
 
+enum CAPTUREDEVICE {FIREWIRE = 0, VIDEO4LINUX = 1, SCREENGRAB =2};
 
 protected:
     virtual void mousePressEvent(QMouseEvent * event);
@@ -48,7 +50,7 @@ private:
     Ui::RecMonitor_UI ui;
     QString m_tmpFolder;
     QString m_name;
-
+       RegionGrabber *rgnGrab;
     bool m_isActive;
 
 
@@ -79,6 +81,7 @@ private slots:
     void slotRewind();
     void slotForward();
     void slotDisconnect();
+       void slotStartGrab(const QRect &rect);
 
 public slots:
     void refreshRecMonitor(bool visible);
diff --git a/src/regiongrabber.cpp b/src/regiongrabber.cpp
new file mode 100644 (file)
index 0000000..a8292e3
--- /dev/null
@@ -0,0 +1,379 @@
+/*
+ *   Copyright (C) 2007 Luca Gugelmann <lucag@student.ethz.ch>
+ *   Adapted for Kdenlive by Jean-Baptiste Mardelle (2008) jb@kdenlive.org
+ *
+ *   This program is free software; you can redistribute it and/or modify it
+ *   under the terms of the GNU Library General Public License version 2 as
+ *   published by the Free Software Foundation
+ *
+ *   This program is distributed in the hope that it will be useful,
+ *   but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *   GNU General Public License for more details
+ *
+ *   You should have received a copy of the GNU Library General Public
+ *   License along with this program; if not, write to the
+ *   Free Software Foundation, Inc.,
+ *   51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+
+#include "regiongrabber.h"
+
+#include <QPainter>
+#include <QMouseEvent>
+#include <QApplication>
+#include <QDesktopWidget>
+#include <QToolTip>
+
+#include <klocale.h>
+#include <KWindowSystem>
+
+RegionGrabber::RegionGrabber( ) :
+    QWidget( 0 ), selection(), mouseDown( false ), newSelection( false ),
+    handleSize( 10 ), mouseOverHandle( 0 ), idleTimer(),
+    showHelp( true ), grabbing( false ),
+    TLHandle(0,0,handleSize,handleSize), TRHandle(0,0,handleSize,handleSize),
+    BLHandle(0,0,handleSize,handleSize), BRHandle(0,0,handleSize,handleSize),
+    LHandle(0,0,handleSize,handleSize), THandle(0,0,handleSize,handleSize),
+    RHandle(0,0,handleSize,handleSize), BHandle(0,0,handleSize,handleSize)
+{
+    handles << &TLHandle << &TRHandle << &BLHandle << &BRHandle
+            << &LHandle << &THandle << &RHandle << &BHandle;
+    setMouseTracking( true );
+    setWindowFlags( Qt::WindowStaysOnTopHint | Qt::FramelessWindowHint | Qt::X11BypassWindowManagerHint);
+    int timeout = KWindowSystem::compositingActive() ? 200 : 50;
+    QTimer::singleShot( timeout, this, SLOT(init()) );
+    connect( &idleTimer, SIGNAL( timeout() ), this, SLOT( displayHelp() ) );
+    idleTimer.start( 3000 );
+}
+
+RegionGrabber::~RegionGrabber()
+{
+}
+
+void RegionGrabber::init()
+{
+    pixmap = QPixmap::grabWindow( QApplication::desktop()->winId() );
+    showFullScreen();
+    resize( pixmap.size() );
+    move(0, 0);
+    setCursor( Qt::CrossCursor );
+}
+
+void RegionGrabber::displayHelp()
+{
+    showHelp = true;
+    update();
+}
+
+void RegionGrabber::paintEvent( QPaintEvent* e )
+{
+    Q_UNUSED( e );
+    if ( grabbing ) // grabWindow() should just get the background
+        return;
+
+    QPainter painter( this );
+
+    QPalette pal(QToolTip::palette());
+    QFont font = QToolTip::font();
+
+    QColor handleColor = pal.color( QPalette::Active, QPalette::Highlight );
+    handleColor.setAlpha( 160 );
+    QColor overlayColor( 0, 0, 0, 160 );
+    QColor textColor = pal.color( QPalette::Active, QPalette::Text );
+    QColor textBackgroundColor = pal.color( QPalette::Active, QPalette::Base );
+    painter.drawPixmap(0, 0, pixmap);
+    painter.setFont(font);
+    
+    QRect r = selection.normalized().adjusted( 0, 0, -1, -1 );
+    if ( !selection.isNull() )
+    {
+        QRegion grey( rect() );
+        grey = grey.subtracted( r );
+        painter.setPen( handleColor );
+        painter.setBrush( overlayColor );
+        painter.setClipRegion( grey );
+        painter.drawRect( -1, -1, rect().width() + 1, rect().height() + 1 );
+        painter.setClipRect( rect() );
+        painter.setBrush( Qt::NoBrush );
+        painter.drawRect( r );
+    }
+
+    if ( showHelp )
+    {
+        painter.setPen( textColor );
+        painter.setBrush( textBackgroundColor );
+        QString helpText = i18n( "Select a region using the mouse. To take the snapshot, press the Enter key. Press Esc to quit." );
+        QRect textRect = painter.boundingRect( rect().adjusted( 2, 2, -2, -2 ), Qt::TextWordWrap, helpText );
+        textRect.adjust( -2, -2, 4, 2 );
+        painter.drawRect( textRect );
+        textRect.moveTopLeft( QPoint( 3, 3 ) );
+        painter.drawText( textRect, helpText );
+    }
+
+    if ( selection.isNull() )
+    {
+        return;
+    }
+
+    // The grabbed region is everything which is covered by the drawn
+    // rectangles (border included). This means that there is no 0px
+    // selection, since a 0px wide rectangle will always be drawn as a line.
+    QString txt = QString( "%1x%2" ).arg( selection.width() == 0 ? 2 : selection.width() )
+                  .arg( selection.height() == 0 ? 2 : selection.height() );
+    QRect textRect = painter.boundingRect( rect(), Qt::AlignLeft, txt );
+    QRect boundingRect = textRect.adjusted( -4, 0, 0, 0);
+
+    if ( textRect.width() < r.width() - 2*handleSize &&
+         textRect.height() < r.height() - 2*handleSize &&
+         ( r.width() > 100 && r.height() > 100 ) ) // center, unsuitable for small selections
+    {
+        boundingRect.moveCenter( r.center() );
+        textRect.moveCenter( r.center() );
+    }
+    else if ( r.y() - 3 > textRect.height() &&
+              r.x() + textRect.width() < rect().right() ) // on top, left aligned
+    {
+        boundingRect.moveBottomLeft( QPoint( r.x(), r.y() - 3 ) );
+        textRect.moveBottomLeft( QPoint( r.x() + 2, r.y() - 3 ) );
+    }
+    else if ( r.x() - 3 > textRect.width() ) // left, top aligned
+    {
+        boundingRect.moveTopRight( QPoint( r.x() - 3, r.y() ) );
+        textRect.moveTopRight( QPoint( r.x() - 5, r.y() ) );
+    }
+    else if ( r.bottom() + 3 + textRect.height() < rect().bottom() &&
+              r.right() > textRect.width() ) // at bottom, right aligned
+    {
+        boundingRect.moveTopRight( QPoint( r.right(), r.bottom() + 3 ) );
+        textRect.moveTopRight( QPoint( r.right() - 2, r.bottom() + 3 ) );
+    }
+    else if ( r.right() + textRect.width() + 3 < rect().width() ) // right, bottom aligned
+    {
+        boundingRect.moveBottomLeft( QPoint( r.right() + 3, r.bottom() ) );
+        textRect.moveBottomLeft( QPoint( r.right() + 5, r.bottom() ) );
+    }
+    // if the above didn't catch it, you are running on a very tiny screen...
+    painter.setPen( textColor );
+    painter.setBrush( textBackgroundColor );
+    painter.drawRect( boundingRect );
+    painter.drawText( textRect, txt );
+
+    if ( ( r.height() > handleSize*2 && r.width() > handleSize*2 )
+         || !mouseDown )
+    {
+        updateHandles();
+        painter.setPen( handleColor );
+        handleColor.setAlpha( 60 );
+        painter.setBrush( handleColor );
+        painter.drawRects( handleMask().rects() );
+    }
+}
+
+void RegionGrabber::resizeEvent( QResizeEvent* e )
+{
+    Q_UNUSED( e );
+    if ( selection.isNull() )
+        return;
+    QRect r = selection;
+    r.setTopLeft( limitPointToRect( r.topLeft(), rect() ) );
+    r.setBottomRight( limitPointToRect( r.bottomRight(), rect() ) );
+    if ( r.width() <= 1 || r.height() <= 1 ) //this just results in ugly drawing...
+        r = QRect();
+    selection = r;
+}
+
+void RegionGrabber::mousePressEvent( QMouseEvent* e )
+{
+    showHelp = false;
+    idleTimer.stop();
+    if ( e->button() == Qt::LeftButton )
+    {
+        mouseDown = true;
+        dragStartPoint = e->pos();
+        selectionBeforeDrag = selection;
+        if ( !selection.contains( e->pos() ) )
+        {
+            newSelection = true;
+            selection = QRect();
+            showHelp = true;
+        }
+        else
+        {
+            setCursor( Qt::ClosedHandCursor );
+        }
+    }
+    else if ( e->button() == Qt::RightButton )
+    {
+        newSelection = false;
+        selection = QRect();
+        setCursor( Qt::CrossCursor );
+    }
+    update();
+}
+
+void RegionGrabber::mouseMoveEvent( QMouseEvent* e )
+{
+    if ( mouseDown )
+    {
+        if ( newSelection )
+        {
+            QPoint p = e->pos();
+            QRect r = rect();
+            selection = QRect( dragStartPoint, limitPointToRect( p, r ) ).normalized();
+        }
+        else if ( mouseOverHandle == 0 ) // moving the whole selection
+        {
+            QRect r = rect().normalized(), s = selectionBeforeDrag.normalized();
+            QPoint p = s.topLeft() + e->pos() - dragStartPoint;
+            r.setBottomRight( r.bottomRight() - QPoint( s.width(), s.height() ) );
+            if ( !r.isNull() && r.isValid() )
+                selection.moveTo( limitPointToRect( p, r ) );
+        }
+        else // dragging a handle
+        {
+            QRect r = selectionBeforeDrag;
+            QPoint offset = e->pos() - dragStartPoint;
+
+            if ( mouseOverHandle == &TLHandle || mouseOverHandle == &THandle
+                 || mouseOverHandle == &TRHandle ) // dragging one of the top handles
+            {
+                r.setTop( r.top() + offset.y() );
+            }
+
+            if ( mouseOverHandle == &TLHandle || mouseOverHandle == &LHandle
+                 || mouseOverHandle == &BLHandle ) // dragging one of the left handles
+            {
+                r.setLeft( r.left() + offset.x() );
+            }
+
+            if ( mouseOverHandle == &BLHandle || mouseOverHandle == &BHandle
+                 || mouseOverHandle == &BRHandle ) // dragging one of the bottom handles
+            {
+                r.setBottom( r.bottom() + offset.y() );
+            }
+
+            if ( mouseOverHandle == &TRHandle || mouseOverHandle == &RHandle
+                 || mouseOverHandle == &BRHandle ) // dragging one of the right handles
+            {
+                r.setRight( r.right() + offset.x() );
+            }
+            r = r.normalized();
+            r.setTopLeft( limitPointToRect( r.topLeft(), rect() ) );
+            r.setBottomRight( limitPointToRect( r.bottomRight(), rect() ) );
+            selection = r;
+        }
+        update();
+    }
+    else
+    {
+        if ( selection.isNull() )
+            return;
+        bool found = false;
+        foreach( QRect* r, handles )
+        {
+            if ( r->contains( e->pos() ) )
+            {
+                mouseOverHandle = r;
+                found = true;
+                break;
+            }
+        }
+        if ( !found )
+        {
+            mouseOverHandle = 0;
+            if ( selection.contains( e->pos() ) )
+                setCursor( Qt::OpenHandCursor );
+            else
+                setCursor( Qt::CrossCursor );
+        }
+        else
+        {
+            if ( mouseOverHandle == &TLHandle || mouseOverHandle == &BRHandle )
+                setCursor( Qt::SizeFDiagCursor );
+            if ( mouseOverHandle == &TRHandle || mouseOverHandle == &BLHandle )
+                setCursor( Qt::SizeBDiagCursor );
+            if ( mouseOverHandle == &LHandle || mouseOverHandle == &RHandle )
+                setCursor( Qt::SizeHorCursor );
+            if ( mouseOverHandle == &THandle || mouseOverHandle == &BHandle )
+                setCursor( Qt::SizeVerCursor );
+        }
+    }
+}
+
+void RegionGrabber::mouseReleaseEvent( QMouseEvent* e )
+{
+    mouseDown = false;
+    newSelection = false;
+    idleTimer.start();
+    if ( mouseOverHandle == 0 && selection.contains( e->pos() ) )
+        setCursor( Qt::OpenHandCursor );
+    update();
+}
+
+void RegionGrabber::mouseDoubleClickEvent( QMouseEvent* )
+{
+    grabRect();
+}
+
+void RegionGrabber::keyPressEvent( QKeyEvent* e )
+{
+    if ( e->key() == Qt::Key_Escape )
+    {
+        emit regionGrabbed( QRect() );
+               close();
+    }
+    else if ( e->key() == Qt::Key_Enter || e->key() == Qt::Key_Return )
+    {
+        grabRect();
+    }
+    else
+    {
+        e->ignore();
+    }
+}
+
+void RegionGrabber::grabRect()
+{
+    QRect r = selection.normalized();
+    if ( !r.isNull() && r.isValid() )
+    {
+       grabbing = true;
+        emit regionGrabbed( r );
+    }
+       close();
+}
+
+void RegionGrabber::updateHandles()
+{
+    QRect r = selection.normalized().adjusted( 0, 0, -1, -1 );
+    int s2 = handleSize / 2;
+
+    TLHandle.moveTopLeft( r.topLeft() );
+    TRHandle.moveTopRight( r.topRight() );
+    BLHandle.moveBottomLeft( r.bottomLeft() );
+    BRHandle.moveBottomRight( r.bottomRight() );
+
+    LHandle.moveTopLeft( QPoint( r.x(), r.y() + r.height() / 2 - s2) );
+    THandle.moveTopLeft( QPoint( r.x() + r.width() / 2 - s2, r.y() ) );
+    RHandle.moveTopRight( QPoint( r.right(), r.y() + r.height() / 2 - s2 ) );
+    BHandle.moveBottomLeft( QPoint( r.x() + r.width() / 2 - s2, r.bottom() ) );
+}
+
+QRegion RegionGrabber::handleMask() const
+{
+    // note: not normalized QRects are bad here, since they will not be drawn
+    QRegion mask;
+    foreach( QRect* rect, handles ) mask += QRegion( *rect );
+    return mask;
+}
+
+QPoint RegionGrabber::limitPointToRect( const QPoint &p, const QRect &r ) const
+{
+    QPoint q;
+    q.setX( p.x() < r.x() ? r.x() : p.x() < r.right() ? p.x() : r.right() );
+    q.setY( p.y() < r.y() ? r.y() : p.y() < r.bottom() ? p.y() : r.bottom() );
+    return q;
+}
+
+#include "regiongrabber.moc"
diff --git a/src/regiongrabber.h b/src/regiongrabber.h
new file mode 100644 (file)
index 0000000..5de59bc
--- /dev/null
@@ -0,0 +1,83 @@
+/*
+ *   Copyright (C) 2007 Luca Gugelmann <lucag@student.ethz.ch>
+ *   Adapted for Kdenlive by Jean-Baptiste Mardelle (2008) jb@kdenlive.org
+ *
+ *   This program is free software; you can redistribute it and/or modify it
+ *   under the terms of the GNU Library General Public License version 2 as
+ *   published by the Free Software Foundation
+ *
+ *   This program is distributed in the hope that it will be useful,
+ *   but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *   GNU General Public License for more details
+ *
+ *   You should have received a copy of the GNU Library General Public
+ *   License along with this program; if not, write to the
+ *   Free Software Foundation, Inc.,
+ *   51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+
+#ifndef REGIONGRABBER_H
+#define REGIONGRABBER_H
+
+#include <QWidget>
+#include <QRegion>
+#include <QPoint>
+#include <QVector>
+#include <QRect>
+#include <QTimer>
+
+class QPaintEvent;
+class QResizeEvent;
+class QMouseEvent;
+
+class RegionGrabber : public QWidget
+{
+    Q_OBJECT
+public:
+    RegionGrabber();
+    ~RegionGrabber();
+
+protected slots:
+    void init();
+    void displayHelp();
+
+signals:
+    void regionGrabbed( const QRect & );
+
+protected:
+    void paintEvent( QPaintEvent* e );
+    void resizeEvent( QResizeEvent* e );
+    void mousePressEvent( QMouseEvent* e );
+    void mouseMoveEvent( QMouseEvent* e );
+    void mouseReleaseEvent( QMouseEvent* e );
+    void mouseDoubleClickEvent( QMouseEvent* );
+    void keyPressEvent( QKeyEvent* e );
+    void updateHandles();
+    QRegion handleMask() const;
+    QPoint limitPointToRect( const QPoint &p, const QRect &r ) const;
+    void grabRect();
+
+    QRect selection;
+    bool mouseDown;
+    bool newSelection;
+    const int handleSize;
+    QRect* mouseOverHandle;
+    QPoint dragStartPoint;
+    QRect  selectionBeforeDrag;
+    QTimer idleTimer;
+    bool showHelp;
+    bool grabbing;
+
+    // naming convention for handles
+    // T top, B bottom, R Right, L left
+    // 2 letters: a corner
+    // 1 letter: the handle on the middle of the corresponding side
+    QRect TLHandle, TRHandle, BLHandle, BRHandle;
+    QRect LHandle, THandle, RHandle, BHandle;
+
+    QVector<QRect*> handles;
+    QPixmap pixmap;
+};
+
+#endif
index 559f1435efb7913f21970c390ea32b12efc80d37..a1055eae3a7dbf8c9c8fc44429fd3fd2fa94e7db 100644 (file)
        <string>Video4Linux (webcam)</string>
       </property>
      </item>
+     <item>
+      <property name="text" >
+       <string>Screen Grab</string>
+      </property>
+     </item>
     </widget>
    </item>
    <item row="1" column="0" colspan="2" >
@@ -47,8 +52,8 @@
        <rect>
         <x>0</x>
         <y>0</y>
-        <width>482</width>
-        <height>233</height>
+        <width>486</width>
+        <height>270</height>
        </rect>
       </property>
       <attribute name="title" >
        <rect>
         <x>0</x>
         <y>0</y>
-        <width>482</width>
-        <height>233</height>
+        <width>486</width>
+        <height>270</height>
        </rect>
       </property>
       <attribute name="title" >
         </widget>
        </item>
       </layout>
-      <zorder>kcfg_video4vdevice</zorder>
-      <zorder>label_7</zorder>
-      <zorder>line</zorder>
-      <zorder>label_3</zorder>
-      <zorder>label_5</zorder>
-      <zorder>kcfg_video4vformat</zorder>
-      <zorder>kcfg_video4vencoding</zorder>
-      <zorder>label_14</zorder>
-      <zorder>kcfg_video4aencoding</zorder>
-      <zorder>kcfg_video4adevice</zorder>
-      <zorder>line_2</zorder>
-      <zorder>label_9</zorder>
-      <zorder>label_16</zorder>
-      <zorder>label_15</zorder>
-      <zorder>label_13</zorder>
-      <zorder>line_3</zorder>
-      <zorder>label_4</zorder>
-      <zorder>label_6</zorder>
-      <zorder>kcfg_video4size</zorder>
-      <zorder>label_11</zorder>
-      <zorder>kcfg_video4rate</zorder>
-      <zorder>kcfg_video4capture</zorder>
-      <zorder>kcfg_video4playback</zorder>
-      <zorder>label_12</zorder>
-      <zorder>kcfg_video4aformat</zorder>
+     </widget>
+     <widget class="QWidget" name="tab_3" >
+      <property name="geometry" >
+       <rect>
+        <x>0</x>
+        <y>0</y>
+        <width>486</width>
+        <height>270</height>
+       </rect>
+      </property>
+      <attribute name="title" >
+       <string>Screen Grab / FFmpeg</string>
+      </attribute>
+      <layout class="QGridLayout" name="gridLayout_4" >
+       <item row="0" column="0" >
+        <widget class="QLabel" name="label_17" >
+         <property name="text" >
+          <string>Capture params</string>
+         </property>
+        </widget>
+       </item>
+       <item row="0" column="1" >
+        <widget class="KLineEdit" name="kcfg_screengrabcapture" />
+       </item>
+       <item row="1" column="0" >
+        <widget class="QLabel" name="label_8" >
+         <property name="sizePolicy" >
+          <sizepolicy vsizetype="Preferred" hsizetype="Maximum" >
+           <horstretch>0</horstretch>
+           <verstretch>0</verstretch>
+          </sizepolicy>
+         </property>
+         <property name="text" >
+          <string>Encoding parameters</string>
+         </property>
+        </widget>
+       </item>
+       <item row="1" column="1" >
+        <widget class="KLineEdit" name="kcfg_screengrabencoding" >
+         <property name="sizePolicy" >
+          <sizepolicy vsizetype="Fixed" hsizetype="MinimumExpanding" >
+           <horstretch>0</horstretch>
+           <verstretch>0</verstretch>
+          </sizepolicy>
+         </property>
+         <property name="text" >
+          <string/>
+         </property>
+        </widget>
+       </item>
+       <item row="2" column="0" >
+        <widget class="QLabel" name="label_10" >
+         <property name="sizePolicy" >
+          <sizepolicy vsizetype="Preferred" hsizetype="Maximum" >
+           <horstretch>0</horstretch>
+           <verstretch>0</verstretch>
+          </sizepolicy>
+         </property>
+         <property name="text" >
+          <string>File extension</string>
+         </property>
+        </widget>
+       </item>
+       <item row="2" column="1" >
+        <widget class="KLineEdit" name="kcfg_screengrabextension" >
+         <property name="sizePolicy" >
+          <sizepolicy vsizetype="Fixed" hsizetype="MinimumExpanding" >
+           <horstretch>0</horstretch>
+           <verstretch>0</verstretch>
+          </sizepolicy>
+         </property>
+         <property name="text" >
+          <string/>
+         </property>
+        </widget>
+       </item>
+       <item row="3" column="0" colspan="2" >
+        <widget class="QCheckBox" name="kcfg_fullscreengrab" >
+         <property name="text" >
+          <string>Full screen capture</string>
+         </property>
+        </widget>
+       </item>
+       <item row="4" column="1" >
+        <spacer name="verticalSpacer_3" >
+         <property name="orientation" >
+          <enum>Qt::Vertical</enum>
+         </property>
+         <property name="sizeHint" stdset="0" >
+          <size>
+           <width>383</width>
+           <height>160</height>
+          </size>
+         </property>
+        </spacer>
+       </item>
+      </layout>
      </widget>
     </widget>
    </item>
index e04a324f62efb1ef58dfebfda7bd98bb67799182..910d2559155c3df287da3dc5b7768f315815eb19 100644 (file)
        <string>Video4Linux</string>
       </property>
      </item>
+     <item>
+      <property name="text" >
+       <string>Screen grab</string>
+      </property>
+     </item>
     </widget>
    </item>
   </layout>