chalk

kis_filter_manager.cpp
1/*
2 * Copyright (c) 2005 Boudewijn Rempt <boud@valdyas.org>
3 * Copyright (c) 2007 Benjamin Schleimer <bensch128@yahoo.com>
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
18 */
19
20#include "tqsignalmapper.h"
21#include <tqlayout.h>
22#include <tqframe.h>
23#include <tqcursor.h>
24#include <tqapplication.h>
25#include <tdemessagebox.h>
26#include <kguiitem.h>
27
28#include <kis_cursor.h>
29#include "tdeaction.h"
30
31#include "kis_part_layer.h"
32#include "kis_id.h"
33#include "kis_view.h"
34#include "kis_doc.h"
35#include "kis_filter.h"
36#include "kis_layer.h"
37#include "kis_paint_device.h"
38#include "kis_paint_layer.h"
39#include "kis_filter_manager.h"
40#include "kis_filter_config_widget.h"
41#include "kis_previewwidget.h"
42#include "kis_previewdialog.h"
43#include "kis_filter_registry.h"
44#include "kis_transaction.h"
45#include "kis_undo_adapter.h"
46#include "kis_previewdialog.h"
47#include "kis_previewwidget.h"
48#include "kis_painter.h"
49#include "kis_selection.h"
50#include "kis_id.h"
51#include "kis_canvas_subject.h"
52#include "kis_doc.h"
53#include "kis_transaction.h"
54#include <kis_progress_display_interface.h>
55
56KisFilterManager::KisFilterManager(KisView * view, KisDoc * doc)
57 : m_view(view),
58 m_doc(doc)
59{
60 // XXX: Store & restore last filter & last filter configuration in session settings
61 m_reapplyAction = 0;
62 m_lastFilterConfig = 0;
63 m_lastDialog = 0;
64 m_lastFilter = 0;
65 m_lastWidget = 0;
66
67 m_filterMapper = new TQSignalMapper(this);
68
69 connect(m_filterMapper, TQ_SIGNAL(mapped(int)), this, TQ_SLOT(slotApplyFilter(int)));
70
71}
72
73KisFilterManager::~KisFilterManager()
74{
75 //delete m_reapplyAction;
76 //delete m_lastFilterConfig;
77 //delete m_filterMapper;
78}
79
80void KisFilterManager::setup(TDEActionCollection * ac)
81{
82 KisFilter * f = 0;
83 int i = 0;
84
85 // Only create the submenu's we've actually got filters for.
86 // XXX: Make this list extensible after 1.5
87
88 TDEActionMenu * other = 0;
89 TDEActionMenu * am = 0;
90
91 m_filterList = KisFilterRegistry::instance()->listKeys();
92
93 for ( KisIDList::Iterator it = m_filterList.begin(); it != m_filterList.end(); ++it ) {
94 f = KisFilterRegistry::instance()->get(*it);
95 if (!f) break;
96
97 TQString s = f->menuCategory();
98 if (s == "adjust" && !m_filterActionMenus.find("adjust")) {
99 am = new TDEActionMenu(i18n("Adjust"), ac, "adjust_filters");
100 m_filterActionMenus.insert("adjust", am);
101 }
102
103 else if (s == "artistic" && !m_filterActionMenus.find("artistic")) {
104 am = new TDEActionMenu(i18n("Artistic"), ac, "artistic_filters");
105 m_filterActionMenus.insert("artistic", am);
106 }
107
108 else if (s == "blur" && !m_filterActionMenus.find("blur")) {
109 am = new TDEActionMenu(i18n("Blur"), ac, "blur_filters");
110 m_filterActionMenus.insert("blur", am);
111 }
112
113 else if (s == "colors" && !m_filterActionMenus.find("colors")) {
114 am = new TDEActionMenu(i18n("Colors"), ac, "color_filters");
115 m_filterActionMenus.insert("colors", am);
116 }
117
118 else if (s == "decor" && !m_filterActionMenus.find("decor")) {
119 am = new TDEActionMenu(i18n("Decor"), ac, "decor_filters");
120 m_filterActionMenus.insert("decor", am);
121 }
122
123 else if (s == "edge" && !m_filterActionMenus.find("edge")) {
124 am = new TDEActionMenu(i18n("Edge Detection"), ac, "edge_filters");
125 m_filterActionMenus.insert("edge", am);
126 }
127
128 else if (s == "emboss" && !m_filterActionMenus.find("emboss")) {
129 am = new TDEActionMenu(i18n("Emboss"), ac, "emboss_filters");
130 m_filterActionMenus.insert("emboss", am);
131 }
132
133 else if (s == "enhance" && !m_filterActionMenus.find("enhance")) {
134 am = new TDEActionMenu(i18n("Enhance"), ac, "enhance_filters");
135 m_filterActionMenus.insert("enhance", am);
136 }
137
138 else if (s == "map" && !m_filterActionMenus.find("map")) {
139 am = new TDEActionMenu(i18n("Map"), ac, "map_filters");
140 m_filterActionMenus.insert("map", am);
141 }
142
143 else if (s == "nonphotorealistic" && !m_filterActionMenus.find("nonphotorealistic")) {
144 am = new TDEActionMenu(i18n("Non-photorealistic"), ac, "nonphotorealistic_filters");
145 m_filterActionMenus.insert("nonphotorealistic", am);
146 }
147
148 else if (s == "other" && !m_filterActionMenus.find("other")) {
149 other = new TDEActionMenu(i18n("Other"), ac, "misc_filters");
150 m_filterActionMenus.insert("other", other);
151 }
152
153 }
154
155 m_reapplyAction = new TDEAction(i18n("Apply Filter Again"),
156 "Ctrl+Shift+F",
157 this, TQ_SLOT(slotApply()),
158 ac, "filter_apply_again");
159
160 m_reapplyAction->setEnabled(false);
161
162 f = 0;
163 i = 0;
164 for ( KisIDList::Iterator it = m_filterList.begin(); it != m_filterList.end(); ++it ) {
165 f = KisFilterRegistry::instance()->get(*it);
166
167 if (!f) break;
168
169 // Create action
170 TDEAction * a = new TDEAction(f->menuEntry(), 0, m_filterMapper, TQ_SLOT(map()), ac,
171 TQString("chalk_filter_%1").arg((*it) . id()).ascii());
172
173 // Add action to the right submenu
174 TDEActionMenu * m = m_filterActionMenus.find( f->menuCategory() );
175 if (m) {
176 m->insert(a);
177 }
178 else {
179 if (!other) {
180 other = new TDEActionMenu(i18n("Other"), ac, "misc_filters");
181 m_filterActionMenus.insert("other", am);
182 }
183 other->insert(a);
184 }
185
186 // Add filter to list of filters for mapper
187 m_filterMapper->setMapping( a, i );
188
189 m_filterActions.append( a );
190 ++i;
191 }
192}
193
194void KisFilterManager::updateGUI()
195{
196 KisImageSP img = m_view->currentImg();
197 if (!img) return;
198
199 KisLayerSP layer = img->activeLayer();
200 if (!layer) return;
201
202 KisPartLayer * partLayer = dynamic_cast<KisPartLayer*>(layer.data());
203
204 bool enable = !(layer->locked() || !layer->visible() || partLayer);
205 KisPaintLayerSP player = dynamic_cast<KisPaintLayer*>( layer.data());
206 if(!player)
207 {
208 enable = false;
209 }
210 m_reapplyAction->setEnabled(m_lastFilterConfig);
211 if (m_lastFilterConfig)
212 m_reapplyAction->setText(i18n("Apply Filter Again") + ": "
213 + KisFilterRegistry::instance()->get(m_lastFilterConfig->name())->id().name());
214 else
215 m_reapplyAction->setText(i18n("Apply Filter Again"));
216
217 TDEAction * a;
218 int i = 0;
219 for (a = m_filterActions.first(); a; a = m_filterActions.next() , i++) {
220 KisFilter* filter = KisFilterRegistry::instance()->get(m_filterList[i]);
221 if(player && filter->workWith( player->paintDevice()->colorSpace()))
222 {
223 a->setEnabled(enable);
224 } else {
225 a->setEnabled(false);
226 }
227 }
228
229}
230
231void KisFilterManager::slotApply()
232{
233 apply();
234}
235
236bool KisFilterManager::apply()
237{
238 if (!m_lastFilter) return false;
239
240 KisImageSP img = m_view->currentImg();
241 if (!img) return false;
242
243 KisPaintDeviceSP dev = img->activeDevice();
244 if (!dev) return false;
245
246 TQApplication::setOverrideCursor( KisCursor::waitCursor() );
247
248 //Apply the filter
249 m_lastFilterConfig = m_lastFilter->configuration(m_lastWidget);
250
251 TQRect r1 = dev->extent();
252 TQRect r2 = img->bounds();
253
254 // Filters should work only on the visible part of an image.
255 TQRect rect = r1.intersect(r2);
256
257 if (dev->hasSelection()) {
258 TQRect r3 = dev->selection()->selectedExactRect();
259 rect = rect.intersect(r3);
260 }
261
262 m_lastFilter->enableProgress();
263
264 m_view->progressDisplay()->setSubject(m_lastFilter, true, true);
265 m_lastFilter->setProgressDisplay( m_view->progressDisplay());
266
267 KisTransaction * cmd = 0;
268 if (img->undo()) cmd = new KisTransaction(m_lastFilter->id().name(), dev);
269
270 m_lastFilter->process(dev, dev, m_lastFilterConfig, rect);
271 m_reapplyAction->setEnabled(m_lastFilterConfig);
272 if (m_lastFilterConfig)
273 m_reapplyAction->setText(i18n("Apply Filter Again") + ": "
274 + KisFilterRegistry::instance()->get(m_lastFilterConfig->name())->id().name());
275
276 else
277 m_reapplyAction->setText(i18n("Apply Filter Again"));
278
279 m_lastFilter->disableProgress();
280 TQApplication::restoreOverrideCursor();
281
282
283 if (m_lastFilter->cancelRequested()) {
284 delete m_lastFilterConfig;
285 if (cmd) {
286 cmd->unexecute();
287 delete cmd;
288 }
289 return false;
290
291 } else {
292 if (dev->parentLayer()) dev->parentLayer()->setDirty(rect);
293 m_doc->setModified(true);
294 if (img->undo() && cmd) img->undoAdapter()->addCommand(cmd);
295 return true;
296 }
297}
298
299void KisFilterManager::slotApplyFilter(int i)
300{
301 KisPreviewDialog * oldDialog = m_lastDialog;
302 KisFilterConfiguration * oldConfig = m_lastFilterConfig;
303 KisFilter * oldFilter = m_lastFilter;
304
305 m_lastFilter = KisFilterRegistry::instance()->get(m_filterList[i]);
306
307 if (!m_lastFilter) {
308 m_lastFilter = oldFilter;
309 return;
310 }
311
312 KisImageSP img = m_view->currentImg();
313 if (!img) return;
314
315 KisPaintDeviceSP dev = img->activeDevice();
316 if (!dev) return;
317
318 if (dev->colorSpace()->willDegrade(m_lastFilter->colorSpaceIndependence())) {
319 // Warning bells!
320 if (m_lastFilter->colorSpaceIndependence() == TO_LAB16) {
321 if (KMessageBox::warningContinueCancel(m_view,
322 i18n("The %1 filter will convert your %2 data to 16-bit L*a*b* and vice versa. ")
323 .arg(m_lastFilter->id().name())
324 .arg(dev->colorSpace()->id().name()),
325 i18n("Filter Will Convert Your Layer Data"),
326 KGuiItem(i18n("Continue")),
327 "lab16degradation") != KMessageBox::Continue) return;
328
329 }
330 else if (m_lastFilter->colorSpaceIndependence() == TO_RGBA8) {
331 if (KMessageBox::warningContinueCancel(m_view,
332 i18n("The %1 filter will convert your %2 data to 8-bit RGBA and vice versa. ")
333 .arg(m_lastFilter->id().name())
334 .arg(dev->colorSpace()->id().name()),
335 i18n("Filter Will Convert Your Layer Data"),
336 KGuiItem(i18n("Continue")),
337 "rgba8degradation") != KMessageBox::Continue) return;
338 }
339 }
340
341 m_lastFilter->disableProgress();
342
343 // Create the config dialog
344 m_lastDialog = new KisPreviewDialog(m_view, m_lastFilter->id().name().ascii(), true, m_lastFilter->id().name());
345 TQ_CHECK_PTR(m_lastDialog);
346 m_lastWidget = m_lastFilter->createConfigurationWidget( (TQWidget*)m_lastDialog->container(), dev );
347
348 bool accepted = true;
349
350 if( m_lastWidget != 0)
351 {
352 connect(m_lastWidget, TQ_SIGNAL(sigPleaseUpdatePreview()), this, TQ_SLOT(slotConfigChanged()));
353
354 m_lastDialog->previewWidget()->slotSetDevice( dev );
355
356 connect(m_lastDialog->previewWidget(), TQ_SIGNAL(updated()), this, TQ_SLOT(refreshPreview()));
357
358 TQGridLayout *widgetLayout = new TQGridLayout((TQWidget *)m_lastDialog->container(), 1, 1);
359
360 widgetLayout->addWidget(m_lastWidget, 0 , 0);
361
362 m_lastDialog->container()->setMinimumSize(m_lastWidget->minimumSize());
363
364 refreshPreview();
365
366 if(m_lastDialog->exec() == TQDialog::Rejected )
367 {
368 accepted = false;
369 }
370 }
371
372 if (!accepted || !apply()) {
373 // Override the old configuration
374 m_lastFilterConfig = oldConfig;
375 m_lastDialog = oldDialog;
376 m_lastFilter = oldFilter;
377 } else {
378 delete oldDialog;
379 delete oldConfig;
380 }
381
382}
383
384void KisFilterManager::slotConfigChanged()
385{
386 if( m_lastDialog == 0 )
387 return;
388 if(m_lastDialog->previewWidget()->getAutoUpdate())
389 {
390 refreshPreview();
391 } else {
392 m_lastDialog->previewWidget()->needUpdate();
393 }
394}
395
396
397void KisFilterManager::refreshPreview( )
398{
399 if( m_lastDialog == 0 ) return;
400
401 KisFilterConfiguration* config = m_lastFilter->configuration(m_lastWidget);
402
403 // The preview widget is in charge of running the filter so it can optimize the performance
404 m_lastDialog->previewWidget()->runFilter(m_lastFilter, config);
405}
406
407
408#include "kis_filter_manager.moc"
virtual bool workWith(KisColorSpace *)
Determine if this filter can work with this colorSpace.
Definition kis_filter.h:142
KisIDList listKeys() const
This function return a list of all the keys.
_T get(const KisID &name) const
This function allow to get an object from its KisID.