krita

kis_filter_manager.cc

00001 /*
00002  *  Copyright (c) 2005 Boudewijn Rempt <boud@valdyas.org>
00003  *
00004  *  This program is free software; you can redistribute it and/or modify
00005  *  it under the terms of the GNU General Public License as published by
00006  *  the Free Software Foundation; either version 2 of the License, or
00007  *  (at your option) any later version.
00008  *
00009  *  This program is distributed in the hope that it will be useful,
00010  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
00011  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00012  *  GNU General Public License for more details.
00013  *
00014  *  You should have received a copy of the GNU General Public License
00015  *  along with this program; if not, write to the Free Software
00016  *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
00017  */
00018 
00019 #include "qsignalmapper.h"
00020 #include <qlayout.h>
00021 #include <qframe.h>
00022 #include <qcursor.h>
00023 #include <qapplication.h>
00024 #include <kmessagebox.h>
00025 #include <kguiitem.h>
00026 
00027 #include "kaction.h"
00028 
00029 #include "kis_part_layer.h"
00030 #include "kis_id.h"
00031 #include "kis_view.h"
00032 #include "kis_doc.h"
00033 #include "kis_filter.h"
00034 #include "kis_layer.h"
00035 #include "kis_paint_device.h"
00036 #include "kis_paint_layer.h"
00037 #include "kis_filter_manager.h"
00038 #include "kis_filter_config_widget.h"
00039 #include "kis_previewwidget.h"
00040 #include "kis_previewdialog.h"
00041 #include "kis_filter_registry.h"
00042 #include "kis_transaction.h"
00043 #include "kis_undo_adapter.h"
00044 #include "kis_previewdialog.h"
00045 #include "kis_previewwidget.h"
00046 #include "kis_painter.h"
00047 #include "kis_selection.h"
00048 #include "kis_id.h"
00049 #include "kis_canvas_subject.h"
00050 #include "kis_doc.h"
00051 #include "kis_transaction.h"
00052 #include <kis_progress_display_interface.h>
00053 
00054 KisFilterManager::KisFilterManager(KisView * view, KisDoc * doc)
00055     : m_view(view),
00056     m_doc(doc)
00057 {
00058     // XXX: Store & restore last filter & last filter configuration in session settings
00059     m_reapplyAction = 0;
00060     m_lastFilterConfig = 0;
00061     m_lastDialog = 0;
00062     m_lastFilter = 0;
00063     m_lastWidget = 0;
00064 
00065     m_filterMapper = new QSignalMapper(this);
00066 
00067     connect(m_filterMapper, SIGNAL(mapped(int)), this, SLOT(slotApplyFilter(int)));
00068 
00069 }
00070 
00071 KisFilterManager::~KisFilterManager()
00072 {
00073     //delete m_reapplyAction;
00074     //delete m_lastFilterConfig;
00075     //delete m_filterMapper;
00076 }
00077 
00078 void KisFilterManager::setup(KActionCollection * ac)
00079 {
00080     KisFilter * f = 0;
00081     int i = 0;
00082 
00083     // Only create the submenu's we've actually got filters for.
00084     // XXX: Make this list extensible after 1.5
00085 
00086     KActionMenu * other = 0;
00087     KActionMenu * am = 0;
00088     
00089     m_filterList = KisFilterRegistry::instance()->listKeys();
00090     
00091     for ( KisIDList::Iterator it = m_filterList.begin(); it != m_filterList.end(); ++it ) {
00092         f = KisFilterRegistry::instance()->get(*it);
00093         if (!f) break;
00094         
00095         QString s = f->menuCategory();
00096         if (s == "adjust" && !m_filterActionMenus.find("adjust")) {
00097             am = new KActionMenu(i18n("Adjust"), ac, "adjust_filters");
00098             m_filterActionMenus.insert("adjust", am);
00099         }
00100 
00101         else if (s == "artistic" && !m_filterActionMenus.find("artistic")) {
00102             am = new KActionMenu(i18n("Artistic"), ac, "artistic_filters");
00103             m_filterActionMenus.insert("artistic", am);
00104         }
00105 
00106         else if (s == "blur" && !m_filterActionMenus.find("blur")) {
00107             am = new KActionMenu(i18n("Blur"), ac, "blur_filters");
00108             m_filterActionMenus.insert("blur", am);
00109         }
00110 
00111         else if (s == "colors" && !m_filterActionMenus.find("colors")) {
00112             am = new KActionMenu(i18n("Colors"), ac, "color_filters");
00113             m_filterActionMenus.insert("colors", am);
00114         }
00115 
00116         else if (s == "decor" && !m_filterActionMenus.find("decor")) {
00117             am = new KActionMenu(i18n("Decor"), ac, "decor_filters");
00118             m_filterActionMenus.insert("decor", am);
00119         }
00120 
00121         else if (s == "edge" && !m_filterActionMenus.find("edge")) {
00122             am = new KActionMenu(i18n("Edge Detection"), ac, "edge_filters");
00123             m_filterActionMenus.insert("edge", am);
00124         }
00125 
00126         else if (s == "emboss" && !m_filterActionMenus.find("emboss")) {
00127             am = new KActionMenu(i18n("Emboss"), ac, "emboss_filters");
00128             m_filterActionMenus.insert("emboss", am);
00129         }
00130 
00131         else if (s == "enhance" && !m_filterActionMenus.find("enhance")) {
00132             am = new KActionMenu(i18n("Enhance"), ac, "enhance_filters");
00133             m_filterActionMenus.insert("enhance", am);
00134         }
00135 
00136         else if (s == "map" && !m_filterActionMenus.find("map")) {
00137             am = new KActionMenu(i18n("Map"), ac, "map_filters");
00138             m_filterActionMenus.insert("map", am);
00139         }
00140 
00141         else if (s == "nonphotorealistic" && !m_filterActionMenus.find("nonphotorealistic")) {
00142             am = new KActionMenu(i18n("Non-photorealistic"), ac, "nonphotorealistic_filters");
00143             m_filterActionMenus.insert("nonphotorealistic", am);
00144         }
00145 
00146         else if (s == "other" && !m_filterActionMenus.find("other")) {
00147             other = new KActionMenu(i18n("Other"), ac, "misc_filters");
00148             m_filterActionMenus.insert("other", am);
00149         }
00150         
00151     }
00152 
00153     m_reapplyAction = new KAction(i18n("Apply Filter Again"),
00154                 "Ctrl+Shift+F",
00155                 this, SLOT(slotApply()),
00156                 ac, "filter_apply_again");
00157     
00158     m_reapplyAction->setEnabled(false);
00159 
00160     f = 0;
00161     i = 0;
00162     for ( KisIDList::Iterator it = m_filterList.begin(); it != m_filterList.end(); ++it ) {
00163         f = KisFilterRegistry::instance()->get(*it);
00164 
00165         if (!f) break;
00166 
00167         // Create action
00168         KAction * a = new KAction(f->menuEntry(), 0, m_filterMapper, SLOT(map()), ac,
00169                                   QString("krita_filter_%1").arg((*it) . id()).ascii());
00170 
00171         // Add action to the right submenu
00172         KActionMenu * m = m_filterActionMenus.find( f->menuCategory() );
00173         if (m) {
00174             m->insert(a);
00175         }
00176         else {
00177             if (!other) {
00178                 other = new KActionMenu(i18n("Other"), ac, "misc_filters");
00179                 m_filterActionMenus.insert("other", am);
00180             }
00181             other->insert(a);
00182         }
00183 
00184         // Add filter to list of filters for mapper
00185         m_filterMapper->setMapping( a, i );
00186 
00187         m_filterActions.append( a );
00188         ++i;
00189     }
00190 }
00191 
00192 void KisFilterManager::updateGUI()
00193 {
00194     KisImageSP img = m_view->currentImg();
00195     if (!img) return;
00196 
00197     KisLayerSP layer = img->activeLayer();
00198     if (!layer) return;
00199 
00200     KisPartLayer * partLayer = dynamic_cast<KisPartLayer*>(layer.data());
00201     
00202     bool enable =  !(layer->locked() || !layer->visible() || partLayer);
00203     KisPaintLayerSP player = dynamic_cast<KisPaintLayer*>( layer.data());
00204     if(!player)
00205     {
00206         enable = false;
00207     }
00208     m_reapplyAction->setEnabled(m_lastFilterConfig);
00209     if (m_lastFilterConfig)
00210         m_reapplyAction->setText(i18n("Apply Filter Again") + ": " 
00211             + KisFilterRegistry::instance()->get(m_lastFilterConfig->name())->id().name());
00212     else
00213         m_reapplyAction->setText(i18n("Apply Filter Again"));
00214     
00215     KAction * a;
00216     int i = 0;
00217     for (a = m_filterActions.first(); a; a = m_filterActions.next() , i++) {
00218         KisFilter* filter = KisFilterRegistry::instance()->get(m_filterList[i]);
00219         if(player && filter->workWith( player->paintDevice()->colorSpace()))
00220         {
00221             a->setEnabled(enable);
00222         } else {
00223             a->setEnabled(false);
00224         }
00225     }
00226 
00227 }
00228 
00229 void KisFilterManager::slotApply()
00230 {
00231     apply();
00232 }
00233 
00234 bool KisFilterManager::apply()
00235 {
00236     if (!m_lastFilter) return false;
00237 
00238     KisImageSP img = m_view->currentImg();
00239     if (!img) return false;
00240 
00241     KisPaintDeviceSP dev = img->activeDevice();
00242     if (!dev) return false;
00243 
00244     QApplication::setOverrideCursor( Qt::waitCursor );
00245 
00246     //Apply the filter
00247     m_lastFilterConfig = m_lastFilter->configuration(m_lastWidget);
00248 
00249     QRect r1 = dev->extent();
00250     QRect r2 = img->bounds();
00251 
00252     // Filters should work only on the visible part of an image.
00253     QRect rect = r1.intersect(r2);
00254 
00255     if (dev->hasSelection()) {
00256         QRect r3 = dev->selection()->selectedExactRect();
00257         rect = rect.intersect(r3);
00258     }
00259 
00260     m_lastFilter->enableProgress();
00261 
00262     m_view->progressDisplay()->setSubject(m_lastFilter, true, true);
00263     m_lastFilter->setProgressDisplay( m_view->progressDisplay());
00264 
00265     KisTransaction * cmd = 0;
00266     if (img->undo()) cmd = new KisTransaction(m_lastFilter->id().name(), dev);
00267     
00268     m_lastFilter->process(dev, dev, m_lastFilterConfig, rect);
00269     m_reapplyAction->setEnabled(m_lastFilterConfig);
00270     if (m_lastFilterConfig)
00271         m_reapplyAction->setText(i18n("Apply Filter Again") + ": "
00272             + KisFilterRegistry::instance()->get(m_lastFilterConfig->name())->id().name());
00273 
00274     else
00275         m_reapplyAction->setText(i18n("Apply Filter Again"));
00276     
00277     if (m_lastFilter->cancelRequested()) {
00278         delete m_lastFilterConfig;
00279         if (cmd) {
00280             cmd->unexecute();
00281             delete cmd;
00282         }
00283         m_lastFilter->disableProgress();
00284         QApplication::restoreOverrideCursor();
00285         return false;
00286 
00287     } else {
00288         if (dev->parentLayer()) dev->parentLayer()->setDirty(rect);
00289         m_doc->setModified(true);
00290         if (img->undo() && cmd) img->undoAdapter()->addCommand(cmd);
00291         m_lastFilter->disableProgress();
00292         QApplication::restoreOverrideCursor();
00293         return true;
00294     }
00295 }
00296 
00297 void KisFilterManager::slotApplyFilter(int i)
00298 {
00299     KisPreviewDialog * oldDialog = m_lastDialog;
00300     KisFilterConfiguration * oldConfig = m_lastFilterConfig;
00301     KisFilter * oldFilter = m_lastFilter;
00302 
00303     m_lastFilter = KisFilterRegistry::instance()->get(m_filterList[i]);
00304 
00305     if (!m_lastFilter) {
00306         m_lastFilter = oldFilter;
00307         return;
00308     }
00309 
00310     KisImageSP img = m_view->currentImg();
00311     if (!img) return;
00312 
00313     KisPaintDeviceSP dev = img->activeDevice();
00314     if (!dev) return;
00315 
00316     if (dev->colorSpace()->willDegrade(m_lastFilter->colorSpaceIndependence())) {
00317         // Warning bells!
00318         if (m_lastFilter->colorSpaceIndependence() == TO_LAB16) {
00319             if (KMessageBox::warningContinueCancel(m_view,
00320                                                i18n("The %1 filter will convert your %2 data to 16-bit L*a*b* and vice versa. ")
00321                                                        .arg(m_lastFilter->id().name())
00322                                                        .arg(dev->colorSpace()->id().name()),
00323                                                i18n("Filter Will Convert Your Layer Data"),
00324                                                KGuiItem(i18n("Continue")),
00325                                                "lab16degradation") != KMessageBox::Continue) return;
00326 
00327         }
00328         else if (m_lastFilter->colorSpaceIndependence() == TO_RGBA8) {
00329             if (KMessageBox::warningContinueCancel(m_view,
00330                                                i18n("The %1 filter will convert your %2 data to 8-bit RGBA and vice versa. ")
00331                                                        .arg(m_lastFilter->id().name())
00332                                                        .arg(dev->colorSpace()->id().name()),
00333                                                i18n("Filter Will Convert Your Layer Data"),
00334                                                KGuiItem(i18n("Continue")),
00335                                                "rgba8degradation") != KMessageBox::Continue) return;
00336         }
00337     }
00338 
00339     m_lastFilter->disableProgress();
00340 
00341     // Create the config dialog
00342     m_lastDialog = new KisPreviewDialog(m_view, m_lastFilter->id().name().ascii(), true, m_lastFilter->id().name());
00343     Q_CHECK_PTR(m_lastDialog);
00344     m_lastWidget = m_lastFilter->createConfigurationWidget( (QWidget*)m_lastDialog->container(), dev );
00345 
00346 
00347     if( m_lastWidget != 0)
00348     {
00349         connect(m_lastWidget, SIGNAL(sigPleaseUpdatePreview()), this, SLOT(slotConfigChanged()));
00350 
00351         m_lastDialog->previewWidget()->slotSetDevice( dev );
00352 
00353         connect(m_lastDialog->previewWidget(), SIGNAL(updated()), this, SLOT(refreshPreview()));
00354 
00355         QGridLayout *widgetLayout = new QGridLayout((QWidget *)m_lastDialog->container(), 1, 1);
00356 
00357         widgetLayout->addWidget(m_lastWidget, 0 , 0);
00358 
00359         m_lastDialog->container()->setMinimumSize(m_lastWidget->minimumSize());
00360 
00361         refreshPreview();
00362 
00363         if(m_lastDialog->exec() == QDialog::Rejected )
00364         {
00365             delete m_lastDialog;
00366             m_lastDialog = oldDialog;
00367             m_lastFilter = oldFilter;
00368             return;
00369         }
00370     }
00371 
00372     if (!apply()) {
00373         m_lastFilterConfig = oldConfig;
00374         m_lastDialog = oldDialog;
00375         m_lastFilter = oldFilter;
00376     }
00377 
00378 }
00379 
00380 void KisFilterManager::slotConfigChanged()
00381 {
00382     if( m_lastDialog == 0 )
00383         return;
00384     if(m_lastDialog->previewWidget()->getAutoUpdate())
00385     {
00386         refreshPreview();
00387     } else {
00388         m_lastDialog->previewWidget()->needUpdate();
00389     }
00390 }
00391 
00392 
00393 void KisFilterManager::refreshPreview( )
00394 {
00395     if( m_lastDialog == 0 )
00396         return;
00397 
00398     KisPaintDeviceSP dev = m_lastDialog->previewWidget()->getDevice();
00399     if (!dev) return;
00400 
00401     KisFilterConfiguration* config = m_lastFilter->configuration(m_lastWidget);
00402 
00403     QRect rect = dev->extent();
00404     KisTransaction cmd("Temporary transaction", dev);
00405     m_lastFilter->process(dev, dev, config, rect);
00406     m_lastDialog->previewWidget()->slotUpdate();
00407     cmd.unexecute();
00408 }
00409 
00410 
00411 #include "kis_filter_manager.moc"
KDE Home | KDE Accessibility Home | Description of Access Keys