chalk

kis_group_layer.cpp
1/*
2 * Copyright (c) 2005 Casper Boemann <cbr@boemann.dk>
3 *
4 * this program is free software; you can redistribute it and/or modify
5 * it under the terms of the gnu general public license as published by
6 * the free software foundation; either version 2 of the license, or
7 * (at your option) any later version.
8 *
9 * this program is distributed in the hope that it will be useful,
10 * but without any warranty; without even the implied warranty of
11 * merchantability or fitness for a particular purpose. see the
12 * gnu general public license for more details.
13 *
14 * you should have received a copy of the gnu general public license
15 * along with this program; if not, write to the free software
16 * foundation, inc., 675 mass ave, cambridge, ma 02139, usa.
17 */
18
19#include <kdebug.h>
20#include <tdeglobal.h>
21#include <tqimage.h>
22#include <tqdatetime.h>
23
24#include "kis_types.h"
25#include "kis_layer.h"
26#include "kis_group_layer.h"
27#include "kis_layer_visitor.h"
28#include "kis_debug_areas.h"
29#include "kis_image.h"
30#include "kis_paint_device.h"
31#include "kis_merge_visitor.h"
32#include "kis_fill_painter.h"
33
34KisGroupLayer::KisGroupLayer(KisImage *img, const TQString &name, TQ_UINT8 opacity) :
35 super(img, name, opacity),
36 m_x(0),
37 m_y(0)
38{
39 m_projection = new KisPaintDevice(this, img->colorSpace(), name.latin1());
40}
41
42KisGroupLayer::KisGroupLayer(const KisGroupLayer &rhs) :
43 super(rhs),
44 m_x(rhs.m_x),
45 m_y(rhs.m_y)
46{
47 for(vKisLayerSP_cit it = rhs.m_layers.begin(); it != rhs.m_layers.end(); ++it)
48 {
49 this->addLayer(it->data()->clone(), 0);
50 }
51 m_projection = new KisPaintDevice(*rhs.m_projection.data());
52 m_projection->setParentLayer(this);
53}
54
55KisLayerSP KisGroupLayer::clone() const
56{
57 return new KisGroupLayer(*this);
58}
59
60KisGroupLayer::~KisGroupLayer()
61{
62 m_layers.clear();
63}
64
65
66void KisGroupLayer::setDirty(bool propagate)
67{
68 KisLayer::setDirty(propagate);
69 if (propagate) emit (sigDirty(m_dirtyRect));
70}
71
72void KisGroupLayer::setDirty(const TQRect & rc, bool propagate)
73{
74 KisLayer::setDirty(rc, propagate);
75 if (propagate) emit sigDirty(rc);
76}
77
79{
80 if (to)
81 m_projection = new KisPaintDevice(*to);
82 else
83 m_projection = new KisPaintDevice(this, image()->colorSpace(), name().latin1());
84}
85
87 return l && l->paintDevice()->colorSpace() == m_image->colorSpace() && l->visible()
88 && l->opacity() == OPACITY_OPAQUE && !l->temporaryTarget() && !l->hasMask();
89}
90
91KisPaintDeviceSP KisGroupLayer::projection(const TQRect & rect)
92{
93 // We don't have a parent, and we've got only one child: abuse the child's
94 // paint device as the projection if the child is visible and 100% opaque
95 if (parent() == 0 && childCount() == 1) {
96 KisPaintLayerSP l = dynamic_cast<KisPaintLayer*>(firstChild().data());
98 l->setClean(rect);
99 setClean(rect);
100 return l->paintDevice();
101 }
102 }
103 // No need for updates, we're clean
104 if (!dirty()) {
105 return m_projection;
106 }
107 // No need for updates -- the desired area wasn't dirty
108 if (!rect.intersects(m_dirtyRect)) {
109 return m_projection;
110 }
111
112
113 // Okay, we need to update the intersection between
114 // what's dirty and what's asked us to be updated.
115 // XXX Nooo, that doesn't work, since the call to setClean following this, is actually:
116 // m_dirtyRect = TQRect(); So the non-intersecting part gets brilliantly lost otherwise.
117 const TQRect rc = m_dirtyRect;//rect.intersect(m_dirtyRect);
118
119 updateProjection(rc);
120 setClean(rect);
121
122 return m_projection;
123}
124
126{
127 return m_layers.count();
128}
129
131{
132 return at(0);
133}
134
135KisLayerSP KisGroupLayer::lastChild() const
136{
137 return at(childCount() - 1);
138}
139
140KisLayerSP KisGroupLayer::at(int index) const
141{
142 if (childCount() && index >= 0 && kClamp(uint(index), uint(0), childCount() - 1) == uint(index))
143 return m_layers.at(reverseIndex(index));
144 return 0;
145}
146
147int KisGroupLayer::index(KisLayerSP layer) const
148{
149 if (layer->parent().data() == this)
150 return layer->index();
151 return -1;
152}
153
154void KisGroupLayer::setIndex(KisLayerSP layer, int index)
155{
156 if (layer->parent().data() != this)
157 return;
158 //TODO optimize
159 removeLayer(layer);
160 addLayer(layer, index);
161}
162
163bool KisGroupLayer::addLayer(KisLayerSP newLayer, int x)
164{
165 if (x < 0 || kClamp(uint(x), uint(0), childCount()) != uint(x) ||
166 newLayer->parent() || m_layers.contains(newLayer))
167 {
168 kdWarning() << "invalid input to KisGroupLayer::addLayer(KisLayerSP newLayer, int x)!" << endl;
169 return false;
170 }
171 uint index(x);
172 if (index == 0)
173 m_layers.append(newLayer);
174 else
175 m_layers.insert(m_layers.begin() + reverseIndex(index) + 1, newLayer);
176 for (uint i = childCount() - 1; i > index; i--)
177 at(i)->m_index++;
178 newLayer->m_parent = this;
179 newLayer->m_index = index;
180 newLayer->setImage(image());
181 newLayer->setDirty(newLayer->extent());
182 setDirty();
183 return true;
184}
185
186bool KisGroupLayer::addLayer(KisLayerSP newLayer, KisLayerSP aboveThis)
187{
188 if (aboveThis && aboveThis->parent().data() != this)
189 {
190 kdWarning() << "invalid input to KisGroupLayer::addLayer(KisLayerSP newLayer, KisLayerSP aboveThis)!" << endl;
191 return false;
192 }
193 return addLayer(newLayer, aboveThis ? aboveThis->index() : childCount());
194}
195
197{
198 if (x >= 0 && kClamp(uint(x), uint(0), childCount() - 1) == uint(x))
199 {
200 uint index(x);
201 for (uint i = childCount() - 1; i > index; i--)
202 at(i)->m_index--;
203 KisLayerSP removedLayer = at(index);
204
205 removedLayer->m_parent = 0;
206 removedLayer->m_index = -1;
207 m_layers.erase(m_layers.begin() + reverseIndex(index));
208 setDirty(removedLayer->extent());
209 if (childCount() < 1) {
210 // No children, nothing to show for it.
211 m_projection->clear();
212 setDirty();
213 }
214 return true;
215 }
216 kdWarning() << "invalid input to KisGroupLayer::removeLayer()!" << endl;
217 return false;
218}
219
220bool KisGroupLayer::removeLayer(KisLayerSP layer)
221{
222 if (layer->parent().data() != this)
223 {
224 kdWarning() << "invalid input to KisGroupLayer::removeLayer()!" << endl;
225 return false;
226 }
227
228 return removeLayer(layer->index());
229}
230
231void KisGroupLayer::setImage(KisImage *image)
232{
233 super::setImage(image);
234 for (vKisLayerSP_it it = m_layers.begin(); it != m_layers.end(); ++it)
235 {
236 (*it)->setImage(image);
237 }
238}
239
241{
242 TQRect groupExtent;
243
244 for (vKisLayerSP_cit it = m_layers.begin(); it != m_layers.end(); ++it)
245 {
246 groupExtent |= (*it)->extent();
247 }
248
249 return groupExtent;
250}
251
253{
254 TQRect groupExactBounds;
255
256 for (vKisLayerSP_cit it = m_layers.begin(); it != m_layers.end(); ++it)
257 {
258 groupExactBounds |= (*it)->exactBounds();
259 }
260
261 return groupExactBounds;
262}
263
264TQ_INT32 KisGroupLayer::x() const
265{
266 return m_x;
267}
268
269void KisGroupLayer::setX(TQ_INT32 x)
270{
271 TQ_INT32 delta = x - m_x;
272
273 for (vKisLayerSP_cit it = m_layers.begin(); it != m_layers.end(); ++it)
274 {
275 KisLayerSP layer = *it;
276 layer->setX(layer->x() + delta);
277 }
278 m_x = x;
279}
280
281TQ_INT32 KisGroupLayer::y() const
282{
283 return m_y;
284}
285
286void KisGroupLayer::setY(TQ_INT32 y)
287{
288 TQ_INT32 delta = y - m_y;
289
290 for (vKisLayerSP_cit it = m_layers.begin(); it != m_layers.end(); ++it)
291 {
292 KisLayerSP layer = *it;
293 layer->setY(layer->y() + delta);
294 }
295
296 m_y = y;
297}
298
299TQImage KisGroupLayer::createThumbnail(TQ_INT32 w, TQ_INT32 h)
300{
301 return m_projection->createThumbnail(w, h);
302}
303
304void KisGroupLayer::updateProjection(const TQRect & rc)
305{
306 if (!m_dirtyRect.isValid()) return;
307
308 // Get the first layer in this group to start compositing with
309 KisLayerSP child = lastChild();
310
311 // No child -- clear the projection. Without children, a group layer is empty.
312 if (!child) m_projection->clear();
313
314 KisLayerSP startWith = 0;
315 KisAdjustmentLayerSP adjLayer = 0;
316 KisLayerSP tmpPaintLayer = 0;
317
318 // If this is the rootlayer, don't do anything with adj. layers that are below the
319 // first paintlayer
320 bool gotPaintLayer = (parent() != 0);
321
322 // Look through all the child layers, searching for the first dirty layer
323 // if it's found, and if we have found an adj. layer before the the dirty layer,
324 // composite from the first adjustment layer searching back from the first dirty layer
325 while (child) {
326 KisAdjustmentLayerSP tmpAdjLayer = dynamic_cast<KisAdjustmentLayer*>(child.data());
327 if (tmpAdjLayer) {
328 if (gotPaintLayer) {
329 // If this adjustment layer is dirty, start compositing with the
330 // previous layer, if there's one.
331 if (tmpAdjLayer->dirty(rc) && adjLayer != 0 && adjLayer->visible()) {
332 startWith = adjLayer->prevSibling();
333 break;
334 }
335 else if (tmpAdjLayer->visible() && !tmpAdjLayer->dirty(rc)) {
336 // This is the first adj. layer that is not dirty -- the perfect starting point
337 adjLayer = tmpAdjLayer;
338 }
339 else {
340 startWith = tmpPaintLayer;
341 }
342 }
343 }
344 else {
345 tmpPaintLayer = child;
346 gotPaintLayer = true;
347 // A non-adjustmentlayer that's dirty; if there's an adjustmentlayer
348 // with a cache, we'll start from there.
349 if (child->dirty(rc)) {
350 if (adjLayer != 0 && adjLayer->visible()) {
351 // the first layer on top of the adj. layer
352 startWith = adjLayer->prevSibling();
353 }
354 else {
355 startWith = child;
356 }
357 // break here: if there's no adj layer, we'll start with the layer->lastChild
358 break;
359 }
360 }
361 child = child->prevSibling();
362 }
363
364 if (adjLayer != 0 && startWith == 0 && gotPaintLayer && adjLayer->prevSibling()) {
365 startWith = adjLayer->prevSibling();
366 }
367
368 // No adj layer -- all layers inside the group must be recomposited
369 if (adjLayer == 0) {
370 startWith = lastChild();
371 }
372
373 if (startWith == 0) {
374 return;
375 }
376
377 bool first = true; // The first layer in a stack needs special compositing
378
379 // Fill the projection either with the cached data, or erase it.
380 KisFillPainter gc(m_projection);
381 if (adjLayer != 0) {
382 gc.bitBlt(rc.left(), rc.top(),
383 COMPOSITE_COPY, adjLayer->cachedPaintDevice(), OPACITY_OPAQUE,
384 rc.left(), rc.top(), rc.width(), rc.height());
385 first = false;
386 }
387 else {
388 gc.eraseRect(rc);
389 first = true;
390 }
391 gc.end();
392
393 KisMergeVisitor visitor(m_projection, rc);
394
395 child = startWith;
396
397 while(child)
398 {
399 if(first)
400 {
401 // Copy the lowest layer rather than compositing it with the background
402 // or an empty image. This means the layer's composite op is ignored,
403 // which is consistent with Photoshop and gimp.
404 const KisCompositeOp cop = child->compositeOp();
405 const bool block = child->signalsBlocked();
406 child->blockSignals(true);
407 // Composite op copy doesn't take a mask/selection into account, so we need
408 // to make a difference between a paintlayer with a mask, and one without
409 KisPaintLayer* l = dynamic_cast<KisPaintLayer*>(child.data());
410 if (l && l->hasMask())
411 child->m_compositeOp = COMPOSITE_OVER;
412 else
413 child->m_compositeOp = COMPOSITE_COPY;
414 child->blockSignals(block);
415 child->accept(visitor);
416 child->blockSignals(true);
417 child->m_compositeOp = cop;
418 child->blockSignals(block);
419 first = false;
420 }
421 else
422 child->accept(visitor);
423
424 child = child->prevSibling();
425 }
426}
427
428#include "kis_group_layer.moc"
Class that contains a KisFilter and optionally a KisSelection.
A KisLayer that bundles child layers into a single layer.
virtual KisLayerSP firstChild() const
Returns the first child layer of this layer (if it supports that).
virtual KisPaintDeviceSP projection(const TQRect &rect)
will copy from to, if !0, CoW!!
virtual uint childCount() const
Returns how many direct child layers this layer has (not recursive).
virtual void resetProjection(KisPaintDevice *to=0)
virtual TQRect exactBounds() const
Returns the exact bounds of where the actual data resides in this layer.
virtual KisLayerSP clone() const
Return a copy of this layer.
virtual bool addLayer(KisLayerSP newLayer, int index)
Adds the layer to this group at the specified index.
virtual void setDirty(bool propagate=true)
Set the entire layer extent dirty; this percolates up to parent layers all the way to the root layer.
virtual KisLayerSP at(int index) const
Returns the layer at the specified index.
virtual KisLayerSP lastChild() const
Returns the last child layer of this layer (if it supports that).
virtual void setIndex(KisLayerSP layer, int index)
Moves the specified layer to the specified index in the group, if it's already a member of this group...
virtual TQRect extent() const
Returns an approximation of where the bounds on actual data are in this layer.
virtual bool removeLayer(int index)
Removes the layer at the specified index from the group.
virtual bool paintLayerInducesProjectionOptimization(KisPaintLayer *l)
Returns if the layer will induce the projection hack (if the only layer in this group).
virtual int index(KisLayerSP layer) const
Returns the index of the layer if it's in this group, or -1 otherwise.
virtual TQImage createThumbnail(TQ_INT32 w, TQ_INT32 h)
Returns a thumbnail in requested size.
virtual void setClean(const TQRect &rect)
Set the specified rect to clean.
virtual bool dirty()
If the layer has been changed and not been composited yet, this returns true.
virtual KisGroupLayerSP parent() const
Returns the parent layer of a layer.
virtual void setDirty(bool propagate=true)
Set the entire layer extent dirty; this percolates up to parent layers all the way to the root layer.
virtual KisLayerSP prevSibling() const
Returns the previous sibling of this layer in the parent's list.
A paint device contains the actual pixel data and offers methods to read and write pixels.
void setParentLayer(KisLayer *parentLayer)
Set the KisLayer that contains this paint device, or 0 if this is not part of a layer.
This layer is of a type that can be painted on.
bool hasMask() const
Does this layer have a layer mask?