File indexing completed on 2024-05-19 04:28:56

0001 /*
0002  *  SPDX-FileCopyrightText: 2006 Bart Coppens <kde@bartcoppens.be>
0003  *
0004  *  SPDX-License-Identifier: GPL-2.0-or-later
0005  */
0006 
0007 #include "kis_custom_pattern.h"
0008 
0009 #include <KoResourceServerProvider.h>
0010 #include <resources/KoPattern.h>
0011 
0012 #include <QLabel>
0013 #include <QImage>
0014 #include <QPushButton>
0015 #include <QComboBox>
0016 #include <QPixmap>
0017 #include <QShowEvent>
0018 #include <QSharedPointer>
0019 #include <QFileInfo>
0020 #include <KoFileDialog.h>
0021 #include <QMessageBox>
0022 
0023 #include "KisDocument.h"
0024 #include "KisViewManager.h"
0025 #include "kis_image.h"
0026 #include "kis_layer.h"
0027 #include "kis_paint_device.h"
0028 #include "kis_selection.h"
0029 #include "kis_painter.h"
0030 
0031 #include <kis_debug.h>
0032 #include "KisResourceServerProvider.h"
0033 #include <KisResourceLoaderRegistry.h>
0034 #include "kis_paint_layer.h"
0035 #include <KisResourceUserOperations.h>
0036 
0037 
0038 KisCustomPattern::KisCustomPattern(QWidget *parent, const char* name, const QString& caption, KisViewManager* view)
0039     : KisWdgCustomPattern(parent, name)
0040     , m_view(view)
0041 {
0042     Q_ASSERT(m_view);
0043     setWindowTitle(caption);
0044 
0045     m_pattern = 0;
0046 
0047     preview->setScaledContents(true);
0048 
0049     m_rServer = KoResourceServerProvider::instance()->patternServer();
0050 
0051     connect(addButton, SIGNAL(pressed()), this, SLOT(slotAddPredefined()));
0052     connect(patternButton, SIGNAL(pressed()), this, SLOT(slotUsePattern()));
0053     connect(updateButton, SIGNAL(pressed()), this, SLOT(slotUpdateCurrentPattern()));
0054     connect(cmbSource, SIGNAL(currentIndexChanged(int)), this, SLOT(slotUpdateCurrentPattern()));
0055 
0056     lblWarning->setVisible(false);
0057     slotUpdateCurrentPattern();
0058 }
0059 
0060 KisCustomPattern::~KisCustomPattern()
0061 {
0062     m_pattern.clear();
0063 }
0064 
0065 void KisCustomPattern::slotUpdateCurrentPattern()
0066 {
0067     m_pattern.clear();
0068     if (m_view && m_view->image()) {
0069         createPattern();
0070         if (m_pattern) {
0071             const qint32 maxSize = 150;
0072             if ((m_pattern->width() > maxSize) || (m_pattern->height() > maxSize)) {
0073                 float aspectRatio = (float)m_pattern->width() / m_pattern->height();
0074                 qint32 scaledWidth, scaledHeight;
0075 
0076                 if (m_pattern->width() > m_pattern->height()) {
0077                     scaledWidth = maxSize;
0078                     scaledHeight = maxSize / aspectRatio;
0079                 } else {
0080                     scaledWidth = maxSize * aspectRatio;
0081                     scaledHeight = maxSize;
0082                 }
0083 
0084                 if (scaledWidth == 0) scaledWidth++;
0085                 if (scaledHeight == 0) scaledHeight++;
0086 
0087                 QPixmap scaledPixmap = QPixmap::fromImage(m_pattern->pattern());
0088                 preview->setPixmap(scaledPixmap.scaled(scaledWidth, scaledHeight, Qt::KeepAspectRatio, Qt::SmoothTransformation));
0089             } else {
0090                 preview->setPixmap(QPixmap::fromImage(m_pattern->pattern()));
0091             }
0092         }
0093     }
0094 
0095 }
0096 
0097 void KisCustomPattern::slotAddPredefined()
0098 {
0099     if (!m_pattern) return;
0100 
0101     // Save in the directory that is likely to be: ~/.kde/share/apps/krita/patterns
0102     // a unique file with this pattern name
0103     QString dir = KoResourceServerProvider::instance()->patternServer()->saveLocation();
0104 
0105     KoFileDialog dlg(this, KoFileDialog::SaveFile, "KisCustomPattern::slotAddPredefined");
0106     dlg.setDefaultDir(dir + "/" + m_pattern->name() + ".pat");
0107     dlg.setMimeTypeFilters(KisResourceLoaderRegistry::instance()->mimeTypes(ResourceType::Patterns));
0108     dlg.setCaption(i18n("Add to Predefined Patterns"));
0109 
0110     QString filename = dlg.filename();
0111 
0112     if (filename == "") {
0113         // dialog was cancelled
0114         return;
0115     }
0116     bool hadToChangeFilename = false;
0117 
0118     QFileInfo fi(filename);
0119     if (fi.suffix().isEmpty()) {
0120         fi.setFile(fi.baseName() + m_pattern->defaultFileExtension());
0121         hadToChangeFilename = true;
0122     }
0123 
0124     if (fi.baseName() != m_pattern->name()) {
0125         m_pattern->setName(fi.baseName());
0126     }
0127 
0128     bool overwrite = false;
0129     if (fi.exists()) {
0130         if (hadToChangeFilename) { // if not, the File Dialog would show the warning
0131             if (QMessageBox::warning(this,  i18nc("@title:window", "Krita"), i18n("This pattern already exists. Do you want to overwrite it?"), QMessageBox::Yes | QMessageBox::No) == QMessageBox::Yes) {
0132                 overwrite = true;
0133             }
0134         } else { // the File Dialog showed the warning and the user said "yeah fine"
0135             overwrite = true;
0136         }
0137     }
0138 
0139     if (!filename.isEmpty()) {
0140         m_pattern->setFilename(fi.fileName()); // to make sure we include the suffix added earlier
0141         if (!fi.exists()) {
0142             if (!KisResourceUserOperations::addResourceWithUserInput(this, m_pattern->clone().dynamicCast<KoPattern>())) {
0143                 qWarning() << "Could not add pattern with filename" << filename;
0144             }
0145             else {
0146                 emit patternAdded(m_pattern);
0147             }
0148         }
0149         else if (overwrite) {
0150             if (!KisResourceUserOperations::updateResourceWithUserInput(this, m_pattern->clone().dynamicCast<KoPattern>())) {
0151                 qWarning() << "Could not add pattern with filename" << filename;
0152             }
0153             else {
0154                 emit patternUpdated(m_pattern);
0155             }
0156         }
0157     }
0158 }
0159 
0160 void KisCustomPattern::slotUsePattern()
0161 {
0162     if (!m_pattern)
0163         return;
0164     KoPatternSP copy = m_pattern->clone().dynamicCast<KoPattern>();
0165     emit(activatedResource(copy));
0166 }
0167 
0168 void KisCustomPattern::createPattern()
0169 {
0170     if (!m_view) return;
0171 
0172     KisPaintDeviceSP dev;
0173     KisPaintDeviceSP cache;
0174     QString name;
0175     KisImageWSP image = m_view->image();
0176     if (!image) return;
0177     QRect rc = image->bounds();
0178 
0179     if (cmbSource->currentIndex() == 0) {
0180         dev = m_view->activeNode()->projection();
0181         name = m_view->activeNode()->name();
0182         QRect rc2 = dev->exactBounds();
0183         rc = rc.intersected(rc2);
0184     }
0185     else {
0186         image->barrierLock();
0187         dev = image->projection();
0188         image->unlock();
0189         name = image->objectName();
0190     }
0191     if (!dev) return;
0192 
0193     if(m_view->selection()) {
0194         KisSelectionSP selection = m_view->selection();
0195         QRect selectionRect = selection->selectedExactRect();
0196         cache = dev->createCompositionSourceDevice();
0197         KisPainter gc(cache);
0198         gc.setSelection(selection);
0199         gc.bitBlt(selectionRect.topLeft(), dev, selectionRect);
0200         rc = selectionRect;
0201     } else {
0202         cache = dev;
0203     }
0204     if (!cache) return;
0205 
0206 
0207     // warn when creating large patterns
0208 
0209     QSize size = rc.size();
0210     if (size.height() > 1000 || size.width() > 1000) {
0211         lblWarning->setVisible(true);
0212         size.scale(1000, 1000, Qt::KeepAspectRatio);
0213     }
0214     else {
0215         lblWarning->setVisible(false);
0216     }
0217 
0218     QString dir = KoResourceServerProvider::instance()->patternServer()->saveLocation();
0219     m_pattern = KoPatternSP(new KoPattern(cache->createThumbnail(size.width(), size.height(), rc, /*oversample*/ 1,
0220                                                                  KoColorConversionTransformation::internalRenderingIntent(),
0221                                                                  KoColorConversionTransformation::internalConversionFlags()), name, dir));
0222 }
0223 
0224