chalk

kis_part_layer.cpp
1/*
2 * Copyright (c) 2005 Boudewijn Rempt <boud@valdyas.org>
3 * (c) 2005 Bart Coppens <kde@bartcoppens.be>
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#include "tqpaintdevice.h"
20#include "tqpixmap.h"
21#include "tqimage.h"
22#include "tqpainter.h"
23
24#include <tdelocale.h>
25
26#include "KoDocument.h"
27#include "KoDocumentChild.h"
28#include "KoFrame.h"
29#include "KoView.h"
30
31#include "kis_layer.h"
32#include "kis_types.h"
33#include "kis_colorspace_factory_registry.h"
34#include "kis_part_layer.h"
35#include "kis_group_layer.h"
36#include "kis_factory.h"
37#include "kis_paint_device.h"
38#include <kis_meta_registry.h>
39
40KisChildDoc::KisChildDoc ( KisDoc * kisDoc, const TQRect & rect, KoDocument * childDoc )
41 : KoDocumentChild( kisDoc, childDoc, rect )
42 , m_doc(kisDoc)
43 , m_partLayer(0)
44{
45}
46
47
48KisChildDoc::KisChildDoc ( KisDoc * kisDoc )
49 : KoDocumentChild( kisDoc)
50 , m_partLayer(0)
51{
52}
53
54KisChildDoc::~KisChildDoc ()
55{
56 // XXX doesn't this get deleted by itself or by anything else? Certainly looks so
57 // (otherwise I get a double deletion of a TQObject, and chalk crashes)
58 //delete m_doc;
59}
60
61
62KisPartLayerImpl::KisPartLayerImpl(KisImageSP img, KisChildDoc * doc)
63 : super(img, i18n("Embedded Document"), OPACITY_OPAQUE), m_doc(doc)
64{
65 m_cache = new KisPaintDevice(
66 KisMetaRegistry::instance()->csRegistry()->getColorSpace(KisID("RGBA",""),""), name().latin1() );
67 m_activated = false;
68}
69
70KisPartLayerImpl::~KisPartLayerImpl()
71{
72}
73
74KisLayerSP KisPartLayerImpl::clone() const {
75 return new KisPartLayerImpl(image(), childDoc());
76}
77
78// Called when the layer is made active
79void KisPartLayerImpl::childActivated(KoDocumentChild* child)
80{
81 // Clear the image, so that if we move the part while activated, no ghosts show up
82 if (!m_activated && child == m_doc) {
83 TQRect rect = extent();
84 m_activated = true;
85 setDirty(rect);
86 TQPtrList<KoView> views = child->parentDocument()->views();
87 Q_ASSERT(views.count());
88 // XXX iterate over views
89 connect(views.at(0), TQ_SIGNAL(activated(bool)),
90 this, TQ_SLOT(childDeactivated(bool)));
91 }
92}
93
94// Called when another layer is made inactive
95void KisPartLayerImpl::childDeactivated(bool activated)
96{
97 // We probably changed, notify the image that it needs to repaint where we currently updated
98 // We use the original geometry
99 if (m_activated && !activated /* no clue, but debugging suggests it is false here */) {
100 TQPtrList<KoView> views = m_doc->parentDocument()->views();
101 Q_ASSERT(views.count());
102 views.at(0)->disconnect(TQ_SIGNAL(activated(bool)));
103 m_activated = false;
104 setDirty(m_doc->geometry());
105 }
106}
107
108void KisPartLayerImpl::setX(TQ_INT32 x) {
109 TQRect rect = m_doc->geometry();
110
111 // KisPaintDevice::move moves to absolute coordinates, not relative. Work around that here,
112 // since the part is not necesarily started at (0,0)
113 rect.moveBy(x - this->x(), 0);
114 m_doc->setGeometry(rect);
115}
116
117void KisPartLayerImpl::setY(TQ_INT32 y) {
118 TQRect rect = m_doc->geometry();
119
120 // KisPaintDevice::move moves to absolute coordinates, not relative. Work around that here,
121 // since the part is not necesarily started at (0,0)
122 rect.moveBy(0, y - this->y());
123 m_doc->setGeometry(rect);
124}
125
126void KisPartLayerImpl::paintSelection(TQImage &img, TQ_INT32 x, TQ_INT32 y, TQ_INT32 w, TQ_INT32 h) {
127 uchar *j = img.bits();
128 TQRect rect = m_doc->geometry();
129
130 for (int y2 = y; y2 < h + y; ++y2) {
131 for (int x2 = x; x2 < w + x; ++x2) {
132 if (!rect.contains(x2, y2)) {
133 TQ_UINT8 g = (*(j + 0) + *(j + 1 ) + *(j + 2 )) / 9;
134 *(j+0) = 165+g;
135 *(j+1) = 128+g;
136 *(j+2) = 128+g;
137 }
138 j+=4;
139 }
140 }
141
142}
143
144KisPaintDeviceSP KisPartLayerImpl::prepareProjection(KisPaintDeviceSP projection, const TQRect& r)
145{
146 if (!m_doc || !m_doc->document() || m_activated) return 0;
147
148 m_cache->clear();
149
150 TQRect intersection(r.intersect(exactBounds()));
151 if (intersection.isEmpty())
152 return m_cache;
153 // XXX: have a look at the comments and see if they still truthfully represent the code :/
154
155 // We know the embedded part's size through the ChildDoc
156 // We move it to (0,0), since that is what we will start painting from in paintEverything.
157 TQRect embedRect(intersection);
158 embedRect.moveBy(- exactBounds().x(), - exactBounds().y());
159 TQRect paintRect(exactBounds());
160 paintRect.moveBy(- exactBounds().x(), - exactBounds().y());
161
162 TQPixmap pm1(projection->convertToTQImage(0 /*srgb XXX*/,
163 intersection.x(), intersection.y(),
164 intersection.width(), intersection.height()));
165 TQPixmap pm2(extent().width(), extent().height());
166 copyBlt(&pm2, embedRect.x(), embedRect.y(), &pm1,
167 0, 0, embedRect.width(), embedRect.height());
168 TQPainter painter(&pm2);
169 painter.setClipRect(embedRect);
170
171 // KWord's KWPartFrameSet::drawFrameContents has some interesting remarks concerning
172 // the semantics of the paintEverything call.
173 // Since a Chalk Device really is displaysize/zoom agnostic, caring about zoom is not
174 // really as important here. What we paint at the moment, is just (0,0)x(w,h)
175 // Paint transparent, no zoom:
176 m_doc->document()->paintEverything(painter, paintRect, true);
177
178 copyBlt(&pm1, 0, 0, &pm2,
179 embedRect.x(), embedRect.y(), embedRect.width(), embedRect.height());
180 TQImage qimg = pm1.convertToImage();
181
182 //assume the part is sRGB for now, and that "" is sRGB
183 // And we need to paint offsetted
184 m_cache->convertFromTQImage(qimg, "", intersection.left(), intersection.top());
185
186 return m_cache;
187}
188
189TQImage KisPartLayerImpl::createThumbnail(TQ_INT32 w, TQ_INT32 h) {
190 TQRect bounds(exactBounds());
191 TQPixmap pm(w, h);
192 TQPainter painter(&pm);
193
194 painter.fillRect(0, 0, w, h, TQt::white);
195
196 painter.scale(w / bounds.width(), h / bounds.height());
197 m_doc->document()->paintEverything(painter, bounds);
198 TQImage qimg = pm.convertToImage();
199
200 return qimg;
201}
202
203bool KisPartLayerImpl::saveToXML(TQDomDocument doc, TQDomElement elem)
204{
205 TQDomElement embeddedElement = doc.createElement("layer");
206 embeddedElement.setAttribute("name", name());
207
208 // x and y are loaded from the rect element in the embedded object tag
209 embeddedElement.setAttribute("x", 0);
210 embeddedElement.setAttribute("y", 0);
211
212 embeddedElement.setAttribute("opacity", opacity());
213 embeddedElement.setAttribute("compositeop", compositeOp().id().id());
214 embeddedElement.setAttribute("visible", visible());
215 embeddedElement.setAttribute("locked", locked());
216 embeddedElement.setAttribute("layertype", "partlayer");
217 elem.appendChild(embeddedElement);
218
219 TQDomElement objectElem = childDoc()->save(doc);
220 embeddedElement.appendChild(objectElem);
221
222 return true;
223}
224
225KisConnectPartLayerVisitor::KisConnectPartLayerVisitor(KisImageSP img, KisView* view, bool mode)
226 : m_img(img), m_view(view), m_connect(mode)
227{
228}
229
230bool KisConnectPartLayerVisitor::visit(KisGroupLayer *layer) {
231 KisLayerSP child = layer->lastChild();
232
233 while (child) {
234 child->accept(*this);
235 child = child->prevSibling();
236 }
237
238 return true;
239}
240
241bool KisConnectPartLayerVisitor::visit(KisPartLayer *layer) {
242 if (m_connect) {
243 TQObject::connect(m_view, TQ_SIGNAL(childActivated(KoDocumentChild*)),
244 layer, TQ_SLOT(childActivated(KoDocumentChild*)));
245 } else {
246 TQObject::disconnect(m_view, TQ_SIGNAL(childActivated(KoDocumentChild*)), layer, 0 );
247 }
248
249 return true;
250}
251
252bool KisConnectPartLayerVisitor::visit(KisPaintLayer*) {
253 return true;
254}
255
256bool KisConnectPartLayerVisitor::visit(KisAdjustmentLayer*) {
257 return true;
258}
259
260#include "kis_part_layer.moc"
Class that contains a KisFilter and optionally a KisSelection.
The child document is responsible for saving and loading the embedded layers.
A KisLayer that bundles child layers into a single layer.
virtual KisLayerSP lastChild() const
Returns the last child layer of this layer (if it supports that).
Chalk has a large number of extensible resources.
Definition kis_id.h:57
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.
A paint device contains the actual pixel data and offers methods to read and write pixels.
This layer is of a type that can be painted on.
A PartLayer is a layer that contains a KOffice Part like a KWord document or a KSpread spreadsheet.
virtual TQRect extent() const
Returns an approximation of where the bounds on actual data are in this layer.
virtual TQImage createThumbnail(TQ_INT32 w, TQ_INT32 h)
Returns a thumbnail in requested size.
virtual KisChildDoc * childDoc() const
Returns the childDoc so that we can access the doc from other places, if need be (KisDoc)
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 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
An interface for the Part Layer so that we can use it in core/, but can implement it in ui/.