File indexing completed on 2025-04-27 03:58:26

0001 /* ============================================================
0002  *
0003  * This file is a part of digiKam project
0004  * https://www.digikam.org
0005  *
0006  * Date        : 2006-01-20
0007  * Description : action categorized view
0008  *
0009  * SPDX-FileCopyrightText: 2006-2024 by Gilles Caulier <caulier dot gilles at gmail dot com>
0010  *
0011  * SPDX-License-Identifier: GPL-2.0-or-later
0012  *
0013  * ============================================================ */
0014 
0015 #include "actioncategorizedview.h"
0016 
0017 // Qt includes
0018 
0019 #include <QString>
0020 #include <QPropertyAnimation>
0021 #include <QScrollBar>
0022 #include <QApplication>
0023 #include <QStyle>
0024 
0025 // Local includes
0026 
0027 #include "digikam_debug.h"
0028 #include "dcategorydrawer.h"
0029 
0030 namespace Digikam
0031 {
0032 
0033 ActionCategorizedView::ActionCategorizedView(QWidget* const parent, bool autoScroll)
0034     : DCategorizedView(parent),
0035       m_autoScroll    (autoScroll)
0036 {
0037     m_horizontalScrollAnimation = new QPropertyAnimation(horizontalScrollBar(), "value", this);
0038     m_verticalScrollAnimation   = new QPropertyAnimation(verticalScrollBar(),   "value", this);
0039 }
0040 
0041 ActionCategorizedView::~ActionCategorizedView()
0042 {
0043 }
0044 
0045 void ActionCategorizedView::setupIconMode()
0046 {
0047     setViewMode(QListView::IconMode);
0048     setMovement(QListView::Static);
0049     setCategoryDrawer(new DCategoryDrawer(this)); // deprecated, but needed for KDE 4.4 compatibility
0050     setSelectionMode(QAbstractItemView::SingleSelection);
0051 
0052     setMouseTracking(true);
0053     viewport()->setAttribute(Qt::WA_Hover);
0054 
0055     setFrameShape(QFrame::NoFrame);
0056 }
0057 
0058 void ActionCategorizedView::adjustGridSize()
0059 {
0060     // Find a suitable grid size. The delegate's size hint does never word-wrap.
0061     // To keep a suitable width, we want to word wrap.
0062 
0063     setWordWrap(true);
0064     QStyleOptionViewItem option;
0065 
0066 #if (QT_VERSION >= QT_VERSION_CHECK(6, 0, 0))
0067 
0068     initViewItemOption(&option);
0069 
0070 #else
0071 
0072     option = viewOptions();
0073 
0074 #endif
0075 
0076     int maxWidth = option.decorationSize.width() * 4;
0077     QFontMetrics fm(option.font);
0078     QSize grid;
0079 
0080     for (int i = 0 ; i < model()->rowCount() ; ++i)
0081     {
0082         const QModelIndex index = model()->index(i, 0);
0083         const QSize size        = sizeHintForIndex(index);
0084 
0085         if (size.width() > maxWidth)
0086         {
0087             QString text      = index.data(Qt::DisplayRole).toString();
0088             QRect wrappedRect = fm.boundingRect(QRect(0, 0, maxWidth, maxWidth),
0089                                                 Qt::AlignLeft | Qt::TextWordWrap, text);
0090             grid              = grid.expandedTo(QSize(maxWidth, wrappedRect.height()));
0091         }
0092         else
0093         {
0094             grid = grid.expandedTo(size);
0095         }
0096     }
0097 /*
0098     grid += QSize(qMin(QApplication::style()->pixelMetric(QStyle::PM_LayoutHorizontalSpacing),
0099                              QApplication::style()->pixelMetric(QStyle::PM_LayoutVerticalSpacing)), qMin(QApplication::style()->pixelMetric(QStyle::PM_LayoutHorizontalSpacing),
0100                              QApplication::style()->pixelMetric(QStyle::PM_LayoutVerticalSpacing)));
0101 */
0102     setGridSize(grid);
0103 }
0104 
0105 int ActionCategorizedView::autoScrollDuration(float relativeDifference, QPropertyAnimation* animation)
0106 {
0107     const int minimumTime       = 1000;
0108     const int maxPixelPerSecond = 1000;
0109 
0110     int pixelToScroll           = qAbs(animation->startValue().toInt() - animation->endValue().toInt());
0111     int factor                  = qMax(1.0f, relativeDifference * 100); // in [1;15]
0112 
0113     int duration                = 1000 * pixelToScroll / maxPixelPerSecond;
0114     duration                   *= factor;
0115 
0116     return qMax(minimumTime, duration);
0117 }
0118 
0119 void ActionCategorizedView::autoScroll(float relativePos, QScrollBar* scrollBar, QPropertyAnimation* animation)
0120 {
0121     if (scrollBar->minimum() != scrollBar->maximum())
0122     {
0123         const float lowerPart = 0.15F;
0124         const float upperPart = 0.85F;
0125 
0126         if      ((relativePos > upperPart) && (scrollBar->value() != scrollBar->maximum()))
0127         {
0128             animation->stop();
0129             animation->setStartValue(scrollBar->value());
0130             animation->setEndValue(scrollBar->maximum());
0131             animation->setDuration(autoScrollDuration(1 - relativePos, animation));
0132             animation->start();
0133         }
0134         else if ((relativePos < lowerPart) && (scrollBar->value() != scrollBar->minimum()))
0135         {
0136             animation->stop();
0137             animation->setStartValue(scrollBar->value());
0138             animation->setEndValue(scrollBar->minimum());
0139             animation->setDuration(autoScrollDuration(relativePos, animation));
0140             animation->start();
0141         }
0142         else
0143         {
0144             animation->stop();
0145         }
0146     }
0147 }
0148 
0149 void ActionCategorizedView::mouseMoveEvent(QMouseEvent* e)
0150 {
0151     DCategorizedView::mouseMoveEvent(e);
0152 
0153     if (m_autoScroll)
0154     {
0155         autoScroll(float(e->pos().x()) / viewport()->width(),  horizontalScrollBar(), m_horizontalScrollAnimation);
0156         autoScroll(float(e->pos().y()) / viewport()->height(), verticalScrollBar(),   m_verticalScrollAnimation);
0157     }
0158 }
0159 
0160 void ActionCategorizedView::leaveEvent(QEvent* e)
0161 {
0162     DCategorizedView::leaveEvent(e);
0163     m_horizontalScrollAnimation->stop();
0164     m_verticalScrollAnimation->stop();
0165 }
0166 
0167 } // namespace Digikam
0168 
0169 #include "moc_actioncategorizedview.cpp"