kis_layer_manager.cc 28 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
/*
 *  Copyright (C) 2006 Boudewijn Rempt <boud@valdyas.org>
 *
 *  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.
 */

19
#include "kis_layer_manager.h"
20 21 22 23 24 25 26 27 28
#include <QRect>
#include <QApplication>
#include <QCursor>
#include <QString>
#include <QDialog>

#include <kactioncollection.h>
#include <ktoggleaction.h>
#include <klocale.h>
Aaron J. Seigo's avatar
Aaron J. Seigo committed
29
#include <kstandardaction.h>
30 31 32 33 34 35 36 37 38 39
#include <kmessagebox.h>
#include <kfiledialog.h>
#include <kurl.h>

#include <KoFilterManager.h>
#include <KoDocument.h>
#include <KoColorSpace.h>
#include <KoCompositeOp.h>
#include <KoPointerEvent.h>
#include <KoColorSpaceRegistry.h>
40
#include <KoColorProfile.h>
41 42
#include <KoSelection.h>
#include <KoShapeManager.h>
43
#include <KoProgressUpdater.h>
44

45
#include <filter/kis_filter_configuration.h>
Halla Rempt's avatar
Halla Rempt committed
46 47 48 49 50
#include <filter/kis_filter.h>
#include <kis_filter_strategy.h>
#include <generator/kis_generator_layer.h>
#include <kis_adjustment_layer.h>
#include <kis_clone_layer.h>
51
#include <kis_group_layer.h>
52 53
#include <kis_image.h>
#include <kis_layer.h>
54
#include <kis_paint_device.h>
55
#include <kis_paint_layer.h>
56
#include <kis_transaction.h>
57
#include <kis_selection.h>
58
#include <flake/kis_shape_layer.h>
59
#include <kis_shear_visitor.h>
Sven Langkamp's avatar
Sven Langkamp committed
60
#include <kis_transform_visitor.h>
61
#include <kis_undo_adapter.h>
62
#include <kis_painter.h>
63 64 65

#include "kis_config.h"
#include "kis_cursor.h"
66 67 68 69
#include "dialogs/kis_dlg_adj_layer_props.h"
#include "dialogs/kis_dlg_adjustment_layer.h"
#include "dialogs/kis_dlg_layer_properties.h"
#include "dialogs/kis_dlg_generator_layer.h"
70
#include "kis_doc2.h"
71
#include "kis_filter_manager.h"
72 73 74
#include "commands/kis_image_commands.h"
#include "commands/kis_layer_commands.h"
#include "commands/kis_node_commands.h"
Halla Rempt's avatar
Halla Rempt committed
75
#include "kis_canvas_resource_provider.h"
76 77 78 79
#include "kis_selection_manager.h"
#include "kis_statusbar.h"
#include "kis_view2.h"
#include "kis_zoom_manager.h"
Halla Rempt's avatar
Halla Rempt committed
80
#include "canvas/kis_canvas2.h"
81 82
#include "widgets/kis_meta_data_merge_strategy_chooser_widget.h"
#include "widgets/kis_wdg_generator.h"
83
#include "kis_progress_widget.h"
84
#include "kis_node_commands_adapter.h"
85
#include "kis_node_manager.h"
Halla Rempt's avatar
Halla Rempt committed
86

Halla Rempt's avatar
Halla Rempt committed
87 88 89
KisLayerManager::KisLayerManager(KisView2 * view, KisDoc2 * doc)
        : m_view(view)
        , m_doc(doc)
Halla Rempt's avatar
Halla Rempt committed
90 91
        , m_imageFlatten(0)
        , m_imageMergeLayer(0)
Halla Rempt's avatar
Halla Rempt committed
92 93
        , m_layerSaveAs(0)
        , m_actLayerVis(false)
Halla Rempt's avatar
Halla Rempt committed
94
        , m_imageResizeToLayer(0)
Halla Rempt's avatar
Halla Rempt committed
95
        , m_flattenLayer(0)
96
        , m_rasterizeLayer(0)
97
        , m_activeLayer(0)
Halla Rempt's avatar
Halla Rempt committed
98
        , m_commandsAdapter(new KisNodeCommandsAdapter(m_view))
99 100 101 102 103
{
}

KisLayerManager::~KisLayerManager()
{
104
    delete m_commandsAdapter;
105 106
}

107 108 109 110 111 112 113
KisLayerSP KisLayerManager::activeLayer()
{
    return m_activeLayer;
}

KisPaintDeviceSP KisLayerManager::activeDevice()
{
Halla Rempt's avatar
Halla Rempt committed
114
    if (m_activeLayer)
115 116 117
        return m_activeLayer->paintDevice();
    else
        return 0;
118 119
}

Halla Rempt's avatar
Halla Rempt committed
120
void KisLayerManager::activateLayer(KisLayerSP layer)
121 122
{
    m_activeLayer = layer;
Halla Rempt's avatar
Halla Rempt committed
123
    emit sigLayerActivated(layer);
124
    layersUpdated();
Halla Rempt's avatar
Halla Rempt committed
125
    if (layer) {
126 127
        m_view->resourceProvider()->slotNodeActivated(layer.data());
    }
128 129 130
}


131 132
void KisLayerManager::setup(KActionCollection * actionCollection)
{
Halla Rempt's avatar
Halla Rempt committed
133 134 135 136
    m_imageFlatten  = new KAction(i18n("&Flatten image"), this);
    actionCollection->addAction("flatten_image", m_imageFlatten);
    m_imageFlatten->setShortcut(QKeySequence(Qt::CTRL + Qt::SHIFT + Qt::Key_E));
    connect(m_imageFlatten, SIGNAL(triggered()), this, SLOT(flattenImage()));
137

Halla Rempt's avatar
Halla Rempt committed
138 139 140 141
    m_imageMergeLayer  = new KAction(i18n("&Merge with Layer Below"), this);
    actionCollection->addAction("merge_layer", m_imageMergeLayer);
    m_imageMergeLayer->setShortcut(QKeySequence(Qt::CTRL + Qt::Key_E));
    connect(m_imageMergeLayer, SIGNAL(triggered()), this, SLOT(mergeLayer()));
142

Halla Rempt's avatar
Halla Rempt committed
143 144 145 146
    m_flattenLayer  = new KAction(i18n("&Flatten Layer"), this);
    actionCollection->addAction("flatten_layer", m_flattenLayer);
    connect(m_flattenLayer, SIGNAL(triggered()), this, SLOT(flattenLayer()));

147 148 149 150
    m_rasterizeLayer  = new KAction(i18n("Rasterize Layer"), this);
    actionCollection->addAction("rasterize_layer", m_rasterizeLayer);
    connect(m_rasterizeLayer, SIGNAL(triggered()), this, SLOT(rasterizeLayer()));
    
151
    m_layerSaveAs  = new KAction(KIcon("document-save"), i18n("Save Layer as Image..."), this);
Halla Rempt's avatar
Halla Rempt committed
152
    actionCollection->addAction("save_layer_as_image", m_layerSaveAs);
153 154
    connect(m_layerSaveAs, SIGNAL(triggered()), this, SLOT(saveLayerAsImage()));

Halla Rempt's avatar
Halla Rempt committed
155 156 157
    m_imageResizeToLayer  = new KAction(i18n("Size Canvas to Size of Current Layer"), this);
    actionCollection->addAction("resizeimagetolayer", m_imageResizeToLayer);
    connect(m_imageResizeToLayer, SIGNAL(triggered()), this, SLOT(imageResizeToActiveLayer()));
158 159
}

160
void KisLayerManager::addAction(QAction * action)
161 162 163 164
{
    m_pluginActions.append(action);
}

165
void KisLayerManager::updateGUI()
166
{
Halla Rempt's avatar
Halla Rempt committed
167
    KisImageWSP image = m_view->image();
168 169 170 171 172 173

    KisLayerSP layer;
    qint32 nlayers = 0;
    qint32 nvisible = 0;


Halla Rempt's avatar
Halla Rempt committed
174
    if (image) {
175
        layer = m_activeLayer;
Halla Rempt's avatar
Halla Rempt committed
176 177
        nlayers = image->nlayers();
        nvisible = nlayers - image->nHiddenLayers();
178 179
    }

Halla Rempt's avatar
Halla Rempt committed
180
    bool enable = image && layer && layer->visible() && !layer->userLocked() && !layer->systemLocked();
181 182 183

    m_layerSaveAs->setEnabled(enable);

Halla Rempt's avatar
Halla Rempt committed
184 185 186
    // XXX these should be named layer instead of image
    m_imageFlatten->setEnabled(nlayers > 1);
    m_imageMergeLayer->setEnabled(nlayers > 1 && layer && layer->prevSibling());
187
    m_flattenLayer->setEnabled(nlayers > 1 && layer && layer->firstChild());
188
    m_rasterizeLayer->setEnabled(enable && layer->inherits("KisShapeLayer"));
189

Halla Rempt's avatar
Halla Rempt committed
190
    m_imageResizeToLayer->setEnabled(activeLayer());
191

Halla Rempt's avatar
Halla Rempt committed
192
    if (m_view->statusBar())
Halla Rempt's avatar
Halla Rempt committed
193
        m_view->statusBar()->setProfile(image);
194 195
}

Halla Rempt's avatar
Halla Rempt committed
196
void KisLayerManager::imageResizeToActiveLayer()
197 198 199 200
{
    KisLayerSP layer;
    KisUndoAdapter * undoAdapter = m_view->undoAdapter();

Halla Rempt's avatar
Halla Rempt committed
201
    KisImageWSP image = m_view->image();
202

Halla Rempt's avatar
Halla Rempt committed
203
    if (image && (layer = activeLayer())) {
204

205
        undoAdapter->beginMacro(i18n("Resize Image to Size of Current Layer"));
206
        image->resize(layer->exactBounds(), true);
207
        undoAdapter->endMacro();
208
    }
209 210 211 212 213 214 215 216 217
}

void KisLayerManager::actLayerVisChanged(int show)
{
    m_actLayerVis = (show != 0);
}

void KisLayerManager::layerProperties()
{
Halla Rempt's avatar
Halla Rempt committed
218
    KisLayerSP layer = m_activeLayer;
219

Halla Rempt's avatar
Halla Rempt committed
220
    if (!layer) return;
221

222
    const KoColorSpace * cs = 0;
Halla Rempt's avatar
Halla Rempt committed
223 224
    KisPaintLayer * pl = dynamic_cast<KisPaintLayer*>(layer.data());
    if (pl) {
225
        cs = pl->paintDevice()->colorSpace();
Halla Rempt's avatar
Halla Rempt committed
226
    } else {
227 228 229 230
        cs = layer->image()->colorSpace();
    }


Halla Rempt's avatar
Halla Rempt committed
231
    if (KisAdjustmentLayerSP alayer = KisAdjustmentLayerSP(dynamic_cast<KisAdjustmentLayer*>(layer.data()))) {
232
        KisPaintDeviceSP dev = alayer->projection();
Halla Rempt's avatar
Halla Rempt committed
233 234
        KisLayerSP prev = dynamic_cast<KisLayer*>(alayer->prevSibling().data());
        if (prev) dev = prev->projection();
235

Halla Rempt's avatar
Halla Rempt committed
236
        KisDlgAdjLayerProps dlg(dev, alayer->image(), alayer->filter(), alayer->name(), i18n("Filter Layer Properties"), m_view, "dlgadjlayerprops");
Halla Rempt's avatar
Halla Rempt committed
237
        dlg.resize(dlg.minimumSizeHint());
238 239
        KisFilterConfiguration* config = dlg.filterConfiguration();
        QString before;
Halla Rempt's avatar
Halla Rempt committed
240
        if (config) {
241
            before = config->toXML();
242
        }
Halla Rempt's avatar
Halla Rempt committed
243
        if (dlg.exec() == QDialog::Accepted) {
244 245

            QString after;
246 247
            alayer->setName(dlg.layerName());

248
            if (dlg.filterConfiguration()) {
249
                after = dlg.filterConfiguration()->toXML();
250
            }
Halla Rempt's avatar
Halla Rempt committed
251
            if (after != before) {
252
                KisChangeFilterCmd<KisAdjustmentLayerSP> * cmd
Halla Rempt's avatar
Halla Rempt committed
253 254 255 256
                = new KisChangeFilterCmd<KisAdjustmentLayerSP>(alayer,
                        dlg.filterConfiguration(),
                        before,
                        after);
257 258 259 260
                cmd->redo();
                m_view->undoAdapter()->addCommand(cmd);
                m_doc->setModified(true);
            }
261
        }
Halla Rempt's avatar
Halla Rempt committed
262
    } else if (KisGeneratorLayerSP alayer = KisGeneratorLayerSP(dynamic_cast<KisGeneratorLayer*>(layer.data()))) {
263 264

        KisDlgGeneratorLayer dlg(alayer->name(), m_view);
265
        dlg.setCaption(i18n("Generator Layer Properties"));
266

267
        QString before = alayer->generator()->toXML();
268
        dlg.setConfiguration(alayer->generator());
Halla Rempt's avatar
Halla Rempt committed
269
        dlg.resize(dlg.minimumSizeHint());
270

271
        if (dlg.exec() == QDialog::Accepted) {
272

273
            QString after = dlg.configuration()->toXML();
Halla Rempt's avatar
Halla Rempt committed
274
            if (after != before) {
275
                KisChangeGeneratorCmd<KisGeneratorLayerSP> * cmd
Halla Rempt's avatar
Halla Rempt committed
276 277 278 279 280
                = new KisChangeGeneratorCmd<KisGeneratorLayerSP>(alayer,
                        dlg.configuration(),
                        before,
                        after
                                                                );
281 282 283 284 285

                cmd->redo();
                m_view->undoAdapter()->addCommand(cmd);
                m_doc->setModified(true);
            }
286 287

        }
Halla Rempt's avatar
Halla Rempt committed
288
    } else {
289 290 291
        KisDlgLayerProperties dlg(layer->name(),
                                  layer->opacity(),
                                  layer->compositeOp(),
292 293
                                  cs,
                                  layer->channelFlags());
Halla Rempt's avatar
Halla Rempt committed
294
        dlg.resize(dlg.minimumSizeHint());
295

Halla Rempt's avatar
Halla Rempt committed
296
        if (dlg.exec() == QDialog::Accepted) {
297

298
            QBitArray newChannelFlags = dlg.getChannelFlags();
299 300 301
            for (int i = 0; i < newChannelFlags.size(); ++i) {
                dbgUI << "we got flags: " << i << " is " << newChannelFlags.testBit(i);
            }
302
            QBitArray oldChannelFlags = layer->channelFlags();
303 304 305 306 307
            for (int i = 0; i < oldChannelFlags.size(); ++i) {
                dbgUI << "the old ones were: " << i << " is " << oldChannelFlags.testBit(i);
            }

            dbgUI << " and are they the same: " << (oldChannelFlags == newChannelFlags);
308

309
            if (layer->name() != dlg.getName() ||
Halla Rempt's avatar
Halla Rempt committed
310
                    layer->opacity() != dlg.getOpacity() ||
311
                    layer->compositeOp()->id() != dlg.getCompositeOp()
Halla Rempt's avatar
Halla Rempt committed
312
               ) {
313
                QApplication::setOverrideCursor(KisCursor::waitCursor());
314 315
                m_view->undoAdapter()->addCommand(new KisLayerPropsCommand(layer,
                                                  layer->opacity(), dlg.getOpacity(),
316
                                                  layer->compositeOpId(), dlg.getCompositeOp(),
317 318
                                                  layer->name(), dlg.getName(),
                                                  oldChannelFlags, newChannelFlags));
319
                QApplication::restoreOverrideCursor();
Halla Rempt's avatar
Halla Rempt committed
320
                m_doc->setModified(true);
321
            }
322 323 324 325
            if (oldChannelFlags != newChannelFlags) {
                layer->setChannelFlags(newChannelFlags);
                layer->setDirty();
            }
326 327
        }
    }
Halla Rempt's avatar
Halla Rempt committed
328

329 330 331 332
}

void KisLayerManager::layerAdd()
{
Halla Rempt's avatar
Halla Rempt committed
333 334
    KisImageWSP image = m_view->image();
    if (image && activeLayer()) {
Halla Rempt's avatar
Halla Rempt committed
335
        addLayer(activeLayer()->parent(), activeLayer());
Halla Rempt's avatar
Halla Rempt committed
336 337
    } else if (image)
        addLayer(image->rootLayer(), KisLayerSP(0));
338 339
}

340
void KisLayerManager::addLayer(KisNodeSP parent, KisNodeSP above)
341
{
Halla Rempt's avatar
Halla Rempt committed
342 343
    KisImageWSP image = m_view->image();
    if (image) {
344 345
        KisConfig cfg;
        QString profilename;
346
        KisLayerSP layer = new KisPaintLayer(image.data(), image->nextLayerName(), OPACITY_OPAQUE_U8, image->colorSpace());
347
        if (layer) {
348
            layer->setCompositeOp(COMPOSITE_OVER);
349
            m_commandsAdapter->addNode(layer.data(), parent.data(), above.data());
350
            m_view->canvas()->update();
351
            m_view->nodeManager()->activateNode(layer);
352 353
        } else {
            KMessageBox::error(m_view, i18n("Could not add layer to image."), i18n("Layer Error"));
354 355 356
        }
    }
}
357

358
void KisLayerManager::addGroupLayer(KisNodeSP parent, KisNodeSP above)
359
{
Halla Rempt's avatar
Halla Rempt committed
360 361
    KisImageWSP image = m_view->image();
    if (image) {
362
        KisLayerSP layer = KisLayerSP(new KisGroupLayer(image.data(), image->nextLayerName(), OPACITY_OPAQUE_U8));
363
        if (layer) {
364
            layer->setCompositeOp(COMPOSITE_OVER);
365
            m_commandsAdapter->addNode(layer.data(), parent.data(), above.data());
366
            m_view->canvas()->update();
367
            m_view->nodeManager()->activateNode(layer);
368 369 370 371 372 373 374 375 376
        } else {
            KMessageBox::error(m_view, i18n("Could not add layer to image."), i18n("Layer Error"));
        }
    }
}


void KisLayerManager::addCloneLayer()
{
Halla Rempt's avatar
Halla Rempt committed
377 378
    KisImageWSP image = m_view->image();
    if (image && activeLayer()) {
Halla Rempt's avatar
Halla Rempt committed
379
        addCloneLayer(activeLayer()->parent(), activeLayer());
Halla Rempt's avatar
Halla Rempt committed
380 381
    } else if (image)
        addCloneLayer(image->rootLayer(), KisLayerSP(0));
382 383
}

Halla Rempt's avatar
Halla Rempt committed
384
void KisLayerManager::addCloneLayer(KisNodeSP parent, KisNodeSP above)
385
{
Halla Rempt's avatar
Halla Rempt committed
386 387
    KisImageWSP image = m_view->image();
    if (image) {
388
        // Check whether we are not cloning a parent layer
Halla Rempt's avatar
Halla Rempt committed
389
        if (KisGroupLayer * from = dynamic_cast<KisGroupLayer*>(m_activeLayer.data())) {
Halla Rempt's avatar
Halla Rempt committed
390
            KisNodeSP parent = parent;
Halla Rempt's avatar
Halla Rempt committed
391
            while (parent && parent != image->root()) {
Halla Rempt's avatar
Halla Rempt committed
392
                if (parent.data() == from) {
393 394 395 396
                    // The chosen layer is one of our own parents -- this will
                    // lead to cyclic behaviour when updating. Don't do that!
                    return;
                }
Halla Rempt's avatar
Halla Rempt committed
397
                parent = parent->parent();
398 399 400
            }
        }

401
        KisLayerSP layer = new KisCloneLayer(m_activeLayer, image.data(), image->nextLayerName(), OPACITY_OPAQUE_U8);
402

Halla Rempt's avatar
Halla Rempt committed
403
        if (layer) {
404

405
            layer->setCompositeOp(COMPOSITE_OVER);
406
            m_commandsAdapter->addNode(layer.data(), parent.data(), above.data());
407
            m_view->nodeManager()->activateNode(layer);
408 409 410 411 412 413 414 415 416 417 418 419

            m_view->canvas()->update();

        } else {
            KMessageBox::error(m_view, i18n("Could not add layer to image."), i18n("Layer Error"));
        }
    }
}


void KisLayerManager::addShapeLayer()
{
Halla Rempt's avatar
Halla Rempt committed
420 421
    KisImageWSP image = m_view->image();
    if (image && activeLayer()) {
Halla Rempt's avatar
Halla Rempt committed
422
        addShapeLayer(activeLayer()->parent(), activeLayer());
Halla Rempt's avatar
Halla Rempt committed
423 424
    } else if (image)
        addShapeLayer(image->rootLayer(), KisLayerSP(0));
425 426 427
}


Halla Rempt's avatar
Halla Rempt committed
428
void KisLayerManager::addShapeLayer(KisNodeSP parent, KisNodeSP above)
429
{
Halla Rempt's avatar
Halla Rempt committed
430 431
    KisImageWSP image = m_view->image();
    if (image) {
Halla Rempt's avatar
Halla Rempt committed
432
        // XXX: Make work with nodes!
Halla Rempt's avatar
Halla Rempt committed
433
        KisLayer * parentLayer = dynamic_cast<KisLayer*>(parent.data());
Halla Rempt's avatar
Halla Rempt committed
434
        KoShapeContainer * parentContainer =
Halla Rempt's avatar
Halla Rempt committed
435 436
            dynamic_cast<KoShapeContainer*>(m_doc->shapeForNode(parentLayer));
        if (!parentContainer) return;
437

438
        KisLayerSP layer = new KisShapeLayer(parentContainer, m_doc->shapeController(), image.data(), image->nextLayerName(), OPACITY_OPAQUE_U8);
Halla Rempt's avatar
Halla Rempt committed
439
        if (layer) {
440
            layer->setCompositeOp(COMPOSITE_OVER);
441
            m_commandsAdapter->addNode(layer.data(), parent, above.data());
442
            m_view->nodeManager()->activateNode(layer);
443 444 445
            m_view->canvas()->update();
        } else {
            KMessageBox::error(m_view, i18n("Could not add layer to image."), i18n("Layer Error"));
446 447 448 449 450 451 452
        }
    }
}


void KisLayerManager::addAdjustmentLayer()
{
Halla Rempt's avatar
Halla Rempt committed
453
    addAdjustmentLayer(activeLayer()->parent(), activeLayer());
454 455
}

456
void KisLayerManager::addAdjustmentLayer(KisNodeSP parent, KisNodeSP above)
457 458 459
{
    Q_ASSERT(parent);

Halla Rempt's avatar
Halla Rempt committed
460 461
    KisImageWSP image = m_view->image();
    if (!image) return;
462

463
    KisLayerSP l = activeLayer();
464

465
    KisPaintDeviceSP dev = l->projection();
466 467

    KisSelectionSP selection;
Halla Rempt's avatar
Halla Rempt committed
468
    if (l->selection())
469 470
        selection = l->selection();
    else
Halla Rempt's avatar
Halla Rempt committed
471
        selection = image->globalSelection();
472

Halla Rempt's avatar
Halla Rempt committed
473
    KisAdjustmentLayerSP adjl = addAdjustmentLayer(parent, above, QString(), 0, selection);
474

Halla Rempt's avatar
Halla Rempt committed
475
    KisDlgAdjustmentLayer dlg(adjl, adjl.data(), dev, adjl->image(), image->nextLayerName(), i18n("New Filter Layer"), m_view, "dlgadjustmentlayer");
Halla Rempt's avatar
Halla Rempt committed
476
    dlg.resize(dlg.minimumSizeHint());
477

Halla Rempt's avatar
Halla Rempt committed
478
    if (dlg.exec() != QDialog::Accepted) {
479
        m_commandsAdapter->undoLastCommand();
Halla Rempt's avatar
Halla Rempt committed
480 481
    } else {
        adjl->setName(dlg.layerName());
482
        m_view->nodeManager()->activateNode(adjl);
483
    }
484 485
}

486
KisAdjustmentLayerSP KisLayerManager::addAdjustmentLayer(KisNodeSP parent, KisNodeSP above, const QString & name,
Halla Rempt's avatar
Halla Rempt committed
487
        KisFilterConfiguration * filter, KisSelectionSP selection)
488 489 490
{
    Q_ASSERT(parent);

Halla Rempt's avatar
Halla Rempt committed
491 492
    KisImageWSP image = m_view->image();
    if (!image) return 0;
493

Halla Rempt's avatar
Halla Rempt committed
494
    KisAdjustmentLayerSP l = new KisAdjustmentLayer(image, name, filter, selection);
495
    m_commandsAdapter->addNode(l.data(), parent, above);
Halla Rempt's avatar
Halla Rempt committed
496
    l->setDirty(image->bounds());
497
    return l;
498 499
}

Halla Rempt's avatar
Halla Rempt committed
500 501
void KisLayerManager::addGeneratorLayer()
{
Halla Rempt's avatar
Halla Rempt committed
502
    addGeneratorLayer(activeLayer()->parent(), activeLayer());
Halla Rempt's avatar
Halla Rempt committed
503 504 505 506
}

void KisLayerManager::addGeneratorLayer(KisNodeSP parent, KisNodeSP above)
{
507 508
    Q_ASSERT(parent);

Halla Rempt's avatar
Halla Rempt committed
509 510
    KisImageWSP image = m_view->image();
    if (!image) return;
511

Halla Rempt's avatar
Halla Rempt committed
512
    KisDlgGeneratorLayer dlg(image->nextLayerName(), m_view);
Halla Rempt's avatar
Halla Rempt committed
513
    dlg.resize(dlg.minimumSizeHint());
514

515 516 517 518
    if (dlg.exec() == QDialog::Accepted) {
        KisSelectionSP selection = m_view->selection();
        KisFilterConfiguration * generator = dlg.configuration();
        QString name = dlg.layerName();
Halla Rempt's avatar
Halla Rempt committed
519
        addGeneratorLayer(parent, above, name, generator, selection);
520 521
    }

Halla Rempt's avatar
Halla Rempt committed
522 523
}

524
void KisLayerManager::addGeneratorLayer(KisNodeSP parent, KisNodeSP above, const QString & name, KisFilterConfiguration * generator, KisSelectionSP selection)
Halla Rempt's avatar
Halla Rempt committed
525 526
{
    Q_ASSERT(parent);
527
    Q_ASSERT(generator);
Halla Rempt's avatar
Halla Rempt committed
528

Halla Rempt's avatar
Halla Rempt committed
529 530
    KisImageWSP image = m_view->image();
    if (!image) return;
Halla Rempt's avatar
Halla Rempt committed
531

Halla Rempt's avatar
Halla Rempt committed
532
    KisGeneratorLayerSP l = new KisGeneratorLayer(image, name, generator, selection);
533
    m_commandsAdapter->addNode(l.data(), parent, above.data());
534
    m_view->nodeManager()->activateNode(l);
Halla Rempt's avatar
Halla Rempt committed
535 536 537
    if (l->selection())
        l->setDirty(l->selection()->selectedExactRect());
    else
Halla Rempt's avatar
Halla Rempt committed
538
        l->setDirty(image->bounds());
Halla Rempt's avatar
Halla Rempt committed
539 540 541

}

542 543 544

void KisLayerManager::layerRemove()
{
Halla Rempt's avatar
Halla Rempt committed
545
    KisImageWSP image = m_view->image();
546

Halla Rempt's avatar
Halla Rempt committed
547
    if (image) {
548
        KisLayerSP layer = activeLayer();
549
        if (layer) {
550 551 552
            QRect extent = layer->extent();
            KisNodeSP parent = layer->parent();

553
            m_commandsAdapter->removeNode(layer);
554

555 556
            if (parent)
                parent->setDirty(extent);
557 558

            m_view->canvas()->update();
559
            m_view->updateGUI();
560 561 562 563 564 565
        }
    }
}

void KisLayerManager::layerDuplicate()
{
Halla Rempt's avatar
Halla Rempt committed
566
    KisImageWSP image = m_view->image();
567

Halla Rempt's avatar
Halla Rempt committed
568
    if (!image)
569 570
        return;

571
    KisLayerSP active = activeLayer();
572 573 574 575

    if (!active)
        return;

Halla Rempt's avatar
Halla Rempt committed
576
    KisLayerSP dup = dynamic_cast<KisLayer*>(active->clone().data());
577
    m_commandsAdapter->addNode(dup.data(), active->parent(), active.data());
578
    if (dup) {
Halla Rempt's avatar
Halla Rempt committed
579
        activateLayer(dup);
580
        dup->setDirty();
581 582 583 584 585 586 587 588
        m_view->canvas()->update();
    } else {
        KMessageBox::error(m_view, i18n("Could not add layer to image."), i18n("Layer Error"));
    }
}

void KisLayerManager::layerRaise()
{
Halla Rempt's avatar
Halla Rempt committed
589
    KisImageWSP image = m_view->image();
590 591
    KisLayerSP layer;

Halla Rempt's avatar
Halla Rempt committed
592
    if (!image)
593 594
        return;

595
    layer = activeLayer();
596

597
    m_commandsAdapter->raise(layer);
598
    layer->parent()->setDirty();
599 600 601 602
}

void KisLayerManager::layerLower()
{
Halla Rempt's avatar
Halla Rempt committed
603
    KisImageWSP image = m_view->image();
604 605
    KisLayerSP layer;

Halla Rempt's avatar
Halla Rempt committed
606
    if (!image)
607 608
        return;

609
    layer = activeLayer();
610

Halla Rempt's avatar
Halla Rempt committed
611
    m_commandsAdapter->lower(layer);
612
    layer->parent()->setDirty();
613 614 615 616
}

void KisLayerManager::layerFront()
{
Halla Rempt's avatar
Halla Rempt committed
617
    KisImageWSP image = m_view->image();
618 619
    KisLayerSP layer;

Halla Rempt's avatar
Halla Rempt committed
620
    if (!image)
621 622
        return;

623
    layer = activeLayer();
624
    m_commandsAdapter->toTop(layer);
625
    layer->parent()->setDirty();
626 627 628 629
}

void KisLayerManager::layerBack()
{
Halla Rempt's avatar
Halla Rempt committed
630 631
    KisImageWSP image = m_view->image();
    if (!image) return;
632 633 634

    KisLayerSP layer;

635
    layer = activeLayer();
636
    m_commandsAdapter->toBottom(layer);
637
    layer->parent()->setDirty();
638 639 640 641
}

void KisLayerManager::rotateLayer180()
{
Halla Rempt's avatar
Halla Rempt committed
642
    rotateLayer(M_PI);
643 644 645 646
}

void KisLayerManager::rotateLayerLeft90()
{
Halla Rempt's avatar
Halla Rempt committed
647
    rotateLayer(M_PI / 2 - 2*M_PI);
648 649 650 651
}

void KisLayerManager::rotateLayerRight90()
{
Halla Rempt's avatar
Halla Rempt committed
652
    rotateLayer(M_PI / 2);
653 654 655 656
}

void KisLayerManager::mirrorLayerX()
{
657 658 659 660 661 662 663
    KisLayerSP layer = activeLayer();
    
    if (layer->inherits("KisShapeLayer")) {
        m_view->image()->undoAdapter()->beginMacro(i18n("Mirror Layer X"));

        KisTransformVisitor visitor(m_view->image(), -1.0, 1.0, 0.0, 0.0, 0.0, m_view->image()->width(), 0, 0, 0);
        layer->accept(visitor);
664

665 666 667 668
        m_view->image()->undoAdapter()->endMacro();
    } else {
        KisPaintDeviceSP dev = activeDevice();
        if (!dev) return;
669

670
        KisTransaction transaction(i18n("Mirror Layer X"), dev);
671

672 673
        QRect dirty = KisTransformWorker::mirrorX(dev, m_view->selection());
        m_activeLayer->setDirty(dirty);
674

675 676
        transaction.commit(m_view->image()->undoAdapter());
    }
677 678 679 680 681 682 683
    m_doc->setModified(true);
    layersUpdated();
    m_view->canvas()->update();
}

void KisLayerManager::mirrorLayerY()
{
684 685 686 687
    KisLayerSP layer = activeLayer();
    
    if (layer->inherits("KisShapeLayer")) {
        m_view->image()->undoAdapter()->beginMacro(i18n("Mirror Layer Y"));
688

689 690
        KisTransformVisitor visitor(m_view->image(), 1.0, -1.0, 0.0, 0.0, 0.0, 0, m_view->image()->height(), 0, 0);
        layer->accept(visitor);
691

692 693 694 695 696 697
        m_view->image()->undoAdapter()->endMacro();
    } else {
        KisPaintDeviceSP dev = activeDevice();
        if (!dev) return;

        KisTransaction transaction(i18n("Mirror Layer Y"), dev);
698

699 700
        QRect dirty = KisTransformWorker::mirrorY(dev, m_view->selection());
        m_activeLayer->setDirty(dirty);
701

702 703
        transaction.commit(m_view->image()->undoAdapter());
    }
704 705 706 707 708 709 710 711 712
    m_doc->setModified(true);
    layersUpdated();
    m_view->canvas()->update();
}

void KisLayerManager::scaleLayer(double sx, double sy, KisFilterStrategy *filterStrategy)
{
    if (!m_view->image()) return;

Sven Langkamp's avatar
Sven Langkamp committed
713 714
    KisLayerSP layer = activeLayer();
    if (!layer) return;
715

716 717
    KoProgressUpdater* updater = m_view->createProgressUpdater();
    KoUpdaterPtr u = updater->startSubtask();
718

719
    m_view->image()->undoAdapter()->beginMacro(i18n("Scale Layer"));
720

721 722
    KisTransformVisitor visitor(m_view->image(), sx, sy, 0.0, 0.0, 0.0, 0, 0, u, filterStrategy);
    layer->accept(visitor);
723

724
    m_view->image()->undoAdapter()->endMacro();
725 726 727
    m_doc->setModified(true);
    layersUpdated();
    m_view->canvas()->update();
728 729

    updater->deleteLater();
730 731
}

732
void KisLayerManager::rotateLayer(double radians)
733 734 735
{
    if (!m_view->image()) return;

Sven Langkamp's avatar
Sven Langkamp committed
736 737
    KisLayerSP layer = activeLayer();
    if (!layer) return;
738

739 740
    KisUndoAdapter * undoAdapter = m_view->image()->undoAdapter();
    undoAdapter->beginMacro(i18n("Rotate Layer"));
741

742
    KisFilterStrategy *filter = KisFilterStrategyRegistry::instance()->value("Triangle");
743
    QRect r;
744

Halla Rempt's avatar
Halla Rempt committed
745
    if (KisSelectionSP selection = activeLayer()->selection())
746
        r = selection->selectedExactRect();
747
    else
Sven Langkamp's avatar
Sven Langkamp committed
748
        r = layer->exactBounds();
Halla Rempt's avatar
Halla Rempt committed
749 750 751 752
    double cx = r.x() + r.width() / 2.0;
    double cy = r.y() + r.height() / 2.0;
    qint32 tx = qint32(cx * cos(radians) - cy * sin(radians) - cx + 0.5);
    qint32 ty = qint32(cy * cos(radians) + cx * sin(radians) - cy + 0.5);
Sven Langkamp's avatar
Sven Langkamp committed
753 754
    KisTransformVisitor visitor(m_view->image(), 1.0, 1.0, 0, 0, radians, -tx, -ty, 0, filter);
    layer->accept(visitor);
755
    layer->parent()->setDirty(r);
756

757
    undoAdapter->endMacro();
758 759 760 761 762 763 764 765 766 767

    m_doc->setModified(true);
    layersUpdated();
    m_view->canvas()->update();
}

void KisLayerManager::shearLayer(double angleX, double angleY)
{
    if (!m_view->image()) return;

768
    KisLayerSP layer = activeLayer();