From 029b95a853066adb48fe7f996448b8704d331f95 Mon Sep 17 00:00:00 2001
From: Edric Milaret <edric.ladent-milaret@savoirfairelinux.com>
Date: Tue, 9 Jun 2015 09:51:44 -0400
Subject: [PATCH] video: add video overlay and video view

- Display name and time on top of the video
- Display the call control on the bottom of the video
- Overlay fade (after 2 sec) when mouse exit the widget
- Overlay appear as soon as the mouse enter the widget
- Move logic into VideoView (screen share / fullscreen)
- Remove mute and slider button on callWidget
- Remove call control on callWidget
- Lay the ground work for the move of the im UI

Refs #74270

Change-Id: I024f1f80f18165c23480ef1e68aa970081732bda
---
 RingWinClient.pro               |  13 ++-
 callwidget.cpp                  |  64 +-----------
 callwidget.h                    |  11 +-
 callwidget.ui                   | 106 +------------------
 images/message-text-outline.png | Bin 0 -> 341 bytes
 ressources.qrc                  |   1 +
 videooverlay.cpp                |  69 +++++++++++++
 videooverlay.h                  |  53 ++++++++++
 videooverlay.ui                 | 159 ++++++++++++++++++++++++++++
 videoview.cpp                   | 177 ++++++++++++++++++++++++++++++++
 videoview.h                     |  64 ++++++++++++
 videoview.ui                    |  48 +++++++++
 videowidget.cpp                 |  72 +------------
 videowidget.h                   |  12 ---
 14 files changed, 591 insertions(+), 258 deletions(-)
 create mode 100644 images/message-text-outline.png
 create mode 100644 videooverlay.cpp
 create mode 100644 videooverlay.h
 create mode 100644 videooverlay.ui
 create mode 100644 videoview.cpp
 create mode 100644 videoview.h
 create mode 100644 videoview.ui

diff --git a/RingWinClient.pro b/RingWinClient.pro
index 9d3c16e..2d33702 100644
--- a/RingWinClient.pro
+++ b/RingWinClient.pro
@@ -44,8 +44,9 @@ SOURCES += main.cpp\
     selectareadialog.cpp \
     accountserializationadapter.cpp \
     instantmessagingwidget.cpp \
-    accountstatedelegate.cpp
-
+    accountstatedelegate.cpp \
+    videoview.cpp \
+    videooverlay.cpp
 
 HEADERS  += mainwindow.h \
     callwidget.h \
@@ -65,7 +66,9 @@ HEADERS  += mainwindow.h \
     selectareadialog.h \
     accountserializationadapter.h \
     instantmessagingwidget.h \
-    accountstatedelegate.h
+    accountstatedelegate.h \
+    videoview.h \
+    videooverlay.h
 
 FORMS    += mainwindow.ui \
     callwidget.ui \
@@ -76,7 +79,9 @@ FORMS    += mainwindow.ui \
     aboutdialog.ui \
     pivotviewwidget.ui \
     wizarddialog.ui \
-    instantmessagingwidget.ui
+    instantmessagingwidget.ui \
+    videoview.ui \
+    videooverlay.ui
 
 win32: LIBS += -lole32 -luuid -lshlwapi
 
diff --git a/callwidget.cpp b/callwidget.cpp
index 7374300..8642903 100644
--- a/callwidget.cpp
+++ b/callwidget.cpp
@@ -42,9 +42,6 @@ CallWidget::CallWidget(QWidget *parent) :
 {
     ui->setupUi(this);
 
-    ui->holdButton->setCheckable(true);
-    ui->muteMicButton->setCheckable(true);
-    ui->muteSpeakerButton->setCheckable(true);
     ui->callInvite->setVisible(false);
     ui->videoWidget->setVisible(false);
 
@@ -72,6 +69,7 @@ CallWidget::CallWidget(QWidget *parent) :
                 , SLOT(findRingAccount(QModelIndex, QModelIndex, QVector<int>)));
 
         ui->callList->setModel(callModel_);
+        ui->callList->setSelectionModel(callModel_->selectionModel());
 
         CategorizedHistoryModel::instance()->
                 addCollection<LocalHistoryCollection>(LoadOptions::FORCE_ENABLED);
@@ -96,9 +94,6 @@ CallWidget::CallWidget(QWidget *parent) :
         ui->contactView->setModel(CategorizedContactModel::instance());
         ui->contactView->setItemDelegate(new ContactDelegate());
 
-        ui->speakerSlider->setValue(Audio::Settings::instance()->playbackVolume());
-        ui->micSlider->setValue(Audio::Settings::instance()->captureVolume());
-
         findRingAccount();
 
     } catch (...) {
@@ -229,23 +224,6 @@ CallWidget::on_refuseButton_clicked()
     ui->callInvite->setVisible(false);
 }
 
-void
-CallWidget::on_holdButton_toggled(bool checked)
-{
-    Q_UNUSED(checked)
-    if (actualCall_ == nullptr)
-        return;
-    actualCall_->performAction(Call::Action::HOLD);
-}
-
-void
-CallWidget::on_hangupButton_clicked()
-{
-    if (actualCall_ == nullptr)
-        return;
-    actualCall_->performAction(Call::Action::REFUSE);
-}
-
 void
 CallWidget::addedCall(Call* call, Call* parent) {
     Q_UNUSED(parent);
@@ -264,8 +242,6 @@ CallWidget::callStateChanged(Call* call, Call::State previousState)
     if (call->state() == Call::State::OVER || call->state() == Call::State::ERROR) {
         setActualCall(nullptr);
         ui->videoWidget->hide();
-    } else if (call->state() == Call::State::HOLD) {
-        ui->videoWidget->hide();
     } else if (call->state() == Call::State::CURRENT) {
         ui->videoWidget->show();
     }
@@ -287,42 +263,6 @@ CallWidget::on_callList_activated(const QModelIndex &index)
     ui->videoWidget->show();
 }
 
-void
-CallWidget::on_muteSpeakerButton_toggled(bool checked)
-{
-    Audio::Settings::instance()->mutePlayback(checked);
-}
-
-void
-CallWidget::on_muteMicButton_toggled(bool checked)
-{
-    Audio::Settings::instance()->muteCapture(checked);
-}
-
-void
-CallWidget::on_speakerSlider_sliderMoved(int position)
-{
-    outputVolume_ = position;
-}
-
-void
-CallWidget::on_speakerSlider_sliderReleased()
-{
-    emit Audio::Settings::instance()->setPlaybackVolume(outputVolume_);
-}
-
-void
-CallWidget::on_micSlider_sliderMoved(int position)
-{
-    inputVolume_ = position;
-}
-
-void
-CallWidget::on_micSlider_sliderReleased()
-{
-    emit Audio::Settings::instance()->setCaptureVolume(inputVolume_);
-}
-
 void
 CallWidget::atExit() {
 
@@ -366,8 +306,6 @@ void
 CallWidget::setActualCall(Call* value)
 {
     actualCall_ = value;
-    ui->holdButton->setEnabled(actualCall_ != nullptr);
-    ui->hangupButton->setEnabled(actualCall_ != nullptr);
     ui->instantMessagingWidget->setVisible(actualCall_ != nullptr);
     ui->instantMessagingWidget->setMediaText(actualCall_);
 }
diff --git a/callwidget.h b/callwidget.h
index cbec8b8..ca1a17b 100644
--- a/callwidget.h
+++ b/callwidget.h
@@ -23,6 +23,7 @@
 #include <QVector>
 #include <QString>
 #include <QMenu>
+#include <QItemSelection>
 
 #include "navwidget.h"
 #include "instantmessagingwidget.h"
@@ -50,18 +51,10 @@ public:
 private slots:
     void on_acceptButton_clicked();
     void on_refuseButton_clicked();
-    void on_holdButton_toggled(bool checked);
-    void on_hangupButton_clicked();
-    void on_callList_activated(const QModelIndex &index);
-    void on_muteSpeakerButton_toggled(bool checked);
-    void on_muteMicButton_toggled(bool checked);
-    void on_speakerSlider_sliderMoved(int position);
-    void on_speakerSlider_sliderReleased();
-    void on_micSlider_sliderMoved(int position);
-    void on_micSlider_sliderReleased();
     void on_contactView_doubleClicked(const QModelIndex &index);
     void on_historyList_doubleClicked(const QModelIndex &index);
     void on_sortComboBox_currentIndexChanged(int index);
+    void on_callList_activated(const QModelIndex &index);
 
 private slots:
     void callIncoming(Call *call);
diff --git a/callwidget.ui b/callwidget.ui
index 14c01c7..15ff4a9 100644
--- a/callwidget.ui
+++ b/callwidget.ui
@@ -29,7 +29,7 @@
       <enum>QLayout::SetDefaultConstraint</enum>
      </property>
      <item>
-      <layout class="QVBoxLayout" name="verticalLayout_5" stretch="0,0">
+      <layout class="QVBoxLayout" name="verticalLayout_5" stretch="0,1">
        <property name="topMargin">
         <number>0</number>
        </property>
@@ -189,40 +189,6 @@
        </item>
       </layout>
      </item>
-     <item>
-      <widget class="QPushButton" name="holdButton">
-       <property name="enabled">
-        <bool>false</bool>
-       </property>
-       <property name="text">
-        <string>Hold/Unhold</string>
-       </property>
-       <property name="icon">
-        <iconset>
-         <normaloff>:/images/phone-paused.png</normaloff>:/images/phone-paused.png</iconset>
-       </property>
-      </widget>
-     </item>
-     <item>
-      <widget class="QPushButton" name="hangupButton">
-       <property name="enabled">
-        <bool>false</bool>
-       </property>
-       <property name="sizePolicy">
-        <sizepolicy hsizetype="Minimum" vsizetype="Fixed">
-         <horstretch>0</horstretch>
-         <verstretch>0</verstretch>
-        </sizepolicy>
-       </property>
-       <property name="text">
-        <string>Hangup</string>
-       </property>
-       <property name="icon">
-        <iconset>
-         <normaloff>:/images/phone-hangup.png</normaloff>:/images/phone-hangup.png</iconset>
-       </property>
-      </widget>
-     </item>
     </layout>
    </item>
    <item row="0" column="1">
@@ -253,7 +219,7 @@
         </property>
         <layout class="QVBoxLayout" name="verticalLayout_7">
          <item>
-          <widget class="VideoWidget" name="videoWidget" native="true"/>
+          <widget class="VideoView" name="videoWidget" native="true"/>
          </item>
          <item>
           <widget class="QWidget" name="callInvite" native="true">
@@ -314,70 +280,6 @@
         </property>
        </widget>
       </item>
-      <item>
-       <widget class="QWidget" name="horizontalWidget" native="true">
-        <property name="sizePolicy">
-         <sizepolicy hsizetype="Preferred" vsizetype="Fixed">
-          <horstretch>0</horstretch>
-          <verstretch>0</verstretch>
-         </sizepolicy>
-        </property>
-        <layout class="QHBoxLayout" name="horizontalLayout_2">
-         <item>
-          <widget class="QPushButton" name="muteSpeakerButton">
-           <property name="text">
-            <string/>
-           </property>
-           <property name="icon">
-            <iconset>
-             <normaloff>:/images/speaker-off.png</normaloff>:/images/speaker-off.png</iconset>
-           </property>
-           <property name="iconSize">
-            <size>
-             <width>25</width>
-             <height>25</height>
-            </size>
-           </property>
-          </widget>
-         </item>
-         <item>
-          <widget class="QSlider" name="speakerSlider">
-           <property name="orientation">
-            <enum>Qt::Horizontal</enum>
-           </property>
-          </widget>
-         </item>
-         <item>
-          <widget class="QPushButton" name="muteMicButton">
-           <property name="text">
-            <string/>
-           </property>
-           <property name="icon">
-            <iconset>
-             <normaloff>:/images/microphone-off.png</normaloff>:/images/microphone-off.png</iconset>
-           </property>
-           <property name="iconSize">
-            <size>
-             <width>25</width>
-             <height>25</height>
-            </size>
-           </property>
-          </widget>
-         </item>
-         <item>
-          <widget class="QSlider" name="micSlider">
-           <property name="orientation">
-            <enum>Qt::Horizontal</enum>
-           </property>
-          </widget>
-         </item>
-        </layout>
-        <zorder>micSlider</zorder>
-        <zorder>muteMicButton</zorder>
-        <zorder>speakerSlider</zorder>
-        <zorder>muteSpeakerButton</zorder>
-       </widget>
-      </item>
       <item>
        <widget class="InstantMessagingWidget" name="instantMessagingWidget" native="true">
         <property name="sizePolicy">
@@ -438,9 +340,9 @@
  </widget>
  <customwidgets>
   <customwidget>
-   <class>VideoWidget</class>
+   <class>VideoView</class>
    <extends>QWidget</extends>
-   <header>videowidget.h</header>
+   <header>videoview.h</header>
    <container>1</container>
   </customwidget>
   <customwidget>
diff --git a/images/message-text-outline.png b/images/message-text-outline.png
new file mode 100644
index 0000000000000000000000000000000000000000..a349d68e2c54d94dabc55287c081e09417a10486
GIT binary patch
literal 341
zcmeAS@N?(olHy`uVBq!ia0y~yU@!n-4mJh`hH$2z?F<YIY)RhkE(~Ds(|LD20|NtR
zfk$L90|SEx7`vU!wgU;46*#7Y^n&rZcRk?@3=9uET^vI)?!BGi%XP>=z-|7cDE)-*
zat9w*&ePj7bJ0$RyBb$6%+J*NYh}T|DW{@ek(Z@O;l(1RECt5iily7VQ>WT9ei!X{
z{+dljm+`vjiEnGIrr#}Lv1!~}8pA!g;c$dQa!1T0$N6g`^2`Jms4-o6!?iDyYv0U6
zOZLzE&FRuGYm)JTeKYqL*f(+nEZ)OjS2XR8zXH>hBeo#5E)7!I2P7*NRQ6_1*4gxv
z&FkmI<*wcbqMn@X-<@^w=K0sovt!rH)+p4yFaE%7pZ0;NHF6L9_Q^g7`X~G#Oz!<B
c#}D~?7^a$N95QyE+6@XGPgg&ebxsLQ0A81aN&o-=

literal 0
HcmV?d00001

diff --git a/ressources.qrc b/ressources.qrc
index d2bcfc0..37b1c52 100644
--- a/ressources.qrc
+++ b/ressources.qrc
@@ -24,5 +24,6 @@
         <file>images/spinner.gif</file>
         <file>images/folder-download.png</file>
         <file>images/arrow-right.png</file>
+        <file>images/message-text-outline.png</file>
     </qresource>
 </RCC>
diff --git a/videooverlay.cpp b/videooverlay.cpp
new file mode 100644
index 0000000..a1f90ab
--- /dev/null
+++ b/videooverlay.cpp
@@ -0,0 +1,69 @@
+/***************************************************************************
+ * Copyright (C) 2015 by Savoir-Faire Linux                                *
+ * Author: Edric Ladent Milaret <edric.ladent-milaret@savoirfairelinux.com>*
+ *                                                                         *
+ * 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 3 of the License, or       *
+ * (at your option) any later version.                                     *
+ *                                                                         *
+ * 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 General Public License       *
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.   *
+ **************************************************************************/
+
+#include "videooverlay.h"
+#include "ui_videooverlay.h"
+
+#include "callmodel.h"
+
+VideoOverlay::VideoOverlay(QWidget *parent) :
+    QWidget(parent),
+    ui(new Ui::VideoOverlay)
+{
+    ui->setupUi(this);
+
+    actionModel_ = CallModel::instance()->userActionModel();
+    setAttribute(Qt::WA_NoSystemBackground);
+}
+
+VideoOverlay::~VideoOverlay()
+{
+    delete ui;
+}
+
+void
+VideoOverlay::setName(const QString& name)
+{
+    ui->nameLabel->setText(name);
+}
+
+void
+VideoOverlay::setTime(const QString& time)
+{
+    ui->timerLabel->setText(time);
+}
+
+void
+VideoOverlay::on_holdButton_toggled(bool checked)
+{
+    Q_UNUSED(checked)
+    actionModel_->execute(UserActionModel::Action::HOLD);
+}
+
+void
+VideoOverlay::on_hangupButton_clicked()
+{
+    actionModel_->execute(UserActionModel::Action::HANGUP);
+}
+
+void
+VideoOverlay::on_chatButton_toggled(bool checked)
+{
+    //TODO : Link this to im class once it's merged
+}
+
diff --git a/videooverlay.h b/videooverlay.h
new file mode 100644
index 0000000..31dc6fb
--- /dev/null
+++ b/videooverlay.h
@@ -0,0 +1,53 @@
+/***************************************************************************
+ * Copyright (C) 2015 by Savoir-Faire Linux                                *
+ * Author: Edric Ladent Milaret <edric.ladent-milaret@savoirfairelinux.com>*
+ *                                                                         *
+ * 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 3 of the License, or       *
+ * (at your option) any later version.                                     *
+ *                                                                         *
+ * 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 General Public License       *
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.   *
+ **************************************************************************/
+
+#ifndef VIDEOOVERLAY_H
+#define VIDEOOVERLAY_H
+
+#include <QWidget>
+
+#include "useractionmodel.h"
+
+namespace Ui {
+class VideoOverlay;
+}
+
+class VideoOverlay : public QWidget
+{
+    Q_OBJECT
+
+public:
+    explicit VideoOverlay(QWidget *parent = 0);
+    ~VideoOverlay();
+
+public:
+    void setName(const QString &name);
+    void setTime(const QString &time);
+
+//UI SLOTS
+private slots:
+    void on_holdButton_toggled(bool checked);
+    void on_hangupButton_clicked();
+    void on_chatButton_toggled(bool checked);
+
+private:
+    Ui::VideoOverlay *ui;
+    UserActionModel* actionModel_;
+};
+
+#endif // VIDEOOVERLAY_H
diff --git a/videooverlay.ui b/videooverlay.ui
new file mode 100644
index 0000000..2feb34a
--- /dev/null
+++ b/videooverlay.ui
@@ -0,0 +1,159 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>VideoOverlay</class>
+ <widget class="QWidget" name="VideoOverlay">
+  <property name="geometry">
+   <rect>
+    <x>0</x>
+    <y>0</y>
+    <width>724</width>
+    <height>507</height>
+   </rect>
+  </property>
+  <property name="windowTitle">
+   <string>Form</string>
+  </property>
+  <layout class="QGridLayout" name="gridLayout">
+   <item row="1" column="2">
+    <widget class="QPushButton" name="hangupButton">
+     <property name="text">
+      <string>Hangup</string>
+     </property>
+    </widget>
+   </item>
+   <item row="1" column="1">
+    <widget class="QPushButton" name="holdButton">
+     <property name="text">
+      <string>Hold</string>
+     </property>
+     <property name="checkable">
+      <bool>true</bool>
+     </property>
+    </widget>
+   </item>
+   <item row="1" column="3">
+    <widget class="QPushButton" name="chatButton">
+     <property name="text">
+      <string>Chat</string>
+     </property>
+    </widget>
+   </item>
+   <item row="1" column="0">
+    <spacer name="horizontalSpacer">
+     <property name="orientation">
+      <enum>Qt::Horizontal</enum>
+     </property>
+     <property name="sizeHint" stdset="0">
+      <size>
+       <width>40</width>
+       <height>20</height>
+      </size>
+     </property>
+    </spacer>
+   </item>
+   <item row="1" column="4">
+    <spacer name="horizontalSpacer_2">
+     <property name="orientation">
+      <enum>Qt::Horizontal</enum>
+     </property>
+     <property name="sizeHint" stdset="0">
+      <size>
+       <width>40</width>
+       <height>20</height>
+      </size>
+     </property>
+    </spacer>
+   </item>
+   <item row="0" column="0" alignment="Qt::AlignTop">
+    <widget class="QLabel" name="nameLabel">
+     <property name="palette">
+      <palette>
+       <active>
+        <colorrole role="WindowText">
+         <brush brushstyle="SolidPattern">
+          <color alpha="255">
+           <red>255</red>
+           <green>255</green>
+           <blue>255</blue>
+          </color>
+         </brush>
+        </colorrole>
+       </active>
+       <inactive>
+        <colorrole role="WindowText">
+         <brush brushstyle="SolidPattern">
+          <color alpha="255">
+           <red>255</red>
+           <green>255</green>
+           <blue>255</blue>
+          </color>
+         </brush>
+        </colorrole>
+       </inactive>
+       <disabled>
+        <colorrole role="WindowText">
+         <brush brushstyle="SolidPattern">
+          <color alpha="255">
+           <red>143</red>
+           <green>146</green>
+           <blue>147</blue>
+          </color>
+         </brush>
+        </colorrole>
+       </disabled>
+      </palette>
+     </property>
+     <property name="text">
+      <string/>
+     </property>
+    </widget>
+   </item>
+   <item row="0" column="4" alignment="Qt::AlignRight|Qt::AlignTop">
+    <widget class="QLabel" name="timerLabel">
+     <property name="palette">
+      <palette>
+       <active>
+        <colorrole role="WindowText">
+         <brush brushstyle="SolidPattern">
+          <color alpha="255">
+           <red>255</red>
+           <green>255</green>
+           <blue>255</blue>
+          </color>
+         </brush>
+        </colorrole>
+       </active>
+       <inactive>
+        <colorrole role="WindowText">
+         <brush brushstyle="SolidPattern">
+          <color alpha="255">
+           <red>255</red>
+           <green>255</green>
+           <blue>255</blue>
+          </color>
+         </brush>
+        </colorrole>
+       </inactive>
+       <disabled>
+        <colorrole role="WindowText">
+         <brush brushstyle="SolidPattern">
+          <color alpha="255">
+           <red>143</red>
+           <green>146</green>
+           <blue>147</blue>
+          </color>
+         </brush>
+        </colorrole>
+       </disabled>
+      </palette>
+     </property>
+     <property name="text">
+      <string>00:00</string>
+     </property>
+    </widget>
+   </item>
+  </layout>
+ </widget>
+ <resources/>
+ <connections/>
+</ui>
diff --git a/videoview.cpp b/videoview.cpp
new file mode 100644
index 0000000..a6305e9
--- /dev/null
+++ b/videoview.cpp
@@ -0,0 +1,177 @@
+/***************************************************************************
+ * Copyright (C) 2015 by Savoir-Faire Linux                                *
+ * Author: Edric Ladent Milaret <edric.ladent-milaret@savoirfairelinux.com>*
+ *                                                                         *
+ * 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 3 of the License, or       *
+ * (at your option) any later version.                                     *
+ *                                                                         *
+ * 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 General Public License       *
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.   *
+ **************************************************************************/
+
+#include "videoview.h"
+#include "ui_videoview.h"
+
+#include "callmodel.h"
+#include "video/devicemodel.h"
+#include "video/sourcemodel.h"
+
+#include <QGraphicsOpacityEffect>
+#include <QPropertyAnimation>
+#include <QDesktopWidget>
+#include <QMenu>
+
+#include <memory>
+
+#include "videooverlay.h"
+#include "selectareadialog.h"
+
+VideoView::VideoView(QWidget *parent) :
+    QWidget(parent),
+    ui(new Ui::VideoView)
+{
+    ui->setupUi(this);
+
+    connect(CallModel::instance(), SIGNAL(callStateChanged(Call*, Call::State)),
+            this, SLOT(callStateChanged(Call*, Call::State)));
+
+    overlay_ = new VideoOverlay(this);
+    auto effect = new QGraphicsOpacityEffect(overlay_);
+    effect->setOpacity(1.0);
+    overlay_->setGraphicsEffect(effect);
+    fadeAnim_ = new QPropertyAnimation(this);
+    fadeAnim_->setTargetObject(effect);
+    fadeAnim_->setPropertyName("opacity");
+    fadeAnim_->setDuration(fadeOverlayTime_);
+    fadeAnim_->setStartValue(effect->opacity());
+    fadeAnim_->setEndValue(0);
+    fadeAnim_->setEasingCurve(QEasingCurve::OutQuad);
+
+    timerLength_ =  new QTimer(this);
+    connect(timerLength_, SIGNAL(timeout()), this, SLOT(updateTimer()));
+
+    this->setContextMenuPolicy(Qt::CustomContextMenu);
+    connect(this, SIGNAL(customContextMenuRequested(const QPoint&)),
+        this, SLOT(showContextMenu(const QPoint&)));
+}
+
+VideoView::~VideoView()
+{
+    delete ui;
+}
+
+void
+VideoView::resizeEvent(QResizeEvent *event)
+{
+    Q_UNUSED(event)
+    overlay_->resize(this->size());
+    overlay_->show();
+    overlay_->raise();
+}
+
+void
+VideoView::enterEvent(QEvent* event)
+{
+    Q_UNUSED(event)
+    fadeAnim_->stop();
+    fadeAnim_->targetObject()->setProperty(fadeAnim_->propertyName(), fadeAnim_->startValue());
+}
+
+void
+VideoView::leaveEvent(QEvent* event)
+{
+    Q_UNUSED(event)
+    fadeAnim_->start(QAbstractAnimation::KeepWhenStopped);
+}
+
+void
+VideoView::callStateChanged(Call* call, Call::State previousState)
+{
+   Q_UNUSED(previousState)
+    if (call->state() == Call::State::CURRENT) {
+        ui->videoWidget->show();
+        timerLength_->start(1000);
+        overlay_->setName(call->formattedName());
+    }
+    else {
+        ui->videoWidget->hide();
+        if (isFullScreen())
+            toggleFullScreen();
+        timerLength_->stop();
+    }
+}
+
+void
+VideoView::updateTimer()
+{
+    overlay_->setTime(CallModel::instance()->selectedCall()->length());
+}
+
+void
+VideoView::mouseDoubleClickEvent(QMouseEvent* e) {
+    QWidget::mouseDoubleClickEvent(e);
+    toggleFullScreen();
+}
+
+void
+VideoView::toggleFullScreen()
+{
+    if(isFullScreen()) {
+        this->setParent(oldParent_);
+        this->showNormal();
+        this->resize(oldSize_.width(), oldSize_.height());
+    } else {
+        oldSize_ = this->size();
+        oldParent_ = static_cast<QWidget*>(this->parent());
+        this->setParent(0);
+        this->showFullScreen();
+        this->show();
+    }
+}
+
+void
+VideoView::showContextMenu(const QPoint& pos)
+{
+    QPoint globalPos = this->mapToGlobal(pos);
+
+    QMenu menu;
+
+    for (auto device : Video::DeviceModel::instance()->devices()) {
+        std::unique_ptr<QAction> deviceAction(new QAction(device->name(), this));
+        deviceAction->setCheckable(true);
+        if (device == Video::DeviceModel::instance()->activeDevice())
+            deviceAction->setChecked(true);
+        auto ptr = deviceAction.release();
+        menu.addAction(ptr);
+        connect(ptr, &QAction::toggled, [=](bool checked) {
+            if (checked == true) {
+                Video::SourceModel::instance()->switchTo(device);
+                Video::DeviceModel::instance()->setActive(device);
+            }
+        });
+    }
+
+    menu.addSeparator();
+
+    auto shareAction = new QAction("Share entire screen", this);
+    menu.addAction(shareAction);
+    connect(shareAction, &QAction::triggered, [=]() {
+        Video::SourceModel::instance()->setDisplay(0, QApplication::desktop()->rect());
+    });
+    auto shareAreaAction = new QAction("Share screen area", this);
+    menu.addAction(shareAreaAction);
+    connect(shareAreaAction, &QAction::triggered, [=]() {
+        SelectAreaDialog selec;
+        selec.exec();
+    });
+
+    menu.exec(globalPos);
+}
+
diff --git a/videoview.h b/videoview.h
new file mode 100644
index 0000000..49a8cde
--- /dev/null
+++ b/videoview.h
@@ -0,0 +1,64 @@
+/***************************************************************************
+ * Copyright (C) 2015 by Savoir-Faire Linux                                *
+ * Author: Edric Ladent Milaret <edric.ladent-milaret@savoirfairelinux.com>*
+ *                                                                         *
+ * 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 3 of the License, or       *
+ * (at your option) any later version.                                     *
+ *                                                                         *
+ * 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 General Public License       *
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.   *
+ **************************************************************************/
+
+#ifndef VIDEOVIEW_H
+#define VIDEOVIEW_H
+
+#include <QWidget>
+#include <QTimer>
+#include <QMouseEvent>
+#include <QPropertyAnimation>
+
+#include "videooverlay.h"
+
+namespace Ui {
+class VideoView;
+}
+
+class VideoView : public QWidget
+{
+    Q_OBJECT
+
+public:
+    explicit VideoView(QWidget *parent = 0);
+    ~VideoView();
+
+protected:
+    void resizeEvent(QResizeEvent* event);
+    void enterEvent(QEvent* event);
+    void leaveEvent(QEvent* event);
+    void mouseDoubleClickEvent(QMouseEvent *e);
+
+private slots:
+    void callStateChanged(Call *call, Call::State previousState);
+    void updateTimer();
+    void showContextMenu(const QPoint &pos);
+
+private:
+    Ui::VideoView *ui;
+    QTimer* timerLength_;
+    VideoOverlay* overlay_;
+    constexpr static int fadeOverlayTime_ = 2000; //msec
+    QPropertyAnimation* fadeAnim_;
+    QWidget *oldParent_;
+    QSize oldSize_;
+private:
+    void toggleFullScreen();
+};
+
+#endif // VIDEOVIEW_H
diff --git a/videoview.ui b/videoview.ui
new file mode 100644
index 0000000..5c8d46d
--- /dev/null
+++ b/videoview.ui
@@ -0,0 +1,48 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>VideoView</class>
+ <widget class="QWidget" name="VideoView">
+  <property name="geometry">
+   <rect>
+    <x>0</x>
+    <y>0</y>
+    <width>845</width>
+    <height>522</height>
+   </rect>
+  </property>
+  <property name="windowTitle">
+   <string>Form</string>
+  </property>
+  <layout class="QGridLayout" name="gridLayout">
+   <property name="leftMargin">
+    <number>0</number>
+   </property>
+   <property name="topMargin">
+    <number>0</number>
+   </property>
+   <property name="rightMargin">
+    <number>0</number>
+   </property>
+   <property name="bottomMargin">
+    <number>0</number>
+   </property>
+   <item row="0" column="0">
+    <widget class="VideoWidget" name="videoWidget" native="true">
+     <property name="enabled">
+      <bool>false</bool>
+     </property>
+    </widget>
+   </item>
+  </layout>
+ </widget>
+ <customwidgets>
+  <customwidget>
+   <class>VideoWidget</class>
+   <extends>QWidget</extends>
+   <header>videowidget.h</header>
+   <container>1</container>
+  </customwidget>
+ </customwidgets>
+ <resources/>
+ <connections/>
+</ui>
diff --git a/videowidget.cpp b/videowidget.cpp
index 9654092..cef4915 100644
--- a/videowidget.cpp
+++ b/videowidget.cpp
@@ -18,15 +18,6 @@
 
 #include "videowidget.h"
 
-#include <QApplication>
-#include <QDesktopWidget>
-
-#include <memory>
-
-#include "video/devicemodel.h"
-
-#include "selectareadialog.h"
-
 VideoWidget::VideoWidget(QWidget *parent) :
     QWidget(parent)
   , previewRenderer_(nullptr)
@@ -46,10 +37,6 @@ VideoWidget::VideoWidget(QWidget *parent) :
     pal.setColor(QPalette::Background, Qt::black);
     this->setAutoFillBackground(true);
     this->setPalette(pal);
-
-    this->setContextMenuPolicy(Qt::CustomContextMenu);
-    connect(this, SIGNAL(customContextMenuRequested(const QPoint&)),
-        this, SLOT(showContextMenu(const QPoint&)));
 }
 
 VideoWidget::~VideoWidget()
@@ -67,6 +54,10 @@ VideoWidget::previewStarted(Video::Renderer *renderer) {
 void
 VideoWidget::previewStopped() {
     QMutexLocker {&lock_};
+    if (previewFrame_) {
+        delete previewFrame_;
+        previewFrame_ = nullptr;
+    }
     disconnect(previewRenderer_, SIGNAL(frameUpdated()),
             this, SLOT(frameFromPreview()));
     disconnect(previewRenderer_, SIGNAL(stopped()),
@@ -150,58 +141,3 @@ VideoWidget::renderingStopped() {
     disconnect(renderer_, SIGNAL(stopped()),this, SLOT(renderingStopped()));
     renderer_ = nullptr;
 }
-
-void
-VideoWidget::mouseDoubleClickEvent(QMouseEvent *e) {
-    QWidget::mouseDoubleClickEvent(e);
-    if(isFullScreen()) {
-        this->setParent(oldParent_);
-        this->showNormal();
-        this->resize(oldSize_.width(), oldSize_.height());
-    } else {
-        oldSize_ = this->size();
-        oldParent_ = static_cast<QWidget*>(this->parent());
-        this->setParent(0);
-        this->showFullScreen();
-        this->show();
-    }
-}
-
-void
-VideoWidget::showContextMenu(const QPoint& pos)
-{
-    QPoint globalPos = this->mapToGlobal(pos);
-
-    QMenu menu;
-
-    for (auto device : Video::DeviceModel::instance()->devices()) {
-        std::unique_ptr<QAction> deviceAction(new QAction(device->name(), this));
-        deviceAction->setCheckable(true);
-        if (device == Video::DeviceModel::instance()->activeDevice())
-            deviceAction->setChecked(true);
-        auto ptr = deviceAction.release();
-        menu.addAction(ptr);
-        connect(ptr, &QAction::toggled, [=](bool checked) {
-            if (checked == true) {
-                Video::SourceModel::instance()->switchTo(device);
-                Video::DeviceModel::instance()->setActive(device);
-            }
-        });
-    }
-
-    menu.addSeparator();
-
-    auto shareAction = new QAction("Share entire screen", this);
-    menu.addAction(shareAction);
-    connect(shareAction, &QAction::triggered, [=]() {
-        Video::SourceModel::instance()->setDisplay(0, QApplication::desktop()->rect());
-    });
-    auto shareAreaAction = new QAction("Share screen area", this);
-    menu.addAction(shareAreaAction);
-    connect(shareAreaAction, &QAction::triggered, [=]() {
-        SelectAreaDialog selec;
-        selec.exec();
-    });
-
-    menu.exec(globalPos);
-}
diff --git a/videowidget.h b/videowidget.h
index 0a0b459..8846279 100644
--- a/videowidget.h
+++ b/videowidget.h
@@ -23,11 +23,9 @@
 #include <QPainter>
 #include <QMutex>
 #include <QPixmap>
-#include <QMenu>
 
 #include "video/renderer.h"
 #include "video/previewmanager.h"
-#include "video/sourcemodel.h"
 #include "callmodel.h"
 
 class VideoWidget : public QWidget
@@ -46,22 +44,12 @@ public slots:
     void frameFromDistant();
     void renderingStopped();
 
-
-protected slots:
-    void mouseDoubleClickEvent(QMouseEvent *e);
-
-private slots:
-    void showContextMenu(const QPoint &pos);
-
 private:
     Video::Renderer* previewRenderer_;
     Video::Renderer* renderer_;
     QImage *previewFrame_;
     QImage *distantFrame_;
     QMutex lock_;
-    QPixmap *previewPix_;
-    QWidget *oldParent_;
-    QSize oldSize_;
     constexpr static int previewMargin_ = 15;
 };
 
-- 
GitLab