File indexing completed on 2024-05-12 04:06:22

0001 /*
0002     SPDX-FileCopyrightText: 2010 Stefan Majewsky <majewsky@gmx.net>
0003 
0004     SPDX-License-Identifier: LGPL-2.0-or-later
0005 */
0006 
0007 #ifndef PALAPELI_TRIGGERLISTVIEW_P_H
0008 #define PALAPELI_TRIGGERLISTVIEW_P_H
0009 
0010 #include "triggerlistview.h"
0011 #include "elidinglabel.h"
0012 #include "mouseinputbutton.h"
0013 #include <QApplication>
0014 #include <QCollator>
0015 #include <QHBoxLayout>
0016 #include <QLabel>
0017 #include <KCategorizedSortFilterProxyModel>
0018 #include <KWidgetItemDelegate>
0019 
0020 namespace Palapeli
0021 {
0022     class TriggerListProxyModel : public KCategorizedSortFilterProxyModel
0023     {
0024         public:
0025             explicit TriggerListProxyModel(QObject* parent = nullptr)
0026                 : KCategorizedSortFilterProxyModel(parent)
0027             {
0028                 setCategorizedModel(true);
0029                 m_collator.setCaseSensitivity(Qt::CaseSensitive);
0030             }
0031         protected:
0032             int compareCategories(const QModelIndex& left, const QModelIndex& right) const override
0033             {
0034                 const int categoryLeft = left.data(KCategorizedSortFilterProxyModel::CategorySortRole).value<int>();
0035                 const int categoryRight = right.data(KCategorizedSortFilterProxyModel::CategorySortRole).value<int>();
0036                 return categoryRight - categoryLeft;
0037             }
0038             bool subSortLessThan(const QModelIndex& left, const QModelIndex& right) const override
0039             {
0040                 const QString textLeft = left.data(Qt::DisplayRole).toString();
0041                 const QString textRight = right.data(Qt::DisplayRole).toString();
0042                 return m_collator.compare(textLeft, textRight) < 0;
0043             }
0044         private:
0045             QCollator m_collator;
0046     };
0047 
0048     class TriggerListDelegateWidget : public QWidget
0049     {
0050         Q_OBJECT
0051         public:
0052             explicit TriggerListDelegateWidget(QWidget* parent = nullptr) : QWidget(parent)
0053             {
0054                 m_iconLabel = new QLabel(this);
0055                 m_nameLabel = new Palapeli::ElidingLabel(this);
0056                 m_inputButton = new Palapeli::MouseInputButton(this);
0057                 connect(m_inputButton, &MouseInputButton::triggerChanged, this, &TriggerListDelegateWidget::triggerChanged);
0058                 //construct layout
0059                 QHBoxLayout* layout = new QHBoxLayout;
0060                 setLayout(layout);
0061                 layout->addWidget(m_iconLabel);
0062                 m_iconLabel->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed);
0063                 m_iconLabel->setFixedSize(QSize(32, 32));
0064                 layout->addWidget(m_nameLabel);
0065                 layout->addWidget(m_inputButton);
0066                 m_inputButton->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed);
0067             }
0068             void setIcon(const QIcon& icon)
0069             {
0070                 //TODO: respect global icon size configuration
0071                 m_iconLabel->setPixmap(icon.pixmap(32));
0072             }
0073             void setText(const QString& text)
0074             {
0075                 m_nameLabel->setFullText(text);
0076             }
0077             void setTrigger(const Palapeli::Trigger& trigger)
0078             {
0079                 m_inputButton->setTrigger(trigger);
0080             }
0081             void setInteractorType(Palapeli::InteractorType type)
0082             {
0083                 m_inputButton->setMouseAllowed(type == Palapeli::MouseInteractor);
0084                 m_inputButton->setWheelAllowed(type == Palapeli::WheelInteractor);
0085             }
0086         Q_SIGNALS:
0087             void triggerChanged(const Palapeli::Trigger& newTrigger);
0088         private:
0089             QLabel* m_iconLabel;
0090             Palapeli::ElidingLabel* m_nameLabel;
0091             Palapeli::MouseInputButton* m_inputButton;
0092     };
0093 
0094     class TriggerListDelegate : public KWidgetItemDelegate
0095     {
0096         Q_OBJECT
0097         public:
0098             explicit TriggerListDelegate(QAbstractItemView* view, QObject* parent = nullptr) : KWidgetItemDelegate(view, parent)
0099             {
0100                 m_calculator = new Palapeli::TriggerListDelegateWidget(view);
0101                 m_calculator->setVisible(false);
0102             }
0103             void paint(QPainter* painter, const QStyleOptionViewItem& option, const QModelIndex& index) const override
0104             {
0105                 Q_UNUSED(index)
0106                 QApplication::style()->drawPrimitive(QStyle::PE_PanelItemViewItem, &option, painter, nullptr);
0107             }
0108             QSize sizeHint(const QStyleOptionViewItem& option, const QModelIndex& index) const override
0109             {
0110                 updateItemWidgets(QList<QWidget*>() << m_calculator, option, index);
0111                 return m_calculator->minimumSizeHint();
0112             }
0113         protected:
0114             QList<QWidget*> createItemWidgets(const QModelIndex &index) const override
0115             {
0116                 Q_UNUSED(index);
0117                 return QList<QWidget*>() << new Palapeli::TriggerListDelegateWidget(itemView());
0118             }
0119             void updateItemWidgets(const QList<QWidget*> &widgets, const QStyleOptionViewItem& option, const QPersistentModelIndex& index) const override
0120             {
0121                 Palapeli::TriggerListDelegateWidget* widget = qobject_cast<Palapeli::TriggerListDelegateWidget*>(widgets[0]);
0122                 //adjust widget contents
0123                 widget->setIcon(index.data(Qt::DecorationRole).value<QIcon>());
0124                 widget->setText(index.data(Qt::DisplayRole).value<QString>());
0125                 disconnect(widget, nullptr, this, nullptr);
0126                 widget->setTrigger(index.data(TriggerRole).value<Palapeli::Trigger>());
0127                 connect(widget, &TriggerListDelegateWidget::triggerChanged, this, &TriggerListDelegate::slotTriggerChanged);
0128                 //adjust widget geometry
0129                 QRect rect = option.rect;
0130                 rect.moveTop(0);
0131                 widget->setGeometry(rect);
0132                 //adjust widget behavior
0133                 widget->setInteractorType((Palapeli::InteractorType) index.data(Palapeli::InteractorTypeRole).toInt());
0134             }
0135         Q_SIGNALS:
0136             void triggerChanged();
0137         private Q_SLOTS:
0138             void slotTriggerChanged(const Palapeli::Trigger& newTrigger)
0139             {
0140                 const QModelIndex index = focusedIndex();
0141                 QAbstractItemModel* model = const_cast<QAbstractItemModel*>(index.model());
0142                 model->setData(index, QVariant::fromValue(newTrigger), Palapeli::TriggerRole);
0143                 Q_EMIT triggerChanged();
0144             }
0145         private:
0146             Palapeli::TriggerListDelegateWidget* m_calculator;
0147     };
0148 }
0149 
0150 #endif // PALAPELI_TRIGGERLISTVIEW_P_H