/* * Copyright (c) 2005 Boudewijn Rempt * (c) 2005 Bart Coppens * * 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. */ #include "tqpaintdevice.h" #include "tqpixmap.h" #include "tqimage.h" #include "tqpainter.h" #include #include "KoDocument.h" #include "KoDocumentChild.h" #include "KoFrame.h" #include "KoView.h" #include "kis_layer.h" #include "kis_types.h" #include "kis_colorspace_factory_registry.h" #include "kis_part_layer.h" #include "kis_group_layer.h" #include "kis_factory.h" #include "kis_paint_device.h" #include KisChildDoc::KisChildDoc ( KisDoc * kisDoc, const TQRect & rect, KoDocument * childDoc ) : KoDocumentChild( kisDoc, childDoc, rect ) , m_doc(kisDoc) , m_partLayer(0) { } KisChildDoc::KisChildDoc ( KisDoc * kisDoc ) : KoDocumentChild( kisDoc) , m_partLayer(0) { } KisChildDoc::~KisChildDoc () { // XXX doesn't this get deleted by itself or by anything else? Certainly looks so // (otherwise I get a double deletion of a TQObject, and chalk crashes) //delete m_doc; } KisPartLayerImpl::KisPartLayerImpl(KisImageSP img, KisChildDoc * doc) : super(img, i18n("Embedded Document"), OPACITY_OPAQUE), m_doc(doc) { m_cache = new KisPaintDevice( KisMetaRegistry::instance()->csRegistry()->getColorSpace(KisID("RGBA",""),""), name().latin1() ); m_activated = false; } KisPartLayerImpl::~KisPartLayerImpl() { } KisLayerSP KisPartLayerImpl::clone() const { return new KisPartLayerImpl(image(), childDoc()); } // Called when the layer is made active void KisPartLayerImpl::childActivated(KoDocumentChild* child) { // Clear the image, so that if we move the part while activated, no ghosts show up if (!m_activated && child == m_doc) { TQRect rect = extent(); m_activated = true; setDirty(rect); TQPtrList views = child->parentDocument()->views(); Q_ASSERT(views.count()); // XXX iterate over views connect(views.at(0), TQ_SIGNAL(activated(bool)), this, TQ_SLOT(childDeactivated(bool))); } } // Called when another layer is made inactive void KisPartLayerImpl::childDeactivated(bool activated) { // We probably changed, notify the image that it needs to repaint where we currently updated // We use the original geometry if (m_activated && !activated /* no clue, but debugging suggests it is false here */) { TQPtrList views = m_doc->parentDocument()->views(); Q_ASSERT(views.count()); views.at(0)->disconnect(TQ_SIGNAL(activated(bool))); m_activated = false; setDirty(m_doc->geometry()); } } void KisPartLayerImpl::setX(TQ_INT32 x) { TQRect rect = m_doc->geometry(); // KisPaintDevice::move moves to absolute coordinates, not relative. Work around that here, // since the part is not necesarily started at (0,0) rect.moveBy(x - this->x(), 0); m_doc->setGeometry(rect); } void KisPartLayerImpl::setY(TQ_INT32 y) { TQRect rect = m_doc->geometry(); // KisPaintDevice::move moves to absolute coordinates, not relative. Work around that here, // since the part is not necesarily started at (0,0) rect.moveBy(0, y - this->y()); m_doc->setGeometry(rect); } void KisPartLayerImpl::paintSelection(TQImage &img, TQ_INT32 x, TQ_INT32 y, TQ_INT32 w, TQ_INT32 h) { uchar *j = img.bits(); TQRect rect = m_doc->geometry(); for (int y2 = y; y2 < h + y; ++y2) { for (int x2 = x; x2 < w + x; ++x2) { if (!rect.contains(x2, y2)) { TQ_UINT8 g = (*(j + 0) + *(j + 1 ) + *(j + 2 )) / 9; *(j+0) = 165+g; *(j+1) = 128+g; *(j+2) = 128+g; } j+=4; } } } KisPaintDeviceSP KisPartLayerImpl::prepareProjection(KisPaintDeviceSP projection, const TQRect& r) { if (!m_doc || !m_doc->document() || m_activated) return 0; m_cache->clear(); TQRect intersection(r.intersect(exactBounds())); if (intersection.isEmpty()) return m_cache; // XXX: have a look at the comments and see if they still truthfully represent the code :/ // We know the embedded part's size through the ChildDoc // We move it to (0,0), since that is what we will start painting from in paintEverything. TQRect embedRect(intersection); embedRect.moveBy(- exactBounds().x(), - exactBounds().y()); TQRect paintRect(exactBounds()); paintRect.moveBy(- exactBounds().x(), - exactBounds().y()); TQPixmap pm1(projection->convertToTQImage(0 /*srgb XXX*/, intersection.x(), intersection.y(), intersection.width(), intersection.height())); TQPixmap pm2(extent().width(), extent().height()); copyBlt(&pm2, embedRect.x(), embedRect.y(), &pm1, 0, 0, embedRect.width(), embedRect.height()); TQPainter painter(&pm2); painter.setClipRect(embedRect); // KWord's KWPartFrameSet::drawFrameContents has some interesting remarks concerning // the semantics of the paintEverything call. // Since a Chalk Device really is displaysize/zoom agnostic, caring about zoom is not // really as important here. What we paint at the moment, is just (0,0)x(w,h) // Paint transparent, no zoom: m_doc->document()->paintEverything(painter, paintRect, true); copyBlt(&pm1, 0, 0, &pm2, embedRect.x(), embedRect.y(), embedRect.width(), embedRect.height()); TQImage qimg = pm1.convertToImage(); //assume the part is sRGB for now, and that "" is sRGB // And we need to paint offsetted m_cache->convertFromTQImage(qimg, "", intersection.left(), intersection.top()); return m_cache; } TQImage KisPartLayerImpl::createThumbnail(TQ_INT32 w, TQ_INT32 h) { TQRect bounds(exactBounds()); TQPixmap pm(w, h); TQPainter painter(&pm); painter.fillRect(0, 0, w, h, TQt::white); painter.scale(w / bounds.width(), h / bounds.height()); m_doc->document()->paintEverything(painter, bounds); TQImage qimg = pm.convertToImage(); return qimg; } bool KisPartLayerImpl::saveToXML(TQDomDocument doc, TQDomElement elem) { TQDomElement embeddedElement = doc.createElement("layer"); embeddedElement.setAttribute("name", name()); // x and y are loaded from the rect element in the embedded object tag embeddedElement.setAttribute("x", 0); embeddedElement.setAttribute("y", 0); embeddedElement.setAttribute("opacity", opacity()); embeddedElement.setAttribute("compositeop", compositeOp().id().id()); embeddedElement.setAttribute("visible", visible()); embeddedElement.setAttribute("locked", locked()); embeddedElement.setAttribute("layertype", "partlayer"); elem.appendChild(embeddedElement); TQDomElement objectElem = childDoc()->save(doc); embeddedElement.appendChild(objectElem); return true; } KisConnectPartLayerVisitor::KisConnectPartLayerVisitor(KisImageSP img, KisView* view, bool mode) : m_img(img), m_view(view), m_connect(mode) { } bool KisConnectPartLayerVisitor::visit(KisGroupLayer *layer) { KisLayerSP child = layer->lastChild(); while (child) { child->accept(*this); child = child->prevSibling(); } return true; } bool KisConnectPartLayerVisitor::visit(KisPartLayer *layer) { if (m_connect) { TQObject::connect(m_view, TQ_SIGNAL(childActivated(KoDocumentChild*)), layer, TQ_SLOT(childActivated(KoDocumentChild*))); } else { TQObject::disconnect(m_view, TQ_SIGNAL(childActivated(KoDocumentChild*)), layer, 0 ); } return true; } bool KisConnectPartLayerVisitor::visit(KisPaintLayer*) { return true; } bool KisConnectPartLayerVisitor::visit(KisAdjustmentLayer*) { return true; } #include "kis_part_layer.moc"