chalk

kis_layer.cpp
1/*
2 * Copyright (c) 2002 Patrick Julien <freak@codepimps.org>
3 * Copyright (c) 2005 Casper Boemann <cbr@boemann.dk>
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., 675 mass ave, cambridge, ma 02139, usa.
18 */
19
20#include <kdebug.h>
21#include <tqimage.h>
22
23#include "kis_debug_areas.h"
24#include "kis_group_layer.h"
25#include "kis_image.h"
26#include "kis_layer.h"
27#include "kis_painter.h"
28#include "kis_undo_adapter.h"
29
30namespace {
31
32 class KisLayerCommand : public KNamedCommand {
33 typedef KNamedCommand super;
34
35 public:
36 KisLayerCommand(const TQString& name, KisLayerSP layer);
37 virtual ~KisLayerCommand() {}
38
39 virtual void execute() = 0;
40 virtual void unexecute() = 0;
41
42 protected:
43 void setUndo(bool undo);
44
45 KisLayerSP m_layer;
46 };
47
48 KisLayerCommand::KisLayerCommand(const TQString& name, KisLayerSP layer) :
49 super(name), m_layer(layer)
50 {
51 }
52
53 void KisLayerCommand::setUndo(bool undo)
54 {
55 if (m_layer->undoAdapter()) {
56 m_layer->undoAdapter()->setUndo(undo);
57 }
58 }
59
60 class KisLayerLockedCommand : public KisLayerCommand {
61 typedef KisLayerCommand super;
62
63 public:
64 KisLayerLockedCommand(KisLayerSP layer, bool newLocked);
65
66 virtual void execute();
67 virtual void unexecute();
68
69 private:
70 bool m_newLocked;
71 };
72
73 KisLayerLockedCommand::KisLayerLockedCommand(KisLayerSP layer, bool newLocked) :
74 super(i18n("Lock Layer"), layer)
75 {
76 m_newLocked = newLocked;
77 }
78
79 void KisLayerLockedCommand::execute()
80 {
81 setUndo(false);
82 m_layer->setLocked(m_newLocked);
83 setUndo(true);
84 }
85
86 void KisLayerLockedCommand::unexecute()
87 {
88 setUndo(false);
89 m_layer->setLocked(!m_newLocked);
90 setUndo(true);
91 }
92
93 class KisLayerOpacityCommand : public KisLayerCommand {
94 typedef KisLayerCommand super;
95
96 public:
97 KisLayerOpacityCommand(KisLayerSP layer, TQ_UINT8 oldOpacity, TQ_UINT8 newOpacity);
98
99 virtual void execute();
100 virtual void unexecute();
101
102 private:
103 TQ_UINT8 m_oldOpacity;
104 TQ_UINT8 m_newOpacity;
105 };
106
107 KisLayerOpacityCommand::KisLayerOpacityCommand(KisLayerSP layer, TQ_UINT8 oldOpacity, TQ_UINT8 newOpacity) :
108 super(i18n("Layer Opacity"), layer)
109 {
110 m_oldOpacity = oldOpacity;
111 m_newOpacity = newOpacity;
112 }
113
114 void KisLayerOpacityCommand::execute()
115 {
116 setUndo(false);
117 m_layer->setOpacity(m_newOpacity);
118 setUndo(true);
119 }
120
121 void KisLayerOpacityCommand::unexecute()
122 {
123 setUndo(false);
124 m_layer->setOpacity(m_oldOpacity);
125 setUndo(true);
126 }
127
128 class KisLayerVisibilityCommand : public KisLayerCommand {
129 typedef KisLayerCommand super;
130
131 public:
132 KisLayerVisibilityCommand(KisLayerSP layer, bool newVisibility);
133
134 virtual void execute();
135 virtual void unexecute();
136
137 private:
138 bool m_newVisibility;
139 };
140
141 KisLayerVisibilityCommand::KisLayerVisibilityCommand(KisLayerSP layer, bool newVisibility) :
142 super(i18n("Layer Visibility"), layer)
143 {
144 m_newVisibility = newVisibility;
145 }
146
147 void KisLayerVisibilityCommand::execute()
148 {
149 setUndo(false);
150 m_layer->setVisible(m_newVisibility);
151 setUndo(true);
152 }
153
154 void KisLayerVisibilityCommand::unexecute()
155 {
156 setUndo(false);
157 m_layer->setVisible(!m_newVisibility);
158 setUndo(true);
159 }
160
161 class KisLayerCompositeOpCommand : public KisLayerCommand {
162 typedef KisLayerCommand super;
163
164 public:
165 KisLayerCompositeOpCommand(KisLayerSP layer, const KisCompositeOp& oldCompositeOp, const KisCompositeOp& newCompositeOp);
166
167 virtual void execute();
168 virtual void unexecute();
169
170 private:
171 KisCompositeOp m_oldCompositeOp;
172 KisCompositeOp m_newCompositeOp;
173 };
174
175 KisLayerCompositeOpCommand::KisLayerCompositeOpCommand(KisLayerSP layer, const KisCompositeOp& oldCompositeOp,
176 const KisCompositeOp& newCompositeOp) :
177 super(i18n("Layer Composite Mode"), layer)
178 {
179 m_oldCompositeOp = oldCompositeOp;
180 m_newCompositeOp = newCompositeOp;
181 }
182
183 void KisLayerCompositeOpCommand::execute()
184 {
185 setUndo(false);
186 m_layer->setCompositeOp(m_newCompositeOp);
187 setUndo(true);
188 }
189
190 void KisLayerCompositeOpCommand::unexecute()
191 {
192 setUndo(false);
193 m_layer->setCompositeOp(m_oldCompositeOp);
194 setUndo(true);
195 }
196
197 class KisLayerOffsetCommand : public KNamedCommand {
198 typedef KNamedCommand super;
199
200 public:
201 KisLayerOffsetCommand(KisLayerSP layer, const TQPoint& oldpos, const TQPoint& newpos);
202 virtual ~KisLayerOffsetCommand();
203
204 virtual void execute();
205 virtual void unexecute();
206
207 private:
208 void moveTo(const TQPoint& pos);
209
210 private:
211 KisLayerSP m_layer;
212 TQRect m_updateRect;
213 TQPoint m_oldPos;
214 TQPoint m_newPos;
215 };
216
217 KisLayerOffsetCommand::KisLayerOffsetCommand(KisLayerSP layer, const TQPoint& oldpos, const TQPoint& newpos) :
218 super(i18n("Move Layer"))
219 {
220 m_layer = layer;
221 m_oldPos = oldpos;
222 m_newPos = newpos;
223
224 TQRect currentBounds = m_layer->exactBounds();
225 TQRect oldBounds = currentBounds;
226 oldBounds.moveBy(oldpos.x() - newpos.x(), oldpos.y() - newpos.y());
227
228 m_updateRect = currentBounds | oldBounds;
229 }
230
231 KisLayerOffsetCommand::~KisLayerOffsetCommand()
232 {
233 }
234
235 void KisLayerOffsetCommand::execute()
236 {
237 moveTo(m_newPos);
238 }
239
240 void KisLayerOffsetCommand::unexecute()
241 {
242 moveTo(m_oldPos);
243 }
244
245 void KisLayerOffsetCommand::moveTo(const TQPoint& pos)
246 {
247 if (m_layer->undoAdapter()) {
248 m_layer->undoAdapter()->setUndo(false);
249 }
250
251 m_layer->setX(pos.x());
252 m_layer->setY(pos.y());
253
254 m_layer->setDirty(m_updateRect);
255
256 if (m_layer->undoAdapter()) {
257 m_layer->undoAdapter()->setUndo(true);
258 }
259 }
260}
261
262static int getID()
263{
264 static int id = 1;
265 return id++;
266}
267
268
269KisLayer::KisLayer(KisImage *img, const TQString &name, TQ_UINT8 opacity) :
270 TQObject(0, name.latin1()),
271 TDEShared(),
272 m_id(getID()),
273 m_index(-1),
274 m_opacity(opacity),
275 m_locked(false),
276 m_visible(true),
277 m_temporary(false),
278 m_name(name),
279 m_parent(0),
280 m_image(img),
281 m_compositeOp(COMPOSITE_OVER)
282{
283}
284
285KisLayer::KisLayer(const KisLayer& rhs) :
286 TQObject(),
287 TDEShared(rhs)
288{
289 if (this != &rhs) {
290 m_id = getID();
291 m_index = -1;
292 m_opacity = rhs.m_opacity;
293 m_locked = rhs.m_locked;
294 m_visible = rhs.m_visible;
295 m_temporary = rhs.m_temporary;
296 m_dirtyRect = rhs.m_dirtyRect;
297 m_name = rhs.m_name;
298 m_image = rhs.m_image;
299 m_parent = 0;
300 m_compositeOp = rhs.m_compositeOp;
301 }
302}
303
304KisLayer::~KisLayer()
305{
306}
307
308void KisLayer::setClean(const TQRect & rect)
309{
310 if (m_dirtyRect.isValid() && rect.isValid()) {
311
312 // XXX: We should only set the parts clean that were actually cleaned. However, extent and exactBounds conspire
313 // to make that very hard atm.
314 //if (rect.contains(m_dirtyRect)) m_dirtyRect = TQRect();
315 m_dirtyRect = TQRect();
316 }
317
318}
319
321{
322 return m_dirtyRect.isValid();
323}
324
325
326bool KisLayer::dirty(const TQRect & rc)
327{
328 if (!m_dirtyRect.isValid() || !rc.isValid()) return false;
329
330 return rc.intersects(m_dirtyRect);
331}
332
333TQRect KisLayer::dirtyRect() const
334{
335 return m_dirtyRect;
336}
337
338void KisLayer::setDirty(bool propagate)
339{
340 TQRect rc = extent();
341
342 if (rc.isValid()) m_dirtyRect = rc;
343
344 // If we're dirty, our parent is dirty, if we've got a parent
345 if (propagate && m_parent && rc.isValid()) m_parent->setDirty(m_dirtyRect);
346
347 if (m_image && rc.isValid()) {
348 m_image->notifyLayerUpdated(this, rc);
349 }
350}
351
352void KisLayer::setDirty(const TQRect & rc, bool propagate)
353{
354 // If we're dirty, our parent is dirty, if we've got a parent
355
356 if (rc.isValid())
357 m_dirtyRect |= rc;
358
359 if (propagate && m_parent && m_dirtyRect.isValid())
360 m_parent->setDirty(m_dirtyRect);
361
362 if (m_image && rc.isValid()) {
363 m_image->notifyLayerUpdated(this, rc);
364 }
365}
366
367KisGroupLayerSP KisLayer::parent() const
368{
369 return m_parent;
370}
371
372KisLayerSP KisLayer::prevSibling() const
373{
374 if (!parent())
375 return 0;
376 return parent()->at(index() - 1);
377}
378
379KisLayerSP KisLayer::nextSibling() const
380{
381 if (!parent())
382 return 0;
383 return parent()->at(index() + 1);
384}
385
386int KisLayer::index() const
387{
388 return m_index;
389}
390
392{
393 if (!parent())
394 return;
395 parent()->setIndex(this, i);
396}
397
398KisLayerSP KisLayer::findLayer(const TQString& n) const
399{
400 if (name() == n)
401 return const_cast<KisLayer*>(this); //HACK any less ugly way? findLayer() is conceptually const...
402 for (KisLayerSP layer = firstChild(); layer; layer = layer->nextSibling())
403 if (KisLayerSP found = layer->findLayer(n))
404 return found;
405 return 0;
406}
407
408KisLayerSP KisLayer::findLayer(int i) const
409{
410 if (id() == i)
411 return const_cast<KisLayer*>(this); //HACK
412 for (KisLayerSP layer = firstChild(); layer; layer = layer->nextSibling())
413 if (KisLayerSP found = layer->findLayer(i))
414 return found;
415 return 0;
416}
417
418int KisLayer::numLayers(int flags) const
419{
420 int num = 0;
421 if (matchesFlags(flags)) num++;
422 for (KisLayerSP layer = firstChild(); layer; layer = layer->nextSibling())
423 num += layer->numLayers(flags);
424 return num;
425}
426
427bool KisLayer::matchesFlags(int flags) const
428{
429 if ((flags & Visible) && !visible())
430 return false;
431 if ((flags & Hidden) && visible())
432 return false;
433 if ((flags & Locked) && !locked())
434 return false;
435 if ((flags & Unlocked) && locked())
436 return false;
437 return true;
438}
439
440TQ_UINT8 KisLayer::opacity() const
441{
442 return m_opacity;
443}
444
445void KisLayer::setOpacity(TQ_UINT8 val)
446{
447 if (m_opacity != val)
448 {
449 m_opacity = val;
450 setDirty();
451 notifyPropertyChanged();
452 }
453}
454
455KNamedCommand *KisLayer::setOpacityCommand(TQ_UINT8 newOpacity)
456{
457 return new KisLayerOpacityCommand(this, opacity(), newOpacity);
458}
459
460KNamedCommand *KisLayer::setOpacityCommand(TQ_UINT8 prevOpacity, TQ_UINT8 newOpacity)
461{
462 return new KisLayerOpacityCommand(this, prevOpacity, newOpacity);
463}
464
465const bool KisLayer::visible() const
466{
467 return m_visible;
468}
469
470void KisLayer::setVisible(bool v)
471{
472 if (m_visible != v) {
473
474 m_visible = v;
475 notifyPropertyChanged();
476 setDirty();
477
478 if (undoAdapter() && undoAdapter()->undo()) {
479 undoAdapter()->addCommand(setVisibleCommand(v));
480 }
481 }
482}
483
484KNamedCommand *KisLayer::setVisibleCommand(bool newVisibility)
485{
486 return new KisLayerVisibilityCommand(this, newVisibility);
487}
488
489bool KisLayer::locked() const
490{
491 return m_locked;
492}
493
494void KisLayer::setLocked(bool l)
495{
496 if (m_locked != l) {
497 m_locked = l;
498 notifyPropertyChanged();
499
500 if (undoAdapter() && undoAdapter()->undo()) {
501 undoAdapter()->addCommand(setLockedCommand(l));
502 }
503 }
504}
505
506bool KisLayer::temporary() const
507{
508 return m_temporary;
509}
510
511void KisLayer::setTemporary(bool t)
512{
513 m_temporary = t;
514}
515
516KNamedCommand *KisLayer::setLockedCommand(bool newLocked)
517{
518 return new KisLayerLockedCommand(this, newLocked);
519}
520
521TQString KisLayer::name() const
522{
523 return m_name;
524}
525
526void KisLayer::setName(const TQString& name)
527{
528 if (!name.isEmpty() && m_name != name)
529 {
530 m_name = name;
531 notifyPropertyChanged();
532 }
533}
534
535void KisLayer::setCompositeOp(const KisCompositeOp& compositeOp)
536{
537 if (m_compositeOp != compositeOp)
538 {
539 m_compositeOp = compositeOp;
540 notifyPropertyChanged();
541 setDirty();
542
543 }
544}
545
546KNamedCommand *KisLayer::setCompositeOpCommand(const KisCompositeOp& newCompositeOp)
547{
548 return new KisLayerCompositeOpCommand(this, compositeOp(), newCompositeOp);
549}
550
551KNamedCommand *KisLayer::moveCommand(TQPoint oldPosition, TQPoint newPosition)
552{
553 return new KisLayerOffsetCommand(this, oldPosition, newPosition);
554}
555
556KisUndoAdapter *KisLayer::undoAdapter() const
557{
558 if (m_image) {
559 return m_image->undoAdapter();
560 }
561 return 0;
562}
563
564void KisLayer::paintMaskInactiveLayers(TQImage &, TQ_INT32, TQ_INT32, TQ_INT32, TQ_INT32)
565{
566}
567
568void KisLayer::paintSelection(TQImage &, TQ_INT32, TQ_INT32, TQ_INT32, TQ_INT32)
569{
570}
571
572void KisLayer::paintSelection(TQImage &, const TQRect&, const TQSize&, const TQSize&)
573{
574}
575
576TQImage KisLayer::createThumbnail(TQ_INT32, TQ_INT32)
577{
578 return 0;
579}
580
581void KisLayer::notifyPropertyChanged()
582{
583 if(image() && !signalsBlocked())
584 image()->notifyPropertyChanged(this);
585}
586
587void KisLayerSupportsIndirectPainting::setTemporaryTarget(KisPaintDeviceSP t) {
588 m_temporaryTarget = t;
589}
590
591void KisLayerSupportsIndirectPainting::setTemporaryCompositeOp(const KisCompositeOp& c) {
592 m_compositeOp = c;
593}
594
595void KisLayerSupportsIndirectPainting::setTemporaryOpacity(TQ_UINT8 o) {
596 m_compositeOpacity = o;
597}
598
599KisPaintDeviceSP KisLayerSupportsIndirectPainting::temporaryTarget() {
600 return m_temporaryTarget;
601}
602
603KisCompositeOp KisLayerSupportsIndirectPainting::temporaryCompositeOp() const {
604 return m_compositeOp;
605}
606
607TQ_UINT8 KisLayerSupportsIndirectPainting::temporaryOpacity() const {
608 return m_compositeOpacity;
609}
610
611#include "kis_layer.moc"
Abstract class that represents the concept of a Layer in Chalk.
Definition kis_layer.h:42
virtual KisLayerSP nextSibling() const
Returns the next sibling of this layer in the parent's list.
virtual void setClean(const TQRect &rect)
Set the specified rect to clean.
virtual TQImage createThumbnail(TQ_INT32 w, TQ_INT32 h)
Returns a thumbnail in requested size.
virtual bool dirty()
If the layer has been changed and not been composited yet, this returns true.
virtual KisLayerSP firstChild() const
Returns the first child layer of this layer (if it supports that).
Definition kis_layer.h:133
virtual void paintSelection(TQImage &img, TQ_INT32 x, TQ_INT32 y, TQ_INT32 w, TQ_INT32 h)
paints a mask where the selection on this layer resides
virtual void paintMaskInactiveLayers(TQImage &img, TQ_INT32 x, TQ_INT32 y, TQ_INT32 w, TQ_INT32 h)
paints where no data is on this layer. Useful when it is a transparent layer stacked on top of anothe...
virtual TQRect extent() const =0
Returns an approximation of where the bounds on actual data are in this layer.
virtual KisLayerSP findLayer(const TQString &name) const
Recursively searches this layer and any child layers for a layer with the specified name.
virtual KisGroupLayerSP parent() const
Returns the parent layer of a layer.
virtual int numLayers(int type=0) const
Returns the total number of layers in this layer, its child layers, and their child layers recursivel...
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 void setIndex(int index)
Moves this layer to the specified index within its parent's list of child layers.
virtual KisLayerSP prevSibling() const
Returns the previous sibling of this layer in the parent's list.