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 }