Make ActivityItemDelegate background- and selection-aware (Dark-/Light-Mode switching)
authorMichael Schuster <michael@schuster.ms>
Thu, 19 Dec 2019 19:07:14 +0000 (20:07 +0100)
committerMichael Schuster <48932272+misch7@users.noreply.github.com>
Thu, 19 Dec 2019 21:07:30 +0000 (22:07 +0100)
Also implement cached member icons in ActivityListModel and return their enums to
ActivityItemDelegate instead of always recreating them for each call to paint().

Signed-off-by: Michael Schuster <michael@schuster.ms>
src/gui/activityitemdelegate.cpp
src/gui/activityitemdelegate.h
src/gui/activitylistmodel.cpp
src/gui/activitylistmodel.h

index 1d49af7d7e5e634c797712f9c779039e7078c970..18306bbe34822db89fb99e89534fbba43f9e1e5a 100644 (file)
@@ -15,6 +15,7 @@
  */
 
 #include "activityitemdelegate.h"
+#include "activitylistmodel.h"
 #include "folderstatusmodel.h"
 #include "folderman.h"
 #include "accountstate.h"
@@ -40,6 +41,12 @@ int ActivityItemDelegate::_buttonHeight = 0;
 const QString ActivityItemDelegate::_remote_share("remote_share");
 const QString ActivityItemDelegate::_call("call");
 
+ActivityItemDelegate::ActivityItemDelegate()
+    : QStyledItemDelegate()
+{
+    customizeStyle();
+}
+
 int ActivityItemDelegate::iconHeight()
 {
     if (_iconHeight == 0) {
@@ -89,10 +96,21 @@ void ActivityItemDelegate::paint(QPainter *painter, const QStyleOptionViewItem &
     int iconSize = 16;
     int iconOffset = qRound(fm.height() / 4.0 * 7.0);
     int offset = 4;
+    const bool isSelected = (option.state & QStyle::State_Selected);
 
     // get the data
     Activity::Type activityType = qvariant_cast<Activity::Type>(index.data(ActionRole));
-    QIcon actionIcon = qvariant_cast<QIcon>(index.data(ActionIconRole));
+    QIcon actionIcon;
+    const ActivityListModel::ActionIcon icn = qvariant_cast<ActivityListModel::ActionIcon>(index.data(ActionIconRole));
+    switch(icn.iconType) {
+        case ActivityListModel::ActivityIconType::iconUseCached:        actionIcon = icn.cachedIcon;                                        break;
+        case ActivityListModel::ActivityIconType::iconActivity:         actionIcon = (isSelected ? _iconActivity_sel : _iconActivity);      break;
+        case ActivityListModel::ActivityIconType::iconBell:             actionIcon = (isSelected ? _iconBell_sel : _iconBell);              break;
+        case ActivityListModel::ActivityIconType::iconStateError:       actionIcon = _iconStateError;                                       break;
+        case ActivityListModel::ActivityIconType::iconStateWarning:     actionIcon = _iconStateWarning;                                     break;
+        case ActivityListModel::ActivityIconType::iconStateInfo:        actionIcon = _iconStateInfo;                                        break;
+        case ActivityListModel::ActivityIconType::iconStateSync:        actionIcon = _iconStateSync;                                        break;
+    }
     QString objectType = qvariant_cast<QString>(index.data(ObjectTypeRole));
     QString actionText = qvariant_cast<QString>(index.data(ActionTextRole));
     QString messageText = qvariant_cast<QString>(index.data(MessageRole));
@@ -184,9 +202,9 @@ void ActivityItemDelegate::paint(QPainter *painter, const QStyleOptionViewItem &
     if(activityType == Activity::Type::NotificationType){
 
         // Secondary will be 'Dismiss' or '...' multiple options button
-        secondaryButton.icon = QIcon(QLatin1String(":/client/resources/close.svg"));
+        secondaryButton.icon = (isSelected ? _iconClose_sel : _iconClose);
         if(customList.size() > 1)
-            secondaryButton.icon = QIcon(QLatin1String(":/client/resources/more.svg"));
+            secondaryButton.icon = (isSelected ? _iconMore_sel : _iconMore);
         secondaryButton.iconSize = QSize(iconSize, iconSize);
 
         // Primary button will be 'More Information' or 'Accept'
@@ -209,7 +227,7 @@ void ActivityItemDelegate::paint(QPainter *painter, const QStyleOptionViewItem &
     } else if(activityType == Activity::SyncResultType){
 
         // Secondary will be 'open file manager' with the folder icon
-        secondaryButton.icon = QIcon(QLatin1String(":/client/resources/folder.svg"));
+        secondaryButton.icon = _iconFolder;
         secondaryButton.iconSize = QSize(iconSize, iconSize);
 
         // Primary button will be 'open browser'
@@ -230,7 +248,7 @@ void ActivityItemDelegate::paint(QPainter *painter, const QStyleOptionViewItem &
     } else if(activityType == Activity::SyncFileItemType){
 
         // Secondary will be 'open file manager' with the folder icon
-        secondaryButton.icon = QIcon(QLatin1String(":/client/resources/folder.svg"));
+        secondaryButton.icon = _iconFolder;
         secondaryButton.iconSize = QSize(iconSize, iconSize);
 
         // No primary button on this case
@@ -255,7 +273,7 @@ void ActivityItemDelegate::paint(QPainter *painter, const QStyleOptionViewItem &
         p.setCurrentColorGroup(QPalette::Disabled);
 
     // change pen color if the line is selected
-    if (option.state & QStyle::State_Selected)
+    if (isSelected)
         painter->setPen(p.color(QPalette::HighlightedText));
     else
         painter->setPen(p.color(QPalette::Text));
@@ -269,8 +287,15 @@ void ActivityItemDelegate::paint(QPainter *painter, const QStyleOptionViewItem &
     painter->drawText(actionTextBox, elidedAction);
 
     // draw the buttons
-    if(activityType == Activity::Type::NotificationType || activityType == Activity::Type::SyncResultType)
+    if(activityType == Activity::Type::NotificationType || activityType == Activity::Type::SyncResultType) {
+        primaryButton.palette = p;
+        if (isSelected)
+            primaryButton.palette.setColor(QPalette::ButtonText, p.color(QPalette::HighlightedText));
+        else
+            primaryButton.palette.setColor(QPalette::ButtonText, p.color(QPalette::Text));
+
         QApplication::style()->drawControl(QStyle::CE_PushButton, &primaryButton, painter);
+    }
 
     // Since they are errors on local syncing, there is nothing to do in the server
     if(activityType != Activity::Type::ActivityType)
@@ -284,7 +309,7 @@ void ActivityItemDelegate::paint(QPainter *painter, const QStyleOptionViewItem &
     }
 
     // change pen color for the time
-    if (option.state & QStyle::State_Selected)
+    if (isSelected)
         painter->setPen(p.color(QPalette::Disabled, QPalette::HighlightedText));
     else
         painter->setPen(p.color(QPalette::Disabled, QPalette::Text));
@@ -333,4 +358,32 @@ bool ActivityItemDelegate::editorEvent(QEvent *event, QAbstractItemModel *model,
     return QStyledItemDelegate::editorEvent(event, model, option, index);
 }
 
+void ActivityItemDelegate::slotStyleChanged()
+{
+    customizeStyle();
+}
+
+void ActivityItemDelegate::customizeStyle()
+{
+    QPalette pal;
+    pal.setColor(QPalette::Base, QColor(0,0,0));    // use dark background colour to invert icons
+
+    _iconClose        = Theme::createColorAwareIcon(QLatin1String(":/client/resources/close.svg"));
+    _iconClose_sel    = Theme::createColorAwareIcon(QLatin1String(":/client/resources/close.svg"), pal);
+    _iconMore         = Theme::createColorAwareIcon(QLatin1String(":/client/resources/more.svg"));
+    _iconMore_sel     = Theme::createColorAwareIcon(QLatin1String(":/client/resources/more.svg"), pal);
+
+    _iconFolder       = QIcon(QLatin1String(":/client/resources/folder.svg"));
+
+    _iconActivity     = Theme::createColorAwareIcon(QLatin1String(":/client/resources/activity.png"));
+    _iconActivity_sel = Theme::createColorAwareIcon(QLatin1String(":/client/resources/activity.png"), pal);
+    _iconBell         = Theme::createColorAwareIcon(QLatin1String(":/client/resources/bell.svg"));
+    _iconBell_sel     = Theme::createColorAwareIcon(QLatin1String(":/client/resources/bell.svg"), pal);
+
+    _iconStateError   = QIcon(QLatin1String(":/client/resources/state-error.svg"));
+    _iconStateWarning = QIcon(QLatin1String(":/client/resources/state-warning.svg"));
+    _iconStateInfo    = QIcon(QLatin1String(":/client/resources/state-info.svg"));
+    _iconStateSync    = QIcon(QLatin1String(":/client/resources/state-sync.svg"));
+}
+
 } // namespace OCC
index 49ffca5929e61ce83cd199735cadea4e58e1dd07..908889eee0be9132cc9d9ef7972ae060a5a0fba1 100644 (file)
@@ -43,6 +43,8 @@ public:
         AccountConnectedRole,
         SyncFileStatusRole };
 
+    ActivityItemDelegate();
+
     void paint(QPainter *, const QStyleOptionViewItem &, const QModelIndex &) const override;
     QSize sizeHint(const QStyleOptionViewItem &, const QModelIndex &) const override;
     bool editorEvent(QEvent *event, QAbstractItemModel *model, const QStyleOptionViewItem &option,
@@ -51,11 +53,16 @@ public:
     static int rowHeight();
     static int iconHeight();
 
+public slots:
+    void slotStyleChanged();
+
 signals:
     void primaryButtonClickedOnItemView(const QModelIndex &index);
     void secondaryButtonClickedOnItemView(const QModelIndex &index);
 
 private:
+    void customizeStyle();
+
     static int _margin;
     static int _iconHeight;
     static int _primaryButtonWidth;
@@ -65,6 +72,23 @@ private:
     static int _buttonHeight;
     static const QString _remote_share;
     static const QString _call;
+
+    QIcon _iconClose;
+    QIcon _iconClose_sel;
+    QIcon _iconMore;
+    QIcon _iconMore_sel;
+
+    QIcon _iconFolder;
+
+    QIcon _iconActivity;
+    QIcon _iconActivity_sel;
+    QIcon _iconBell;
+    QIcon _iconBell_sel;
+
+    QIcon _iconStateError;
+    QIcon _iconStateWarning;
+    QIcon _iconStateInfo;
+    QIcon _iconStateSync;
 };
 
 } // namespace OCC
index f64290abc098bf2ae15ed888019aff38701643c2..cd544729bfac341cef362be810d43d017b63e16b 100644 (file)
@@ -79,31 +79,41 @@ QVariant ActivityListModel::data(const QModelIndex &index, int role) const
         }
         return customList;
     }
-    case ActivityItemDelegate::ActionIconRole:
+    case ActivityItemDelegate::ActionIconRole:{
+        ActionIcon actionIcon;
         if(a._type == Activity::NotificationType){
            QIcon cachedIcon = ServerNotificationHandler::iconCache.value(a._id);
-           if(!cachedIcon.isNull())
-               return cachedIcon;
-           else return QIcon(QLatin1String(":/client/resources/bell.svg"));
+            if(!cachedIcon.isNull()) {
+               actionIcon.iconType = ActivityIconType::iconUseCached;
+               actionIcon.cachedIcon = cachedIcon;
+            } else {
+                actionIcon.iconType = ActivityIconType::iconBell;
+            }
         } else if(a._type == Activity::SyncResultType){
-            return QIcon(QLatin1String(":/client/resources/state-error.svg"));
+            actionIcon.iconType = ActivityIconType::iconStateError;
         } else if(a._type == Activity::SyncFileItemType){
                if(a._status == SyncFileItem::NormalError
                    || a._status == SyncFileItem::FatalError
                    || a._status == SyncFileItem::DetailError
                    || a._status == SyncFileItem::BlacklistedError) {
-                   return QIcon(QLatin1String(":/client/resources/state-error.svg"));
+                   actionIcon.iconType = ActivityIconType::iconStateError;
                } else if(a._status == SyncFileItem::SoftError
                          || a._status == SyncFileItem::Conflict
                          || a._status == SyncFileItem::Restoration
                          || a._status == SyncFileItem::FileLocked){
-                   return QIcon(QLatin1String(":/client/resources/state-warning.svg"));
+                   actionIcon.iconType = ActivityIconType::iconStateWarning;
                } else if(a._status == SyncFileItem::FileIgnored){
-                   return QIcon(QLatin1String(":/client/resources/state-info.svg"));
+                   actionIcon.iconType = ActivityIconType::iconStateInfo;
+               } else {
+                   actionIcon.iconType = ActivityIconType::iconStateSync;
+               }
+        } else {
+            actionIcon.iconType = ActivityIconType::iconActivity;
                }
-               return QIcon(QLatin1String(":/client/resources/state-sync.svg"));
+        QVariant icn;
+        icn.setValue(actionIcon);
+        return icn;
         }
-        return QIcon(QLatin1String(":/client/resources/activity.png"));
         break;
     case ActivityItemDelegate::ObjectTypeRole:
         return a._objectType;
index cbb823f1f44e98f5039908e633c48e270ab528b2..7198fbb98800ad712a868f991f57b57061e568f4 100644 (file)
@@ -38,6 +38,20 @@ class ActivityListModel : public QAbstractListModel
 {
     Q_OBJECT
 public:
+    enum ActivityIconType {
+        iconUseCached = 0,
+        iconActivity,
+        iconBell,
+        iconStateError,
+        iconStateWarning,
+        iconStateInfo,
+        iconStateSync
+    };
+    struct ActionIcon {
+        ActivityIconType iconType;
+        QIcon cachedIcon;
+    };
+
     explicit ActivityListModel(AccountState *accountState, QWidget *parent = nullptr);
 
     QVariant data(const QModelIndex &index, int role) const override;
@@ -84,4 +98,7 @@ private:
     int _currentItem = 0;
 };
 }
+
+Q_DECLARE_METATYPE(OCC::ActivityListModel::ActionIcon);
+
 #endif // ACTIVITYLISTMODEL_H