|
|
|
/*
|
|
|
|
* Copyright (c) 2005 Boudewijn Rempt <boud@valdyas.org>
|
|
|
|
* Copyright (c) 2007 Benjamin Schleimer <bensch128@yahoo.com>
|
|
|
|
*
|
|
|
|
* This program is free software; you can redistribute it and/or modify
|
|
|
|
* it under the terms of the GNU General Public License as published by
|
|
|
|
* the Free Software Foundation; either version 2 of the License, or
|
|
|
|
* (at your option) any later version.
|
|
|
|
*
|
|
|
|
* This program is distributed in the hope that it will be useful,
|
|
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
* GNU General Public License for more details.
|
|
|
|
*
|
|
|
|
* You should have received a copy of the GNU General Public License
|
|
|
|
* along with this program; if not, write to the Free Software
|
|
|
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include "tqsignalmapper.h"
|
|
|
|
#include <tqlayout.h>
|
|
|
|
#include <tqframe.h>
|
|
|
|
#include <tqcursor.h>
|
|
|
|
#include <tqapplication.h>
|
|
|
|
#include <kmessagebox.h>
|
|
|
|
#include <kguiitem.h>
|
|
|
|
|
|
|
|
#include <kis_cursor.h>
|
|
|
|
#include "kaction.h"
|
|
|
|
|
|
|
|
#include "kis_part_layer.h"
|
|
|
|
#include "kis_id.h"
|
|
|
|
#include "kis_view.h"
|
|
|
|
#include "kis_doc.h"
|
|
|
|
#include "kis_filter.h"
|
|
|
|
#include "kis_layer.h"
|
|
|
|
#include "kis_paint_device.h"
|
|
|
|
#include "kis_paint_layer.h"
|
|
|
|
#include "kis_filter_manager.h"
|
|
|
|
#include "kis_filter_config_widget.h"
|
|
|
|
#include "kis_previewwidget.h"
|
|
|
|
#include "kis_previewdialog.h"
|
|
|
|
#include "kis_filter_registry.h"
|
|
|
|
#include "kis_transaction.h"
|
|
|
|
#include "kis_undo_adapter.h"
|
|
|
|
#include "kis_previewdialog.h"
|
|
|
|
#include "kis_previewwidget.h"
|
|
|
|
#include "kis_painter.h"
|
|
|
|
#include "kis_selection.h"
|
|
|
|
#include "kis_id.h"
|
|
|
|
#include "kis_canvas_subject.h"
|
|
|
|
#include "kis_doc.h"
|
|
|
|
#include "kis_transaction.h"
|
|
|
|
#include <kis_progress_display_interface.h>
|
|
|
|
|
|
|
|
KisFilterManager::KisFilterManager(KisView * view, KisDoc * doc)
|
|
|
|
: m_view(view),
|
|
|
|
m_doc(doc)
|
|
|
|
{
|
|
|
|
// XXX: Store & restore last filter & last filter configuration in session settings
|
|
|
|
m_reapplyAction = 0;
|
|
|
|
m_lastFilterConfig = 0;
|
|
|
|
m_lastDialog = 0;
|
|
|
|
m_lastFilter = 0;
|
|
|
|
m_lastWidget = 0;
|
|
|
|
|
|
|
|
m_filterMapper = new TQSignalMapper(this);
|
|
|
|
|
|
|
|
connect(m_filterMapper, TQT_SIGNAL(mapped(int)), this, TQT_SLOT(slotApplyFilter(int)));
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
KisFilterManager::~KisFilterManager()
|
|
|
|
{
|
|
|
|
//delete m_reapplyAction;
|
|
|
|
//delete m_lastFilterConfig;
|
|
|
|
//delete m_filterMapper;
|
|
|
|
}
|
|
|
|
|
|
|
|
void KisFilterManager::setup(KActionCollection * ac)
|
|
|
|
{
|
|
|
|
KisFilter * f = 0;
|
|
|
|
int i = 0;
|
|
|
|
|
|
|
|
// Only create the submenu's we've actually got filters for.
|
|
|
|
// XXX: Make this list extensible after 1.5
|
|
|
|
|
|
|
|
KActionMenu * other = 0;
|
|
|
|
KActionMenu * am = 0;
|
|
|
|
|
|
|
|
m_filterList = KisFilterRegistry::instance()->listKeys();
|
|
|
|
|
|
|
|
for ( KisIDList::Iterator it = m_filterList.begin(); it != m_filterList.end(); ++it ) {
|
|
|
|
f = KisFilterRegistry::instance()->get(*it);
|
|
|
|
if (!f) break;
|
|
|
|
|
|
|
|
TQString s = f->menuCategory();
|
|
|
|
if (s == "adjust" && !m_filterActionMenus.find("adjust")) {
|
|
|
|
am = new KActionMenu(i18n("Adjust"), ac, "adjust_filters");
|
|
|
|
m_filterActionMenus.insert("adjust", am);
|
|
|
|
}
|
|
|
|
|
|
|
|
else if (s == "artistic" && !m_filterActionMenus.find("artistic")) {
|
|
|
|
am = new KActionMenu(i18n("Artistic"), ac, "artistic_filters");
|
|
|
|
m_filterActionMenus.insert("artistic", am);
|
|
|
|
}
|
|
|
|
|
|
|
|
else if (s == "blur" && !m_filterActionMenus.find("blur")) {
|
|
|
|
am = new KActionMenu(i18n("Blur"), ac, "blur_filters");
|
|
|
|
m_filterActionMenus.insert("blur", am);
|
|
|
|
}
|
|
|
|
|
|
|
|
else if (s == "colors" && !m_filterActionMenus.find("colors")) {
|
|
|
|
am = new KActionMenu(i18n("Colors"), ac, "color_filters");
|
|
|
|
m_filterActionMenus.insert("colors", am);
|
|
|
|
}
|
|
|
|
|
|
|
|
else if (s == "decor" && !m_filterActionMenus.find("decor")) {
|
|
|
|
am = new KActionMenu(i18n("Decor"), ac, "decor_filters");
|
|
|
|
m_filterActionMenus.insert("decor", am);
|
|
|
|
}
|
|
|
|
|
|
|
|
else if (s == "edge" && !m_filterActionMenus.find("edge")) {
|
|
|
|
am = new KActionMenu(i18n("Edge Detection"), ac, "edge_filters");
|
|
|
|
m_filterActionMenus.insert("edge", am);
|
|
|
|
}
|
|
|
|
|
|
|
|
else if (s == "emboss" && !m_filterActionMenus.find("emboss")) {
|
|
|
|
am = new KActionMenu(i18n("Emboss"), ac, "emboss_filters");
|
|
|
|
m_filterActionMenus.insert("emboss", am);
|
|
|
|
}
|
|
|
|
|
|
|
|
else if (s == "enhance" && !m_filterActionMenus.find("enhance")) {
|
|
|
|
am = new KActionMenu(i18n("Enhance"), ac, "enhance_filters");
|
|
|
|
m_filterActionMenus.insert("enhance", am);
|
|
|
|
}
|
|
|
|
|
|
|
|
else if (s == "map" && !m_filterActionMenus.find("map")) {
|
|
|
|
am = new KActionMenu(i18n("Map"), ac, "map_filters");
|
|
|
|
m_filterActionMenus.insert("map", am);
|
|
|
|
}
|
|
|
|
|
|
|
|
else if (s == "nonphotorealistic" && !m_filterActionMenus.find("nonphotorealistic")) {
|
|
|
|
am = new KActionMenu(i18n("Non-photorealistic"), ac, "nonphotorealistic_filters");
|
|
|
|
m_filterActionMenus.insert("nonphotorealistic", am);
|
|
|
|
}
|
|
|
|
|
|
|
|
else if (s == "other" && !m_filterActionMenus.find("other")) {
|
|
|
|
other = new KActionMenu(i18n("Other"), ac, "misc_filters");
|
|
|
|
m_filterActionMenus.insert("other", other);
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
m_reapplyAction = new KAction(i18n("Apply Filter Again"),
|
|
|
|
"Ctrl+Shift+F",
|
|
|
|
this, TQT_SLOT(slotApply()),
|
|
|
|
ac, "filter_apply_again");
|
|
|
|
|
|
|
|
m_reapplyAction->setEnabled(false);
|
|
|
|
|
|
|
|
f = 0;
|
|
|
|
i = 0;
|
|
|
|
for ( KisIDList::Iterator it = m_filterList.begin(); it != m_filterList.end(); ++it ) {
|
|
|
|
f = KisFilterRegistry::instance()->get(*it);
|
|
|
|
|
|
|
|
if (!f) break;
|
|
|
|
|
|
|
|
// Create action
|
|
|
|
KAction * a = new KAction(f->menuEntry(), 0, m_filterMapper, TQT_SLOT(map()), ac,
|
|
|
|
TQString("chalk_filter_%1").tqarg((*it) . id()).ascii());
|
|
|
|
|
|
|
|
// Add action to the right submenu
|
|
|
|
KActionMenu * m = m_filterActionMenus.find( f->menuCategory() );
|
|
|
|
if (m) {
|
|
|
|
m->insert(a);
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
if (!other) {
|
|
|
|
other = new KActionMenu(i18n("Other"), ac, "misc_filters");
|
|
|
|
m_filterActionMenus.insert("other", am);
|
|
|
|
}
|
|
|
|
other->insert(a);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Add filter to list of filters for mapper
|
|
|
|
m_filterMapper->setMapping( a, i );
|
|
|
|
|
|
|
|
m_filterActions.append( a );
|
|
|
|
++i;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void KisFilterManager::updateGUI()
|
|
|
|
{
|
|
|
|
KisImageSP img = m_view->currentImg();
|
|
|
|
if (!img) return;
|
|
|
|
|
|
|
|
KisLayerSP layer = img->activeLayer();
|
|
|
|
if (!layer) return;
|
|
|
|
|
|
|
|
KisPartLayer * partLayer = dynamic_cast<KisPartLayer*>(layer.data());
|
|
|
|
|
|
|
|
bool enable = !(layer->locked() || !layer->visible() || partLayer);
|
|
|
|
KisPaintLayerSP player = dynamic_cast<KisPaintLayer*>( layer.data());
|
|
|
|
if(!player)
|
|
|
|
{
|
|
|
|
enable = false;
|
|
|
|
}
|
|
|
|
m_reapplyAction->setEnabled(m_lastFilterConfig);
|
|
|
|
if (m_lastFilterConfig)
|
|
|
|
m_reapplyAction->setText(i18n("Apply Filter Again") + ": "
|
|
|
|
+ KisFilterRegistry::instance()->get(m_lastFilterConfig->name())->id().name());
|
|
|
|
else
|
|
|
|
m_reapplyAction->setText(i18n("Apply Filter Again"));
|
|
|
|
|
|
|
|
KAction * a;
|
|
|
|
int i = 0;
|
|
|
|
for (a = m_filterActions.first(); a; a = m_filterActions.next() , i++) {
|
|
|
|
KisFilter* filter = KisFilterRegistry::instance()->get(m_filterList[i]);
|
|
|
|
if(player && filter->workWith( player->paintDevice()->colorSpace()))
|
|
|
|
{
|
|
|
|
a->setEnabled(enable);
|
|
|
|
} else {
|
|
|
|
a->setEnabled(false);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
void KisFilterManager::slotApply()
|
|
|
|
{
|
|
|
|
apply();
|
|
|
|
}
|
|
|
|
|
|
|
|
bool KisFilterManager::apply()
|
|
|
|
{
|
|
|
|
if (!m_lastFilter) return false;
|
|
|
|
|
|
|
|
KisImageSP img = m_view->currentImg();
|
|
|
|
if (!img) return false;
|
|
|
|
|
|
|
|
KisPaintDeviceSP dev = img->activeDevice();
|
|
|
|
if (!dev) return false;
|
|
|
|
|
|
|
|
TQApplication::setOverrideCursor( KisCursor::waitCursor() );
|
|
|
|
|
|
|
|
//Apply the filter
|
|
|
|
m_lastFilterConfig = m_lastFilter->configuration(m_lastWidget);
|
|
|
|
|
|
|
|
TQRect r1 = dev->extent();
|
|
|
|
TQRect r2 = img->bounds();
|
|
|
|
|
|
|
|
// Filters should work only on the visible part of an image.
|
|
|
|
TQRect rect = r1.intersect(r2);
|
|
|
|
|
|
|
|
if (dev->hasSelection()) {
|
|
|
|
TQRect r3 = dev->selection()->selectedExactRect();
|
|
|
|
rect = rect.intersect(r3);
|
|
|
|
}
|
|
|
|
|
|
|
|
m_lastFilter->enableProgress();
|
|
|
|
|
|
|
|
m_view->progressDisplay()->setSubject(m_lastFilter, true, true);
|
|
|
|
m_lastFilter->setProgressDisplay( m_view->progressDisplay());
|
|
|
|
|
|
|
|
KisTransaction * cmd = 0;
|
|
|
|
if (img->undo()) cmd = new KisTransaction(m_lastFilter->id().name(), dev);
|
|
|
|
|
|
|
|
m_lastFilter->process(dev, dev, m_lastFilterConfig, rect);
|
|
|
|
m_reapplyAction->setEnabled(m_lastFilterConfig);
|
|
|
|
if (m_lastFilterConfig)
|
|
|
|
m_reapplyAction->setText(i18n("Apply Filter Again") + ": "
|
|
|
|
+ KisFilterRegistry::instance()->get(m_lastFilterConfig->name())->id().name());
|
|
|
|
|
|
|
|
else
|
|
|
|
m_reapplyAction->setText(i18n("Apply Filter Again"));
|
|
|
|
|
|
|
|
m_lastFilter->disableProgress();
|
|
|
|
TQApplication::restoreOverrideCursor();
|
|
|
|
|
|
|
|
|
|
|
|
if (m_lastFilter->cancelRequested()) {
|
|
|
|
delete m_lastFilterConfig;
|
|
|
|
if (cmd) {
|
|
|
|
cmd->unexecute();
|
|
|
|
delete cmd;
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
|
|
|
|
} else {
|
|
|
|
if (dev->parentLayer()) dev->parentLayer()->setDirty(rect);
|
|
|
|
m_doc->setModified(true);
|
|
|
|
if (img->undo() && cmd) img->undoAdapter()->addCommand(cmd);
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void KisFilterManager::slotApplyFilter(int i)
|
|
|
|
{
|
|
|
|
KisPreviewDialog * oldDialog = m_lastDialog;
|
|
|
|
KisFilterConfiguration * oldConfig = m_lastFilterConfig;
|
|
|
|
KisFilter * oldFilter = m_lastFilter;
|
|
|
|
|
|
|
|
m_lastFilter = KisFilterRegistry::instance()->get(m_filterList[i]);
|
|
|
|
|
|
|
|
if (!m_lastFilter) {
|
|
|
|
m_lastFilter = oldFilter;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
KisImageSP img = m_view->currentImg();
|
|
|
|
if (!img) return;
|
|
|
|
|
|
|
|
KisPaintDeviceSP dev = img->activeDevice();
|
|
|
|
if (!dev) return;
|
|
|
|
|
|
|
|
if (dev->colorSpace()->willDegrade(m_lastFilter->colorSpaceIndependence())) {
|
|
|
|
// Warning bells!
|
|
|
|
if (m_lastFilter->colorSpaceIndependence() == TO_LAB16) {
|
|
|
|
if (KMessageBox::warningContinueCancel(m_view,
|
|
|
|
i18n("The %1 filter will convert your %2 data to 16-bit L*a*b* and vice versa. ")
|
|
|
|
.tqarg(m_lastFilter->id().name())
|
|
|
|
.tqarg(dev->colorSpace()->id().name()),
|
|
|
|
i18n("Filter Will Convert Your Layer Data"),
|
|
|
|
KGuiItem(i18n("Continue")),
|
|
|
|
"lab16degradation") != KMessageBox::Continue) return;
|
|
|
|
|
|
|
|
}
|
|
|
|
else if (m_lastFilter->colorSpaceIndependence() == TO_RGBA8) {
|
|
|
|
if (KMessageBox::warningContinueCancel(m_view,
|
|
|
|
i18n("The %1 filter will convert your %2 data to 8-bit RGBA and vice versa. ")
|
|
|
|
.tqarg(m_lastFilter->id().name())
|
|
|
|
.tqarg(dev->colorSpace()->id().name()),
|
|
|
|
i18n("Filter Will Convert Your Layer Data"),
|
|
|
|
KGuiItem(i18n("Continue")),
|
|
|
|
"rgba8degradation") != KMessageBox::Continue) return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
m_lastFilter->disableProgress();
|
|
|
|
|
|
|
|
// Create the config dialog
|
|
|
|
m_lastDialog = new KisPreviewDialog(m_view, m_lastFilter->id().name().ascii(), true, m_lastFilter->id().name());
|
|
|
|
Q_CHECK_PTR(m_lastDialog);
|
|
|
|
m_lastWidget = m_lastFilter->createConfigurationWidget( (TQWidget*)m_lastDialog->container(), dev );
|
|
|
|
|
|
|
|
bool accepted = true;
|
|
|
|
|
|
|
|
if( m_lastWidget != 0)
|
|
|
|
{
|
|
|
|
connect(m_lastWidget, TQT_SIGNAL(sigPleaseUpdatePreview()), this, TQT_SLOT(slotConfigChanged()));
|
|
|
|
|
|
|
|
m_lastDialog->previewWidget()->slotSetDevice( dev );
|
|
|
|
|
|
|
|
connect(m_lastDialog->previewWidget(), TQT_SIGNAL(updated()), this, TQT_SLOT(refreshPreview()));
|
|
|
|
|
|
|
|
TQGridLayout *widgetLayout = new TQGridLayout((TQWidget *)m_lastDialog->container(), 1, 1);
|
|
|
|
|
|
|
|
widgetLayout->addWidget(m_lastWidget, 0 , 0);
|
|
|
|
|
|
|
|
m_lastDialog->container()->setMinimumSize(m_lastWidget->tqminimumSize());
|
|
|
|
|
|
|
|
refreshPreview();
|
|
|
|
|
|
|
|
if(m_lastDialog->exec() == TQDialog::Rejected )
|
|
|
|
{
|
|
|
|
accepted = false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!accepted || !apply()) {
|
|
|
|
// Override the old configuration
|
|
|
|
m_lastFilterConfig = oldConfig;
|
|
|
|
m_lastDialog = oldDialog;
|
|
|
|
m_lastFilter = oldFilter;
|
|
|
|
} else {
|
|
|
|
delete oldDialog;
|
|
|
|
delete oldConfig;
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
void KisFilterManager::slotConfigChanged()
|
|
|
|
{
|
|
|
|
if( m_lastDialog == 0 )
|
|
|
|
return;
|
|
|
|
if(m_lastDialog->previewWidget()->getAutoUpdate())
|
|
|
|
{
|
|
|
|
refreshPreview();
|
|
|
|
} else {
|
|
|
|
m_lastDialog->previewWidget()->needUpdate();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void KisFilterManager::refreshPreview( )
|
|
|
|
{
|
|
|
|
if( m_lastDialog == 0 ) return;
|
|
|
|
|
|
|
|
KisFilterConfiguration* config = m_lastFilter->configuration(m_lastWidget);
|
|
|
|
|
|
|
|
// The preview widget is in charge of running the filter so it can optimize the performance
|
|
|
|
m_lastDialog->previewWidget()->runFilter(m_lastFilter, config);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
#include "kis_filter_manager.moc"
|