Fading version, replaces former patch.
From 6eaaa2c88459cde9c36c4598a8d6cd83a4070919 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Thomas=20L=C3=BCbking?= <thomas.luebk...@gmail.com>
Date: Sat, 14 Sep 2013 01:03:00 +0200
Subject: [PATCH] cc scrolling

---
 src/Gui/ComposeWidget.cpp | 127 +++++++++++++++++++++++++++++++++++++++++++++-
 src/Gui/ComposeWidget.h   |   5 ++
 src/Gui/ComposeWidget.ui  |  89 ++++++++++++++++++--------------
 3 files changed, 181 insertions(+), 40 deletions(-)

diff --git a/src/Gui/ComposeWidget.cpp b/src/Gui/ComposeWidget.cpp
index 7eef98f..c7cbb54 100644
--- a/src/Gui/ComposeWidget.cpp
+++ b/src/Gui/ComposeWidget.cpp
@@ -23,10 +23,12 @@
 #include <QAbstractProxyModel>
 #include <QBuffer>
 #include <QFileDialog>
+#include <QGraphicsOpacityEffect>
 #include <QKeyEvent>
 #include <QMenu>
 #include <QMessageBox>
 #include <QProgressDialog>
+#include <QPropertyAnimation>
 #include <QPushButton>
 #include <QSettings>
 #include <QTimer>
@@ -56,15 +58,18 @@
 
 namespace
 {
-enum { OFFSET_OF_FIRST_ADDRESSEE = 1 };
+enum { OFFSET_OF_FIRST_ADDRESSEE = 1, MAX_VISIBLE_RECIPIENTS = 4 };
 }
 
 namespace Gui
 {
 
+static const QString trojita_opacityAnimation("trojita_opacityAnimation");
+
 ComposeWidget::ComposeWidget(MainWindow *mainWindow, QSettings *settings, MSA::MSAFactory *msaFactory) :
     QWidget(0, Qt::Window),
     ui(new Ui::ComposeWidget),
+    m_lastFocusedRecipient(NULL),
     m_sentMail(false),
     m_messageUpdated(false),
     m_messageEverEdited(false),
@@ -101,6 +106,13 @@ ComposeWidget::ComposeWidget(MainWindow *mainWindow, QSettings *settings, MSA::M
     m_recipientListUpdateTimer->setInterval(250);
     connect(m_recipientListUpdateTimer, SIGNAL(timeout()), SLOT(updateRecipientList()));
 
+    connect(ui->recipientSlider, SIGNAL(valueChanged(int)), SLOT(scrollRecipients(int)));
+    connect (qApp, SIGNAL(focusChanged(QWidget*, QWidget*)), SLOT(invalidateLastFocusedRecipient()));
+    ui->recipientSlider->setMinimum(0);
+    ui->recipientSlider->setMaximum(0);
+    ui->recipientSlider->setVisible(false);
+    ui->envelopeWidget->installEventFilter(this);
+
     ui->mailText->setFont(Gui::Util::systemMonospaceFont());
 
     connect(ui->mailText, SIGNAL(urlsAdded(QList<QUrl>)), SLOT(slotAttachFiles(QList<QUrl>)));
@@ -439,9 +451,20 @@ void ComposeWidget::addRecipient(int position, Composer::RecipientKind kind, con
     connect(edit, SIGNAL(editingFinished()), SLOT(collapseRecipients()));
     connect(edit, SIGNAL(textChanged(QString)), m_recipientListUpdateTimer, SLOT(start()));
     m_recipients.insert(position, Recipient(combo, edit));
+    ui->envelopeWidget->setUpdatesEnabled(false);
     ui->envelopeLayout->insertRow(actualRow(ui->envelopeLayout, position + OFFSET_OF_FIRST_ADDRESSEE), combo, edit);
     setTabOrder(formPredecessor(ui->envelopeLayout, combo), combo);
     setTabOrder(combo, edit);
+    const int max = qMax(0, m_recipients.count() - MAX_VISIBLE_RECIPIENTS);
+    ui->recipientSlider->setMaximum(max);
+    ui->recipientSlider->setVisible(max > 0);
+    if (ui->recipientSlider->isVisible()) {
+        const int v = ui->recipientSlider->value();
+        ui->recipientSlider->setValue((position+1)*max/m_recipients.count());
+        if (v == ui->recipientSlider->value()) // force scroll update
+            scrollRecipients(v);
+    }
+    ui->envelopeWidget->setUpdatesEnabled(true);
 }
 
 void ComposeWidget::slotCheckAddress()
@@ -473,6 +496,9 @@ void ComposeWidget::removeRecipient(int pos)
     m_recipients.at(pos).first->deleteLater();
     m_recipients.at(pos).second->deleteLater();
     m_recipients.removeAt(pos);
+    const int max = qMax(0, m_recipients.count() - MAX_VISIBLE_RECIPIENTS);
+    ui->recipientSlider->setMaximum(max);
+    ui->recipientSlider->setVisible(max > 0);
 }
 
 static inline Composer::RecipientKind currentRecipient(const QComboBox *box)
@@ -501,6 +527,91 @@ void ComposeWidget::updateRecipientList()
     }
 }
 
+void ComposeWidget::invalidateLastFocusedRecipient()
+{
+    m_lastFocusedRecipient = QApplication::focusWidget(); // got explicit focus on other widget
+}
+
+void ComposeWidget::fadeIn(QWidget *w)
+{
+    QGraphicsOpacityEffect *effect = new QGraphicsOpacityEffect(w);
+    w->setGraphicsEffect(effect);
+    QPropertyAnimation *animation = new QPropertyAnimation(effect, "opacity", w);
+    connect (animation, SIGNAL(finished()), SLOT(slotFadeFinished()));
+    animation->setObjectName(trojita_opacityAnimation);
+    animation->setDuration(333);
+    animation->setStartValue(0.0);
+    animation->setEndValue(1.0);
+    animation->start(QAbstractAnimation::DeleteWhenStopped);
+}
+
+void ComposeWidget::slotFadeFinished()
+{
+    Q_ASSERT(sender());
+    QWidget *animatedEffectWidget = qobject_cast<QWidget*>(sender()->parent());
+    Q_ASSERT(animatedEffectWidget);
+    animatedEffectWidget->setGraphicsEffect(0); // deletes old one
+}
+
+void ComposeWidget::scrollRecipients(int value)
+{
+    // ignore focus changes caused by "scrolling"
+    disconnect (qApp, SIGNAL(focusChanged(QWidget*, QWidget*)), this, SLOT(invalidateLastFocusedRecipient()));
+
+    QList<QWidget*> visibleWidgets;
+    for (int i = 0; i < m_recipients.count(); ++i) {
+        // remove all widgets from the form because of vspacing - causes spurious padding
+
+        QWidget *toCC = m_recipients.at(i).first;
+        QWidget *lineEdit = m_recipients.at(i).second;
+        if (!m_lastFocusedRecipient) { // apply only _once_
+            if (toCC->hasFocus())
+                m_lastFocusedRecipient = toCC;
+            else if (lineEdit->hasFocus())
+                m_lastFocusedRecipient = lineEdit;
+        }
+        if (toCC->isVisible())
+            visibleWidgets << toCC;
+        if (lineEdit->isVisible())
+            visibleWidgets << lineEdit;
+        ui->envelopeLayout->removeWidget(toCC);
+        ui->envelopeLayout->removeWidget(lineEdit);
+        toCC->hide();
+        lineEdit->hide();
+    }
+
+    const int begin = qMin(m_recipients.count(), value);
+    const int end   = qMin(m_recipients.count(), value + MAX_VISIBLE_RECIPIENTS);
+    for (int i = begin, j = 0; i < end; ++i, ++j) {
+        const int pos = actualRow(ui->envelopeLayout, j + OFFSET_OF_FIRST_ADDRESSEE);
+        QWidget *toCC = m_recipients.at(i).first;
+        QWidget *lineEdit = m_recipients.at(i).second;
+        ui->envelopeLayout->insertRow(pos, toCC, lineEdit);
+        if (!visibleWidgets.contains(toCC))
+            fadeIn(toCC);
+        visibleWidgets.removeOne(toCC);
+        if (!visibleWidgets.contains(lineEdit))
+            fadeIn(lineEdit);
+        visibleWidgets.removeOne(lineEdit);
+        toCC->show();
+        lineEdit->show();
+        setTabOrder(formPredecessor(ui->envelopeLayout, toCC), toCC);
+        setTabOrder(toCC, lineEdit);
+        if (toCC == m_lastFocusedRecipient)
+            toCC->setFocus();
+        else if (lineEdit == m_lastFocusedRecipient)
+            lineEdit->setFocus();
+    }
+
+    Q_FOREACH (QWidget *w, visibleWidgets) {
+        // was visible, is no longer -> stop animation so it won't conflict later ones
+        w->setGraphicsEffect(0); // deletes old one
+        if (QPropertyAnimation *pa = w->findChild<QPropertyAnimation*>(trojita_opacityAnimation))
+            pa->stop();
+    }
+    connect (qApp, SIGNAL(focusChanged(QWidget*, QWidget*)), SLOT(invalidateLastFocusedRecipient()));
+}
+
 void ComposeWidget::collapseRecipients()
 {
     QLineEdit *edit = qobject_cast<QLineEdit*>(sender());
@@ -614,6 +725,20 @@ bool ComposeWidget::eventFilter(QObject *o, QEvent *e)
         }
         return false;
     }
+
+    if (o == ui->envelopeWidget)  {
+        if (e->type() == QEvent::Wheel) {
+            int v = ui->recipientSlider->value();
+            if (static_cast<QWheelEvent*>(e)->delta() > 0)
+                --v;
+            else
+                ++v;
+            ui->recipientSlider->setValue(v);
+            e->accept();
+            return true;
+        }
+        return false;
+    }
     return false;
 }
 
diff --git a/src/Gui/ComposeWidget.h b/src/Gui/ComposeWidget.h
index 5185e5c..e5c40ed 100644
--- a/src/Gui/ComposeWidget.h
+++ b/src/Gui/ComposeWidget.h
@@ -89,6 +89,9 @@ private slots:
     void gotError(const QString &error);
     void sent();
     void updateRecipientList();
+    void scrollRecipients(int);
+    void invalidateLastFocusedRecipient();
+    void slotFadeFinished();
 
     void slotCheckAddress();
     void slotCheckAddress(QLineEdit *edit);
@@ -111,6 +114,7 @@ private:
     void addRecipient(int position, Composer::RecipientKind kind, const QString &address);
     bool parseRecipients(QList<QPair<Composer::RecipientKind, Imap::Message::MailAddress> > &results, QString &errorMessage);
     void removeRecipient(int position);
+    void fadeIn(QWidget *w);
 
     bool buildMessageData();
     bool shouldBuildMessageLocally() const;
@@ -123,6 +127,7 @@ private:
     typedef QPair<QComboBox*, QLineEdit*> Recipient;
     QList<Recipient> m_recipients;
     QTimer *m_recipientListUpdateTimer;
+    QWidget *m_lastFocusedRecipient;
 
     bool m_sentMail;
     /** @short Has it been updated since the last time we auto-saved it? */
diff --git a/src/Gui/ComposeWidget.ui b/src/Gui/ComposeWidget.ui
index 11bfca6..1ff1b26 100644
--- a/src/Gui/ComposeWidget.ui
+++ b/src/Gui/ComposeWidget.ui
@@ -6,8 +6,8 @@
    <rect>
     <x>0</x>
     <y>0</y>
-    <width>715</width>
-    <height>377</height>
+    <width>716</width>
+    <height>362</height>
    </rect>
   </property>
   <property name="windowTitle">
@@ -15,16 +15,16 @@
   </property>
   <layout class="QVBoxLayout" name="verticalLayout_2">
    <item>
-    <widget class="QSplitter" name="splitter">
+    <widget class="QSplitter" name="splitter_2">
      <property name="orientation">
       <enum>Qt::Vertical</enum>
      </property>
      <property name="childrenCollapsible">
       <bool>false</bool>
      </property>
-     <widget class="QSplitter" name="splitter_2">
+     <widget class="QSplitter" name="splitter">
       <property name="sizePolicy">
-       <sizepolicy hsizetype="Expanding" vsizetype="Preferred">
+       <sizepolicy hsizetype="Expanding" vsizetype="Expanding">
         <horstretch>0</horstretch>
         <verstretch>1</verstretch>
        </sizepolicy>
@@ -42,43 +42,54 @@
          <verstretch>0</verstretch>
         </sizepolicy>
        </property>
-       <layout class="QFormLayout" name="envelopeLayout">
-        <property name="fieldGrowthPolicy">
-         <enum>QFormLayout::ExpandingFieldsGrow</enum>
-        </property>
-        <item row="0" column="0">
-         <widget class="QLabel" name="fromLabel">
-          <property name="text">
-           <string>From</string>
-          </property>
-          <property name="buddy">
-           <cstring>sender</cstring>
-          </property>
-         </widget>
-        </item>
-        <item row="0" column="1">
-         <widget class="QComboBox" name="sender">
-          <property name="sizePolicy">
-           <sizepolicy hsizetype="MinimumExpanding" vsizetype="Fixed">
-            <horstretch>0</horstretch>
-            <verstretch>0</verstretch>
-           </sizepolicy>
-          </property>
-         </widget>
+       <layout class="QHBoxLayout" name="horizontalLayout">
+        <item>
+         <layout class="QFormLayout" name="envelopeLayout">
+          <property name="fieldGrowthPolicy">
+           <enum>QFormLayout::ExpandingFieldsGrow</enum>
+          </property>
+          <item row="0" column="0">
+           <widget class="QLabel" name="fromLabel">
+            <property name="text">
+             <string>From</string>
+            </property>
+            <property name="buddy">
+             <cstring>sender</cstring>
+            </property>
+           </widget>
+          </item>
+          <item row="0" column="1">
+           <widget class="QComboBox" name="sender">
+            <property name="sizePolicy">
+             <sizepolicy hsizetype="MinimumExpanding" vsizetype="Fixed">
+              <horstretch>0</horstretch>
+              <verstretch>0</verstretch>
+             </sizepolicy>
+            </property>
+           </widget>
+          </item>
+          <item row="1" column="0">
+           <widget class="QLabel" name="subjectLabel">
+            <property name="text">
+             <string>Subject</string>
+            </property>
+            <property name="buddy">
+             <cstring>subject</cstring>
+            </property>
+           </widget>
+          </item>
+          <item row="1" column="1">
+           <widget class="LineEdit" name="subject"/>
+          </item>
+         </layout>
         </item>
-        <item row="1" column="0">
-         <widget class="QLabel" name="subjectLabel">
-          <property name="text">
-           <string>Subject</string>
-          </property>
-          <property name="buddy">
-           <cstring>subject</cstring>
+        <item>
+         <widget class="QScrollBar" name="recipientSlider">
+          <property name="orientation">
+           <enum>Qt::Vertical</enum>
           </property>
          </widget>
         </item>
-        <item row="1" column="1">
-         <widget class="LineEdit" name="subject"/>
-        </item>
        </layout>
       </widget>
       <widget class="QGroupBox" name="groupBox">
@@ -161,7 +172,7 @@
       <property name="sizePolicy">
        <sizepolicy hsizetype="Expanding" vsizetype="Expanding">
         <horstretch>0</horstretch>
-        <verstretch>3</verstretch>
+        <verstretch>100</verstretch>
        </sizepolicy>
       </property>
       <property name="minimumSize">
-- 
1.8.4

Reply via email to