krita

kis_filter_manager.cc

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