From 864a2050af673374135a26b515cfff21028a646a Mon Sep 17 00:00:00 2001
From: Edric Milaret <edric.ladent-milaret@savoirfairelinux.com>
Date: Thu, 14 Jan 2016 15:45:03 -0500
Subject: [PATCH] ui: add quality button

- Add the slider and the auto quality checkbox
- This a an adaptation of Stepan code

Change-Id: I04bd33dbc6b9f7042617443ce42f9c6162971282
Tuleap: #215
---
 RingWinClient.pro                           |   9 +-
 images/video-conf/ic_high_quality_white.svg |   4 +
 qualitydialog.cpp                           | 116 ++++++++++++++
 qualitydialog.h                             |  45 ++++++
 qualitydialog.ui                            |  93 +++++++++++
 ressources.qrc                              |   1 +
 stylesheet.css                              |   6 +
 videooverlay.cpp                            |  20 ++-
 videooverlay.h                              |   3 +
 videooverlay.ui                             | 163 +++++++++++---------
 10 files changed, 384 insertions(+), 76 deletions(-)
 create mode 100644 images/video-conf/ic_high_quality_white.svg
 create mode 100644 qualitydialog.cpp
 create mode 100644 qualitydialog.h
 create mode 100644 qualitydialog.ui

diff --git a/RingWinClient.pro b/RingWinClient.pro
index c67fdac..693af7b 100644
--- a/RingWinClient.pro
+++ b/RingWinClient.pro
@@ -67,7 +67,8 @@ SOURCES += main.cpp\
     mainwindowtoolbar.cpp \
     ringcontactlineedit.cpp \
     smartlistscrollbar.cpp \
-    pixbufmanipulator.cpp
+    pixbufmanipulator.cpp \
+    qualitydialog.cpp
 
 HEADERS  += mainwindow.h \
     callwidget.h \
@@ -102,7 +103,8 @@ HEADERS  += mainwindow.h \
     mainwindowtoolbar.h \
     ringcontactlineedit.h \
     smartlistscrollbar.h \
-    pixbufmanipulator.h
+    pixbufmanipulator.h \
+    qualitydialog.h
 
 FORMS    += mainwindow.ui \
     callwidget.ui \
@@ -117,7 +119,8 @@ FORMS    += mainwindow.ui \
     contactpicker.ui \
     contactmethodpicker.ui \
     callutilsdialog.ui \
-    combar.ui
+    combar.ui \
+    qualitydialog.ui
 
 win32: LIBS += -lole32 -luuid -lshlwapi
 
diff --git a/images/video-conf/ic_high_quality_white.svg b/images/video-conf/ic_high_quality_white.svg
new file mode 100644
index 0000000..ad4091c
--- /dev/null
+++ b/images/video-conf/ic_high_quality_white.svg
@@ -0,0 +1,4 @@
+<svg fill="#FFFFFF" height="48" viewBox="0 0 24 24" width="48" xmlns="http://www.w3.org/2000/svg">
+    <path d="M0 0h24v24H0z" fill="none"/>
+    <path d="M19 4H5c-1.11 0-2 .9-2 2v12c0 1.1.89 2 2 2h14c1.1 0 2-.9 2-2V6c0-1.1-.9-2-2-2zm-8 11H9.5v-2h-2v2H6V9h1.5v2.5h2V9H11v6zm7-1c0 .55-.45 1-1 1h-.75v1.5h-1.5V15H14c-.55 0-1-.45-1-1v-4c0-.55.45-1 1-1h3c.55 0 1 .45 1 1v4zm-3.5-.5h2v-3h-2v3z"/>
+</svg>
\ No newline at end of file
diff --git a/qualitydialog.cpp b/qualitydialog.cpp
new file mode 100644
index 0000000..589e5be
--- /dev/null
+++ b/qualitydialog.cpp
@@ -0,0 +1,116 @@
+/***************************************************************************
+ * Copyright (C) 2016 by Savoir-faire Linux                                *
+ * Author: Edric Ladent Milaret <edric.ladent-milaret@savoirfairelinux.com>*
+ * Author: Stepan Salenikovich <stepan.salenikovich@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 "qualitydialog.h"
+#include "ui_qualitydialog.h"
+
+#include "callmodel.h"
+#include "account.h"
+#include "audio/codecmodel.h"
+
+#include <QSortFilterProxyModel>
+
+QualityDialog::QualityDialog(QWidget *parent) :
+    QDialog(parent),
+    ui(new Ui::QualityDialog)
+{
+    ui->setupUi(this);
+
+    this->setWindowFlags(Qt::CustomizeWindowHint);
+    this->setWindowFlags(Qt::FramelessWindowHint | Qt::Popup);
+}
+
+QualityDialog::~QualityDialog()
+{
+    delete ui;
+}
+
+void
+QualityDialog::on_autoCheckBox_toggled(bool checked)
+{
+    setQuality();
+    ui->qualitySlider->setEnabled(not checked);
+}
+
+
+void
+QualityDialog::on_qualitySlider_sliderReleased()
+{
+    setQuality();
+}
+
+void QualityDialog::showEvent(QShowEvent* event) {
+    QWidget::showEvent(event);
+    ui->autoCheckBox->blockSignals(true);
+    const auto& call = CallModel::instance().selectedCall();
+    if (const auto& codecModel = call->account()->codecModel()) {
+        const auto& videoCodecs = codecModel->videoCodecs();
+        if (videoCodecs->rowCount() > 0) {
+            /* we only need to check the first codec since by default it is ON for all, and the
+             *  client sets its ON or OFF for all codecs as well */
+            const auto& idx = videoCodecs->index(0,0);
+            auto auto_quality_enabled = idx.data(static_cast<int>(CodecModel::Role::AUTO_QUALITY_ENABLED)).toString() == "true";
+            ui->autoCheckBox->setChecked(auto_quality_enabled);
+            ui->qualitySlider->setEnabled(not auto_quality_enabled);
+
+            // TODO: save the manual quality setting in the client and set the slider to that value here;
+            //       the daemon resets the bitrate/quality between each call, and the default may be
+            //       different for each codec, so there is no reason to check it here
+        }
+    }
+    ui->autoCheckBox->blockSignals(false);
+}
+
+void
+QualityDialog::setQuality()
+{
+    /* set auto quality true or false, also set the bitrate and quality values;
+     * the slider is from 0 to 100, use the min and max vals to scale each value accordingly */
+    const auto& call = CallModel::instance().selectedCall();
+    if (const auto& codecModel = call->account()->codecModel()) {
+        const auto& videoCodecs = codecModel->videoCodecs();
+
+        for (int i=0; i < videoCodecs->rowCount();i++) {
+            const auto& idx = videoCodecs->index(i,0);
+
+            if (ui->autoCheckBox->isChecked()) {
+                videoCodecs->setData(idx, "true", CodecModel::Role::AUTO_QUALITY_ENABLED);
+            } else {
+                auto min_bitrate = idx.data(static_cast<int>(CodecModel::Role::MIN_BITRATE)).toInt();
+                auto max_bitrate = idx.data(static_cast<int>(CodecModel::Role::MAX_BITRATE)).toInt();
+                auto min_quality = idx.data(static_cast<int>(CodecModel::Role::MIN_QUALITY)).toInt();
+                auto max_quality = idx.data(static_cast<int>(CodecModel::Role::MAX_QUALITY)).toInt();
+
+                double bitrate;
+                bitrate = min_bitrate + (double)(max_bitrate - min_bitrate)*(ui->qualitySlider->value()/100.0);
+                if (bitrate < 0) bitrate = 0;
+
+                double quality;
+                // note: a lower value means higher quality
+                quality = (double)min_quality - (min_quality - max_quality)*(ui->qualitySlider->value()/100.0);
+                if (quality < 0) quality = 0;
+
+                videoCodecs->setData(idx, "false", CodecModel::Role::AUTO_QUALITY_ENABLED);
+                videoCodecs->setData(idx, QString::number((int)bitrate), CodecModel::Role::BITRATE);
+                videoCodecs->setData(idx, QString::number((int)quality), CodecModel::Role::QUALITY);
+            }
+        }
+        codecModel << CodecModel::EditAction::SAVE;
+    }
+}
diff --git a/qualitydialog.h b/qualitydialog.h
new file mode 100644
index 0000000..17c4428
--- /dev/null
+++ b/qualitydialog.h
@@ -0,0 +1,45 @@
+/***************************************************************************
+ * Copyright (C) 2016 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/>.   *
+ **************************************************************************/
+
+#pragma once
+
+#include <QDialog>
+
+namespace Ui {
+class QualityDialog;
+}
+
+class QualityDialog : public QDialog
+{
+    Q_OBJECT
+
+public:
+    explicit QualityDialog(QWidget *parent = 0);
+    ~QualityDialog();
+
+protected:
+    void showEvent(QShowEvent* event);
+
+private slots:
+    void on_autoCheckBox_toggled(bool checked);
+    void on_qualitySlider_sliderReleased();
+
+private:
+    Ui::QualityDialog *ui;
+    void setQuality();
+};
diff --git a/qualitydialog.ui b/qualitydialog.ui
new file mode 100644
index 0000000..3c051e6
--- /dev/null
+++ b/qualitydialog.ui
@@ -0,0 +1,93 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>QualityDialog</class>
+ <widget class="QDialog" name="QualityDialog">
+  <property name="geometry">
+   <rect>
+    <x>0</x>
+    <y>0</y>
+    <width>73</width>
+    <height>194</height>
+   </rect>
+  </property>
+  <property name="windowTitle">
+   <string>Dialog</string>
+  </property>
+  <layout class="QVBoxLayout" name="verticalLayout">
+   <property name="leftMargin">
+    <number>0</number>
+   </property>
+   <property name="topMargin">
+    <number>5</number>
+   </property>
+   <property name="rightMargin">
+    <number>0</number>
+   </property>
+   <property name="bottomMargin">
+    <number>0</number>
+   </property>
+   <item>
+    <layout class="QHBoxLayout" name="horizontalLayout">
+     <property name="bottomMargin">
+      <number>0</number>
+     </property>
+     <item>
+      <widget class="QSlider" name="qualitySlider">
+       <property name="maximum">
+        <number>100</number>
+       </property>
+       <property name="value">
+        <number>50</number>
+       </property>
+       <property name="orientation">
+        <enum>Qt::Vertical</enum>
+       </property>
+      </widget>
+     </item>
+    </layout>
+   </item>
+   <item>
+    <layout class="QHBoxLayout" name="horizontalLayout_2">
+     <property name="bottomMargin">
+      <number>0</number>
+     </property>
+     <item>
+      <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>
+      <widget class="QCheckBox" name="autoCheckBox">
+       <property name="text">
+        <string>Auto</string>
+       </property>
+      </widget>
+     </item>
+     <item>
+      <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>
+    </layout>
+   </item>
+  </layout>
+ </widget>
+ <resources/>
+ <connections/>
+</ui>
diff --git a/ressources.qrc b/ressources.qrc
index 964548e..f3010b8 100644
--- a/ressources.qrc
+++ b/ressources.qrc
@@ -41,5 +41,6 @@
         <file>images/video-conf/btn-transfer.svg</file>
         <file>images/btn-info.svg</file>
         <file>images/ic_arrow_back_white.svg</file>
+        <file>images/video-conf/ic_high_quality_white.svg</file>
     </qresource>
 </RCC>
diff --git a/stylesheet.css b/stylesheet.css
index a588c52..da4912b 100644
--- a/stylesheet.css
+++ b/stylesheet.css
@@ -119,3 +119,9 @@ QPushButton#imBackButton {
    border-radius: 15px;
    border:solid 1px;
 }
+
+QPushButton#qualityButton {
+   background-color: rgba(0, 0, 0, 140);
+   border-radius: 18px;
+   border:solid 1px;
+}
diff --git a/videooverlay.cpp b/videooverlay.cpp
index 369f435..5d02898 100644
--- a/videooverlay.cpp
+++ b/videooverlay.cpp
@@ -24,7 +24,8 @@
 VideoOverlay::VideoOverlay(QWidget* parent) :
     QWidget(parent),
     ui(new Ui::VideoOverlay),
-    transferDialog_(new CallUtilsDialog())
+    transferDialog_(new CallUtilsDialog()),
+    qualityDialog_(new QualityDialog())
 {
     ui->setupUi(this);
 
@@ -35,6 +36,11 @@ VideoOverlay::VideoOverlay(QWidget* parent) :
 
     ui->noMicButton->setCheckable(true);
 
+    QPixmap pixmap(":/images/video-conf/ic_high_quality_white.svg");
+    QIcon qualityIcon(pixmap);
+    ui->qualityButton->setIcon(qualityIcon);
+    ui->qualityButton->setIconSize(pixmap.rect().size());
+
     connect(actionModel_,&UserActionModel::dataChanged, [=](const QModelIndex& tl, const QModelIndex& br) {
         const int first(tl.row()),last(br.row());
         for(int i = first; i <= last;i++) {
@@ -85,6 +91,7 @@ VideoOverlay::~VideoOverlay()
 {
     delete ui;
     delete transferDialog_;
+    delete qualityDialog_;
 }
 
 void
@@ -159,3 +166,14 @@ void VideoOverlay::on_joinButton_clicked()
 {
     CallModel::instance().selectedCall()->joinToParent();
 }
+
+void
+VideoOverlay::on_qualityButton_clicked()
+{
+    auto pos = this->mapToGlobal(ui->qualityButton->pos());
+    qualityDialog_->move(pos.x()
+              - qualityDialog_->size().width()/2
+              + ui->qualityButton->size().width()/2,
+              pos.y() - (qualityDialog_->height()));
+    qualityDialog_->show();
+}
diff --git a/videooverlay.h b/videooverlay.h
index 68d4980..322ad62 100644
--- a/videooverlay.h
+++ b/videooverlay.h
@@ -24,6 +24,7 @@
 #include "useractionmodel.h"
 
 #include "callutilsdialog.h"
+#include "qualitydialog.h"
 
 namespace Ui {
 class VideoOverlay;
@@ -51,11 +52,13 @@ private slots:
     void on_joinButton_clicked();
     void on_noMicButton_clicked();
     void on_noVideoButton_clicked();
+    void on_qualityButton_clicked();
 
 private:
     Ui::VideoOverlay* ui;
     UserActionModel* actionModel_;
     CallUtilsDialog* transferDialog_;
+    QualityDialog* qualityDialog_;
 
 signals:
     void setChatVisibility(bool visible);
diff --git a/videooverlay.ui b/videooverlay.ui
index 81b97b1..9301b00 100644
--- a/videooverlay.ui
+++ b/videooverlay.ui
@@ -23,8 +23,27 @@
    <string/>
   </property>
   <layout class="QGridLayout" name="gridLayout">
-   <item row="0" column="10" alignment="Qt::AlignRight|Qt::AlignTop">
-    <widget class="QLabel" name="timerLabel">
+   <item row="1" column="1">
+    <widget class="QPushButton" name="hangupButton">
+     <property name="minimumSize">
+      <size>
+       <width>36</width>
+       <height>36</height>
+      </size>
+     </property>
+     <property name="maximumSize">
+      <size>
+       <width>36</width>
+       <height>36</height>
+      </size>
+     </property>
+     <property name="text">
+      <string/>
+     </property>
+    </widget>
+   </item>
+   <item row="0" column="0" alignment="Qt::AlignTop">
+    <widget class="QLabel" name="nameLabel">
      <property name="palette">
       <palette>
        <active>
@@ -63,12 +82,12 @@
       </palette>
      </property>
      <property name="text">
-      <string>00:00</string>
+      <string/>
      </property>
     </widget>
    </item>
-   <item row="1" column="5">
-    <widget class="QPushButton" name="addPersonButton">
+   <item row="1" column="6">
+    <widget class="QPushButton" name="joinButton">
      <property name="minimumSize">
       <size>
        <width>36</width>
@@ -86,14 +105,8 @@
      </property>
     </widget>
    </item>
-   <item row="1" column="9">
-    <widget class="QPushButton" name="noVideoButton">
-     <property name="sizePolicy">
-      <sizepolicy hsizetype="Minimum" vsizetype="Minimum">
-       <horstretch>0</horstretch>
-       <verstretch>0</verstretch>
-      </sizepolicy>
-     </property>
+   <item row="1" column="2">
+    <widget class="QPushButton" name="holdButton">
      <property name="minimumSize">
       <size>
        <width>36</width>
@@ -114,27 +127,14 @@
      </property>
     </widget>
    </item>
-   <item row="1" column="7">
-    <widget class="QPushButton" name="transferButton">
-     <property name="minimumSize">
-      <size>
-       <width>36</width>
-       <height>36</height>
-      </size>
-     </property>
-     <property name="maximumSize">
-      <size>
-       <width>36</width>
-       <height>36</height>
-      </size>
-     </property>
-     <property name="text">
-      <string/>
+   <item row="1" column="8">
+    <widget class="QPushButton" name="noMicButton">
+     <property name="sizePolicy">
+      <sizepolicy hsizetype="Minimum" vsizetype="Minimum">
+       <horstretch>0</horstretch>
+       <verstretch>0</verstretch>
+      </sizepolicy>
      </property>
-    </widget>
-   </item>
-   <item row="1" column="2">
-    <widget class="QPushButton" name="holdButton">
      <property name="minimumSize">
       <size>
        <width>36</width>
@@ -174,8 +174,8 @@
      </property>
     </widget>
    </item>
-   <item row="1" column="0">
-    <spacer name="horizontalSpacer">
+   <item row="1" column="11">
+    <spacer name="horizontalSpacer_2">
      <property name="orientation">
       <enum>Qt::Horizontal</enum>
      </property>
@@ -187,36 +187,8 @@
      </property>
     </spacer>
    </item>
-   <item row="1" column="8">
-    <widget class="QPushButton" name="noMicButton">
-     <property name="sizePolicy">
-      <sizepolicy hsizetype="Minimum" vsizetype="Minimum">
-       <horstretch>0</horstretch>
-       <verstretch>0</verstretch>
-      </sizepolicy>
-     </property>
-     <property name="minimumSize">
-      <size>
-       <width>36</width>
-       <height>36</height>
-      </size>
-     </property>
-     <property name="maximumSize">
-      <size>
-       <width>36</width>
-       <height>36</height>
-      </size>
-     </property>
-     <property name="text">
-      <string/>
-     </property>
-     <property name="checkable">
-      <bool>true</bool>
-     </property>
-    </widget>
-   </item>
-   <item row="0" column="0" alignment="Qt::AlignTop">
-    <widget class="QLabel" name="nameLabel">
+   <item row="0" column="11" alignment="Qt::AlignRight|Qt::AlignTop">
+    <widget class="QLabel" name="timerLabel">
      <property name="palette">
       <palette>
        <active>
@@ -255,12 +227,18 @@
       </palette>
      </property>
      <property name="text">
-      <string/>
+      <string>00:00</string>
      </property>
     </widget>
    </item>
-   <item row="1" column="6">
-    <widget class="QPushButton" name="joinButton">
+   <item row="1" column="9">
+    <widget class="QPushButton" name="noVideoButton">
+     <property name="sizePolicy">
+      <sizepolicy hsizetype="Minimum" vsizetype="Minimum">
+       <horstretch>0</horstretch>
+       <verstretch>0</verstretch>
+      </sizepolicy>
+     </property>
      <property name="minimumSize">
       <size>
        <width>36</width>
@@ -276,10 +254,13 @@
      <property name="text">
       <string/>
      </property>
+     <property name="checkable">
+      <bool>true</bool>
+     </property>
     </widget>
    </item>
-   <item row="1" column="10">
-    <spacer name="horizontalSpacer_2">
+   <item row="1" column="0">
+    <spacer name="horizontalSpacer">
      <property name="orientation">
       <enum>Qt::Horizontal</enum>
      </property>
@@ -291,8 +272,46 @@
      </property>
     </spacer>
    </item>
-   <item row="1" column="1">
-    <widget class="QPushButton" name="hangupButton">
+   <item row="1" column="5">
+    <widget class="QPushButton" name="addPersonButton">
+     <property name="minimumSize">
+      <size>
+       <width>36</width>
+       <height>36</height>
+      </size>
+     </property>
+     <property name="maximumSize">
+      <size>
+       <width>36</width>
+       <height>36</height>
+      </size>
+     </property>
+     <property name="text">
+      <string/>
+     </property>
+    </widget>
+   </item>
+   <item row="1" column="7">
+    <widget class="QPushButton" name="transferButton">
+     <property name="minimumSize">
+      <size>
+       <width>36</width>
+       <height>36</height>
+      </size>
+     </property>
+     <property name="maximumSize">
+      <size>
+       <width>36</width>
+       <height>36</height>
+      </size>
+     </property>
+     <property name="text">
+      <string/>
+     </property>
+    </widget>
+   </item>
+   <item row="1" column="10">
+    <widget class="QPushButton" name="qualityButton">
      <property name="minimumSize">
       <size>
        <width>36</width>
-- 
GitLab