File indexing completed on 2024-12-22 04:13:13
0001 /* 0002 * SPDX-FileCopyrightText: 2002 Patrick Julien <freak@codepimps.org> 0003 * SPDX-FileCopyrightText: 2009 Sven Langkamp <sven.langkamp@gmail.com> 0004 * SPDX-FileCopyrightText: 2011 Silvio Heinrich <plassy@web.de> 0005 * SPDX-FileCopyrightText: 2011 Srikanth Tiyyagura <srikanth.tulasiram@gmail.com> 0006 * SPDX-FileCopyrightText: 2011 José Luis Vergara <pentalis@gmail.com> 0007 * 0008 * SPDX-License-Identifier: GPL-2.0-or-later 0009 */ 0010 0011 #include "kis_preset_chooser.h" 0012 0013 #include <QVBoxLayout> 0014 #include <QPainter> 0015 #include <QAbstractItemDelegate> 0016 #include <QStyleOptionViewItem> 0017 #include <QSortFilterProxyModel> 0018 #include <KisResourceModel.h> 0019 #include <QApplication> 0020 0021 #include <kis_config.h> 0022 #include <klocalizedstring.h> 0023 #include <KisKineticScroller.h> 0024 0025 #include <KoIcon.h> 0026 #include <KisResourceItemChooser.h> 0027 #include <KisResourceItemChooserSync.h> 0028 #include <KisResourceItemListView.h> 0029 #include <KisResourceLocator.h> 0030 #include <KisResourceTypes.h> 0031 0032 #include <brushengine/kis_paintop_settings.h> 0033 #include <brushengine/kis_paintop_preset.h> 0034 #include "kis_config_notifier.h" 0035 #include <kis_icon.h> 0036 #include <KisResourceModelProvider.h> 0037 #include <KisTagFilterResourceProxyModel.h> 0038 #include <KisResourceThumbnailCache.h> 0039 0040 0041 /// The resource item delegate for rendering the resource preview 0042 class KisPresetDelegate : public QAbstractItemDelegate 0043 { 0044 public: 0045 KisPresetDelegate(QObject * parent = 0) 0046 : QAbstractItemDelegate(parent) 0047 , m_showText(false) 0048 , m_useDirtyPresets(false) {} 0049 0050 ~KisPresetDelegate() override {} 0051 0052 /// reimplemented 0053 void paint(QPainter *, const QStyleOptionViewItem &, const QModelIndex &) const override; 0054 0055 /// reimplemented 0056 QSize sizeHint(const QStyleOptionViewItem & option, const QModelIndex &) const override { 0057 return option.decorationSize; 0058 } 0059 0060 void setShowText(bool showText) { 0061 m_showText = showText; 0062 } 0063 0064 void setUseDirtyPresets(bool value) { 0065 m_useDirtyPresets = value; 0066 } 0067 0068 private: 0069 bool m_showText; 0070 bool m_useDirtyPresets; 0071 }; 0072 0073 void KisPresetDelegate::paint(QPainter * painter, const QStyleOptionViewItem & option, const QModelIndex & index) const 0074 { 0075 painter->save(); 0076 painter->setRenderHint(QPainter::SmoothPixmapTransform, true); 0077 if (!(option.state & QStyle::State_Enabled)) { 0078 painter->setOpacity(0.2); 0079 } 0080 0081 if (!index.isValid()) { 0082 painter->restore(); 0083 return; 0084 } 0085 0086 bool dirty = index.data(Qt::UserRole + KisAbstractResourceModel::Dirty).toBool(); 0087 0088 QImage preview = KisResourceThumbnailCache::instance()->getImage(index); 0089 0090 if (preview.isNull()) { 0091 preview = QImage(512, 512, QImage::Format_RGB32); 0092 preview.fill(Qt::red); 0093 } 0094 0095 qreal devicePixelRatioF = painter->device()->devicePixelRatioF(); 0096 0097 QRect paintRect = option.rect.adjusted(1, 1, -1, -1); 0098 if (!m_showText) { 0099 QImage previewHighDpi = 0100 KisResourceThumbnailCache::instance()->getImage(index, 0101 paintRect.size() * devicePixelRatioF, 0102 Qt::IgnoreAspectRatio, 0103 Qt::SmoothTransformation); 0104 previewHighDpi.setDevicePixelRatio(devicePixelRatioF); 0105 painter->drawImage(paintRect.x(), paintRect.y(), previewHighDpi); 0106 } 0107 else { 0108 QSize pixSize(paintRect.height(), paintRect.height()); 0109 QImage previewHighDpi = KisResourceThumbnailCache::instance()->getImage(index, 0110 pixSize * devicePixelRatioF, 0111 Qt::KeepAspectRatio, 0112 Qt::SmoothTransformation); 0113 previewHighDpi.setDevicePixelRatio(devicePixelRatioF); 0114 painter->drawImage(paintRect.x(), paintRect.y(), previewHighDpi); 0115 0116 // Put an asterisk after the preset if it is dirty. This will help in case the pixmap icon is too small 0117 0118 QString dirtyPresetIndicator = QString(""); 0119 if (m_useDirtyPresets && dirty) { 0120 dirtyPresetIndicator = QString("*"); 0121 } 0122 0123 // qreal brushSize = metaData["paintopSize"].toReal(); 0124 // qDebug() << "brushsize" << brushSize; 0125 // QString brushSizeText; 0126 // // Disable displayed decimal precision beyond a certain brush size 0127 // if (brushSize < 100) { 0128 // brushSizeText = QString::number(brushSize, 'g', 3); 0129 // } 0130 // else { 0131 // brushSizeText = QString::number(brushSize, 'f', 0); 0132 // } 0133 0134 // painter->drawText(pixSize.width() + 10, option.rect.y() + option.rect.height() - 10, brushSizeText); // brush size 0135 0136 QString presetDisplayName = index.data(Qt::UserRole + KisAbstractResourceModel::Name).toString().replace("_", " "); // don't need underscores that might be part of the file name 0137 painter->drawText(pixSize.width() + 10, option.rect.y() + option.rect.height() - 10, presetDisplayName.append(dirtyPresetIndicator)); 0138 0139 } 0140 0141 if (m_useDirtyPresets && dirty) { 0142 const QIcon icon = KisIconUtils::loadIcon("dirty-preset"); 0143 QPixmap pixmap = icon.pixmap(QSize(16,16)); 0144 painter->drawPixmap(paintRect.x() + 3, paintRect.y() + 3, pixmap); 0145 } 0146 0147 bool broken = false; 0148 QMap<QString, QVariant> metaData = index.data(Qt::UserRole + KisAbstractResourceModel::MetaData).value<QMap<QString, QVariant>>(); 0149 QStringList requiredBrushes = metaData["dependent_resources_filenames"].toStringList(); 0150 if (!requiredBrushes.isEmpty()) { 0151 KisAllResourcesModel *model = KisResourceModelProvider::resourceModel(ResourceType::Brushes); 0152 Q_FOREACH(const QString brushFile, requiredBrushes) { 0153 if (!model->resourceExists("", brushFile, "")) { 0154 qWarning() << "dependent resource" << brushFile << "misses."; 0155 broken = true; 0156 } 0157 } 0158 } 0159 0160 if (broken) { 0161 const QIcon icon = KisIconUtils::loadIcon("broken-preset"); 0162 icon.paint(painter, QRect(paintRect.x() + paintRect.height() - 25, paintRect.y() + paintRect.height() - 25, 25, 25)); 0163 } 0164 0165 if (option.state & QStyle::State_Selected) { 0166 painter->setCompositionMode(QPainter::CompositionMode_HardLight); 0167 painter->setOpacity(1.0); 0168 painter->fillRect(option.rect, option.palette.highlight()); 0169 0170 // highlight is not strong enough to pick out preset. draw border around it. 0171 painter->setCompositionMode(QPainter::CompositionMode_SourceOver); 0172 painter->setPen(QPen(option.palette.highlight(), 4, Qt::SolidLine, Qt::FlatCap, Qt::MiterJoin)); 0173 QRect selectedBorder = option.rect.adjusted(2 , 2, -2, -2); // constrict the rectangle so it doesn't bleed into other presets 0174 painter->drawRect(selectedBorder); 0175 } 0176 0177 painter->restore(); 0178 0179 } 0180 0181 KisPresetChooser::KisPresetChooser(QWidget *parent) 0182 : QWidget(parent) 0183 { 0184 setObjectName("KisPresetChooser"); 0185 0186 QVBoxLayout * layout = new QVBoxLayout(this); 0187 layout->setMargin(0); 0188 0189 m_chooser = new KisResourceItemChooser(ResourceType::PaintOpPresets, false, this); 0190 m_chooser->setRowHeight(50); 0191 m_delegate = new KisPresetDelegate(this); 0192 m_chooser->setItemDelegate(m_delegate); 0193 m_chooser->setSynced(true); 0194 m_chooser->showImportExportBtns(false); 0195 layout->addWidget(m_chooser); 0196 0197 connect(m_chooser, SIGNAL(resourceSelected(KoResourceSP )), 0198 this, SLOT(slotResourceWasSelected(KoResourceSP ))); 0199 0200 connect(m_chooser, SIGNAL(resourceSelected(KoResourceSP )), 0201 this, SIGNAL(resourceSelected(KoResourceSP ))); 0202 connect(m_chooser, SIGNAL(resourceClicked(KoResourceSP )), 0203 this, SIGNAL(resourceClicked(KoResourceSP ))); 0204 0205 connect(m_chooser, &KisResourceItemChooser::listViewModeChanged, this, &KisPresetChooser::showHideBrushNames); 0206 0207 m_mode = ViewMode::THUMBNAIL; 0208 0209 connect(KisConfigNotifier::instance(), SIGNAL(configChanged()), 0210 SLOT(notifyConfigChanged())); 0211 0212 0213 notifyConfigChanged(); 0214 } 0215 0216 KisPresetChooser::~KisPresetChooser() 0217 { 0218 } 0219 0220 void KisPresetChooser::setViewMode(KisPresetChooser::ViewMode mode) 0221 { 0222 m_mode = mode; 0223 updateViewSettings(); 0224 } 0225 0226 void KisPresetChooser::setViewModeToThumbnail() 0227 { 0228 setViewMode(KisPresetChooser::ViewMode::THUMBNAIL); 0229 } 0230 0231 void KisPresetChooser::setViewModeToDetail() 0232 { 0233 setViewMode(KisPresetChooser::ViewMode::DETAIL); 0234 } 0235 0236 void KisPresetChooser::notifyConfigChanged() 0237 { 0238 KisConfig cfg(true); 0239 m_delegate->setUseDirtyPresets(cfg.useDirtyPresets()); 0240 setIconSize(cfg.presetIconSize()); 0241 } 0242 0243 void KisPresetChooser::slotResourceWasSelected(KoResourceSP resource) 0244 { 0245 m_currentPresetConnections.clear(); 0246 if (!resource) return; 0247 0248 KisPaintOpPresetSP preset = resource.dynamicCast<KisPaintOpPreset>(); 0249 KIS_SAFE_ASSERT_RECOVER_RETURN(preset); 0250 0251 m_currentPresetConnections.addUniqueConnection( 0252 preset->updateProxy(), SIGNAL(sigSettingsChanged()), 0253 this, SLOT(slotCurrentPresetChanged())); 0254 } 0255 0256 void KisPresetChooser::slotCurrentPresetChanged() 0257 { 0258 KoResourceSP currentResource = m_chooser->currentResource(); 0259 if (!currentResource) return; 0260 0261 QModelIndex index = m_chooser->tagFilterModel()->indexForResource(currentResource); 0262 emit m_chooser->tagFilterModel()->dataChanged(index, 0263 index, 0264 {Qt::UserRole + KisAbstractResourceModel::Thumbnail}); 0265 } 0266 0267 void KisPresetChooser::updateViewSettings() 0268 { 0269 switch (m_mode) { 0270 case ViewMode::THUMBNAIL: { 0271 m_chooser->setListViewMode(ListViewMode::IconGrid); 0272 m_delegate->setShowText(false); 0273 break; 0274 } 0275 case ViewMode::DETAIL: { 0276 m_chooser->setListViewMode(ListViewMode::Detail); 0277 m_delegate->setShowText(true); 0278 break; 0279 } 0280 } 0281 } 0282 0283 void KisPresetChooser::setCurrentResource(KoResourceSP resource) 0284 { 0285 m_chooser->setCurrentResource(resource); 0286 } 0287 0288 KoResourceSP KisPresetChooser::currentResource() const 0289 { 0290 return m_chooser->currentResource(); 0291 } 0292 0293 void KisPresetChooser::showTaggingBar(bool show) 0294 { 0295 m_chooser->showTaggingBar(show); 0296 } 0297 0298 KisResourceItemChooser *KisPresetChooser::itemChooser() 0299 { 0300 return m_chooser; 0301 } 0302 0303 void KisPresetChooser::setPresetFilter(const QString& paintOpId) 0304 { 0305 QMap<QString, QVariant> metaDataFilter; 0306 if (!paintOpId.isEmpty()) { // empty means "all" 0307 metaDataFilter["paintopid"] = paintOpId; 0308 } 0309 m_chooser->tagFilterModel()->setMetaDataFilter(metaDataFilter); 0310 updateViewSettings(); 0311 } 0312 0313 void KisPresetChooser::setIconSize(int newSize) 0314 { 0315 KisResourceItemChooserSync* chooserSync = KisResourceItemChooserSync::instance(); 0316 chooserSync->setBaseLength(newSize); 0317 } 0318 0319 int KisPresetChooser::iconSize() 0320 { 0321 KisResourceItemChooserSync* chooserSync = KisResourceItemChooserSync::instance(); 0322 return chooserSync->baseLength(); 0323 } 0324 0325 void KisPresetChooser::saveIconSize() 0326 { 0327 // save icon size 0328 if (KisConfig(true).presetIconSize() != iconSize()) { 0329 KisConfig(false).setPresetIconSize(iconSize()); 0330 } 0331 } 0332 0333 void KisPresetChooser::showHideBrushNames(ListViewMode newViewMode) 0334 { 0335 switch (newViewMode) { 0336 case ListViewMode::Detail: { 0337 m_delegate->setShowText(true); 0338 break; 0339 } 0340 default: { 0341 m_delegate->setShowText(false); 0342 } 0343 } 0344 }