File indexing completed on 2024-05-12 16:02:10

0001 /*
0002  * Made by Tomislav Lukman (tomislav.lukman@ck.tel.hr)
0003  * SPDX-FileCopyrightText: 2012 Jean-Nicolas Artaud <jeannicolasartaud@gmail.com>
0004  * SPDX-FileCopyrightText: 2019 Boudewijn Rempt <boud@valdyas.org>
0005  *
0006  * SPDX-License-Identifier: LGPL-2.0-or-later
0007  */
0008 
0009 #include "KoResourcePopupAction.h"
0010 
0011 #include <KisResourceItemListView.h>
0012 #include <KisResourceModel.h>
0013 #include <KisResourceItemDelegate.h>
0014 #include <KoResource.h>
0015 
0016 #include <KoCheckerBoardPainter.h>
0017 #include <KoShapeBackground.h>
0018 #include <resources/KoAbstractGradient.h>
0019 #include <resources/KoPattern.h>
0020 #include <KoGradientBackground.h>
0021 #include <KoPatternBackground.h>
0022 
0023 #include <QMenu>
0024 #include <QHBoxLayout>
0025 #include <QHeaderView>
0026 #include <QPainter>
0027 #include <QGradient>
0028 #include <QToolButton>
0029 #include <QRect>
0030 #include <QWidgetAction>
0031 
0032 class KoResourcePopupAction::Private
0033 {
0034 public:
0035     QMenu *menu = 0;
0036     KisResourceModel *model = 0;
0037     KisResourceItemListView *resourceList = 0;
0038     QSharedPointer<KoShapeBackground> background;
0039     KoCheckerBoardPainter checkerPainter {4};
0040     KoCanvasResourcesInterfaceSP canvasResourcesInterface;
0041 };
0042 
0043 KoResourcePopupAction::KoResourcePopupAction(const QString &resourceType, KoCanvasResourcesInterfaceSP canvasResourcesInterface, QObject *parent)
0044     : QAction(parent)
0045     , d(new Private())
0046 {
0047     d->canvasResourcesInterface = canvasResourcesInterface;
0048 
0049     d->menu = new QMenu();
0050     QWidget *widget = new QWidget();
0051     QWidgetAction *wdgAction = new QWidgetAction(this);
0052 
0053     d->resourceList = new KisResourceItemListView(widget);
0054     if (resourceType == ResourceType::PaintOpPresets) {
0055         d->resourceList->setFixedToolTipThumbnailSize(QSize(128, 128));
0056     }
0057 
0058     d->model = new KisResourceModel(resourceType, this);
0059     d->resourceList->setModel(d->model);
0060     d->resourceList->setItemDelegate(new KisResourceItemDelegate(widget));
0061     d->resourceList->setCurrentIndex(d->model->index(0, 0));
0062     if (resourceType==ResourceType::Gradients) {
0063         d->resourceList->setViewMode(QListView::ListMode);
0064     }
0065     indexChanged(d->resourceList->currentIndex());
0066     QHBoxLayout *layout = new QHBoxLayout(widget);
0067     layout->addWidget(d->resourceList);
0068 
0069     wdgAction->setDefaultWidget(widget);
0070     d->menu->addAction(wdgAction);
0071     setMenu(d->menu);
0072     new QHBoxLayout(d->menu);
0073     d->menu->layout()->addWidget(widget);
0074     d->menu->layout()->setMargin(0);
0075 
0076     connect(d->resourceList, SIGNAL(clicked(QModelIndex)), this, SLOT(indexChanged(QModelIndex)));
0077 
0078     updateIcon();
0079 }
0080 
0081 KoResourcePopupAction::~KoResourcePopupAction()
0082 {
0083     /* Removing the actions here make them be deleted together with their default widget.
0084      * This happens only if the actions are QWidgetAction, and we know they are since
0085      * the only ones added are in KoResourcePopupAction constructor. */
0086     int i = 0;
0087     while(d->menu->actions().size() > 0) {
0088         d->menu->removeAction(d->menu->actions()[i]);
0089         ++i;
0090     }
0091 
0092     delete d->menu;
0093     delete d;
0094 }
0095 
0096 QSharedPointer<KoShapeBackground> KoResourcePopupAction::currentBackground() const
0097 {
0098     return d->background;
0099 }
0100 
0101 void KoResourcePopupAction::setCurrentBackground(QSharedPointer<KoShapeBackground>  background)
0102 {
0103     d->background = background;
0104 
0105     updateIcon();
0106 }
0107 
0108 void KoResourcePopupAction::setCurrentResource(KoResourceSP resource)
0109 {
0110     QModelIndex index = d->model->indexForResource(resource);
0111     if (index.isValid()) {
0112         d->resourceList->setCurrentIndex(index);
0113         indexChanged(index);
0114     }
0115 }
0116 
0117 KoResourceSP KoResourcePopupAction::currentResource() const
0118 {
0119     QModelIndex index = d->resourceList->currentIndex();
0120     if (!index.isValid()) return 0;
0121 
0122     KoResourceSP resource = d->model->resourceForIndex(index);
0123     return resource;
0124 }
0125 
0126 void KoResourcePopupAction::setCanvasResourcesInterface(KoCanvasResourcesInterfaceSP canvasResourcesInterface)
0127 {
0128     d->canvasResourcesInterface = canvasResourcesInterface;
0129 }
0130 
0131 void KoResourcePopupAction::indexChanged(const QModelIndex &modelIndex)
0132 {
0133     if (! modelIndex.isValid()) {
0134         return;
0135     }
0136 
0137     d->menu->hide();
0138 
0139     KoResourceSP resource = d->model->resourceForIndex(modelIndex);
0140 
0141     if (resource) {
0142         KoAbstractGradientSP gradient = resource.dynamicCast<KoAbstractGradient>();
0143         KoPatternSP pattern = resource.dynamicCast<KoPattern>();
0144         if (gradient) {
0145             QGradient *qg = gradient->cloneAndBakeVariableColors(d->canvasResourcesInterface)->toQGradient();
0146             qg->setCoordinateMode(QGradient::ObjectBoundingMode);
0147             d->background = QSharedPointer<KoShapeBackground>(new KoGradientBackground(qg));
0148         } else if (pattern) {
0149             d->background = QSharedPointer<KoShapeBackground>(new KoPatternBackground());
0150             qSharedPointerDynamicCast<KoPatternBackground>(d->background)->setPattern(pattern->pattern());
0151         }
0152 
0153         emit resourceSelected(d->background);
0154 
0155         updateIcon();
0156     }
0157 }
0158 
0159 void KoResourcePopupAction::updateIcon()
0160 {
0161     QSize iconSize;
0162     QToolButton *toolButton = dynamic_cast<QToolButton*>(parentWidget());
0163     if (toolButton) {
0164         iconSize = QSize(toolButton->iconSize());
0165     } else {
0166         iconSize = QSize(16, 16);
0167     }
0168 
0169     // This must be a QImage, as drawing to a QPixmap outside the
0170     // UI thread will cause sporadic crashes.
0171     QImage pm = QImage(iconSize, QImage::Format_ARGB32_Premultiplied);
0172 
0173     pm.fill(Qt::transparent);
0174 
0175     QPainter p(&pm);
0176     QSharedPointer<KoGradientBackground> gradientBackground = qSharedPointerDynamicCast<KoGradientBackground>(d->background);
0177     QSharedPointer<KoPatternBackground> patternBackground = qSharedPointerDynamicCast<KoPatternBackground>(d->background);
0178 
0179     if (gradientBackground) {
0180         QRect innerRect(0, 0, iconSize.width(), iconSize.height());
0181         QLinearGradient paintGradient;
0182         paintGradient.setStops(gradientBackground->gradient()->stops());
0183         paintGradient.setStart(innerRect.topLeft());
0184         paintGradient.setFinalStop(innerRect.topRight());
0185 
0186         d->checkerPainter.paint(p, innerRect);
0187         p.fillRect(innerRect, QBrush(paintGradient));
0188     }
0189     else if (patternBackground) {
0190         d->checkerPainter.paint(p, QRect(QPoint(),iconSize));
0191         p.fillRect(0, 0, iconSize.width(), iconSize.height(), patternBackground->pattern());
0192     }
0193 
0194     p.end();
0195 
0196     setIcon(QIcon(QPixmap::fromImage(pm)));
0197 }