krita

kis_tool_freehand.cc

00001 /*
00002  *  kis_tool_brush.cc - part of Krita
00003  *
00004  *  Copyright (c) 2003-2004 Boudewijn Rempt <boud@valdyas.org>
00005  *  Copyright (c) 2004 Bart Coppens <kde@bartcoppens.be>
00006  *
00007  *  This program is free software; you can redistribute it and/or modify
00008  *  it under the terms of the GNU General Public License as published by
00009  *  the Free Software Foundation; either version 2 of the License, or
00010  *  (at your option) any later version.
00011  *
00012  *  This program is distributed in the hope that it will be useful,
00013  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
00014  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00015  *  GNU General Public License for more details.
00016  *
00017  *  You should have received a copy of the GNU General Public License
00018  *  along with this program; if not, write to the Free Software
00019  *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
00020  */
00021 #include <qevent.h>
00022 #include <qlabel.h>
00023 #include <qlayout.h>
00024 #include <qwidget.h>
00025 #include <qrect.h>
00026 
00027 #include <kdebug.h>
00028 #include <kaction.h>
00029 #include <kcommand.h>
00030 #include <klocale.h>
00031 
00032 #include "kis_canvas_subject.h"
00033 #include "kis_undo_adapter.h"
00034 #include "kis_selection.h"
00035 #include "kis_painter.h"
00036 #include "kis_fill_painter.h"
00037 #include "kis_tool_freehand.h"
00038 #include "kis_cursor.h"
00039 #include "kis_button_press_event.h"
00040 #include "kis_button_release_event.h"
00041 #include "kis_move_event.h"
00042 #include "kis_layer.h"
00043 #include "kis_group_layer.h"
00044 #include "kis_paint_layer.h"
00045 #include "kis_canvas.h"
00046 #include "kis_canvas_painter.h"
00047 #include "kis_boundary_painter.h"
00048 #include "kis_brush.h"
00049 
00050 KisToolFreehand::KisToolFreehand(QString transactionText)
00051         : super(transactionText),
00052         m_dragDist ( 0 ),
00053         m_transactionText(transactionText),
00054         m_mode( HOVER )
00055 {
00056     m_painter = 0;
00057     m_currentImage = 0;
00058     m_tempLayer = 0;
00059     m_paintIncremental = true;
00060     m_paintOnSelection = false;
00061     m_paintedOutline = false;
00062 }
00063 
00064 KisToolFreehand::~KisToolFreehand()
00065 {
00066 }
00067 
00068 void KisToolFreehand::update(KisCanvasSubject *subject)
00069 {
00070     super::update(subject);
00071     m_currentImage = m_subject->currentImg();
00072 }
00073 
00074 void KisToolFreehand::buttonPress(KisButtonPressEvent *e)
00075 {
00076     if (!m_subject) return;
00077 
00078     if (!m_subject->currentBrush()) return;
00079 
00080     if (!m_currentImage || !m_currentImage->activeDevice()) return;
00081 
00082     if (e->button() == QMouseEvent::LeftButton) {
00083         
00084         
00085         if (!m_currentImage->bounds().contains(e->pos().floorQPoint())) return;
00086         
00087         initPaint(e);
00088         paintAt(e->pos(), e->pressure(), e->xTilt(), e->yTilt());
00089 
00090         m_prevPos = e->pos();
00091         m_prevPressure = e->pressure();
00092         m_prevXTilt = e->xTilt();
00093         m_prevYTilt = e->yTilt();
00094 
00095         QRect r = m_painter->dirtyRect();
00096         if ( r.isValid() ) {
00097             m_dirtyRect = r;
00098 
00099             r = QRect(r.left()-1, r.top()-1, r.width()+2, r.height()+2); //needed to update selectionvisualization
00100             if (!m_paintOnSelection) {
00101                 if (!m_paintIncremental) {
00102                     m_tempLayer->setDirty(r);
00103                 }
00104                 else {
00105                     m_currentImage->activeLayer()->setDirty(r);
00106                 }
00107             }
00108             else {
00109                 // Just update the canvas. XXX: After 1.5, find a better way to make sure tools don't set dirty what they didn't touch.
00110                 m_subject->canvasController()->updateCanvas( r );
00111             } 
00112         }
00113     }
00114 }
00115 
00116 void KisToolFreehand::buttonRelease(KisButtonReleaseEvent* e)
00117 {
00118     if (e->button() == QMouseEvent::LeftButton && m_mode == PAINT) {
00119         endPaint();
00120     }
00121 }
00122 
00123 void KisToolFreehand::move(KisMoveEvent *e)
00124 {
00125     if (m_mode == PAINT) {
00126 
00127         paintLine(m_prevPos, m_prevPressure, m_prevXTilt, m_prevYTilt, e->pos(), e->pressure(), e->xTilt(), e->yTilt());
00128     
00129         m_prevPos = e->pos();
00130         m_prevPressure = e->pressure();
00131         m_prevXTilt = e->xTilt();
00132         m_prevYTilt = e->yTilt();
00133 
00134         QRect r = m_painter->dirtyRect();
00135 
00136         if (r.isValid()) {
00137             m_dirtyRect |= r;
00138 
00139             if (!m_paintOnSelection) {
00140                 if (!m_paintIncremental) {
00141                     m_tempLayer->setDirty(r);
00142                 }
00143                 else {
00144                     m_currentImage->activeLayer()->setDirty(r);
00145                 }
00146             }
00147             else {
00148                 // Just update the canvas
00149                 r = QRect(r.left()-1, r.top()-1, r.width()+2, r.height()+2); //needed to update selectionvisualization
00150                 m_subject->canvasController()->updateCanvas( r );
00151             } 
00152         }
00153     }
00154 }
00155 
00156 void KisToolFreehand::initPaint(KisEvent *)
00157 {
00158     if (!m_currentImage || !m_currentImage->activeDevice()) return;
00159 
00160     m_mode = PAINT;
00161     m_dragDist = 0;
00162 
00163     // Create painter
00164     KisPaintDeviceSP device;
00165     if (m_currentImage && (device = m_currentImage->activeDevice())) {
00166         
00167         if (m_painter)
00168             delete m_painter;
00169         
00170         if (!m_paintIncremental) {
00171             if (m_currentImage->undo())
00172                 m_currentImage->undoAdapter()->beginMacro(m_transactionText);
00173 
00174             //if (m_tempLayer == 0) {
00175                 // XXX ugly! hacky! We'd like to cache the templayer, but that makes sure
00176                 // the layer is never really removed from its parent group because of shared pointers
00177                 m_tempLayer = new KisPaintLayer(m_currentImage, "temp", OPACITY_OPAQUE);
00178                 m_tempLayer->setTemporary(true);
00179                 // Yuck, what an ugly cast!
00180                 m_target = (dynamic_cast<KisPaintLayer*>(m_tempLayer.data()))->paintDevice();
00181             //}
00182 
00183             m_tempLayer->setCompositeOp( m_compositeOp );
00184             m_tempLayer->setOpacity( m_opacity );
00185 
00186             m_tempLayer->setVisible(true);
00187 
00188             currentImage()->addLayer(m_tempLayer, m_currentImage->activeLayer()->parent().data(), m_currentImage->activeLayer());
00189 
00190         } else {
00191             m_target = device;
00192         }
00193         m_painter = new KisPainter( m_target );
00194         Q_CHECK_PTR(m_painter);
00195         m_source = device;
00196         if (currentImage()->undo()) m_painter->beginTransaction(m_transactionText);
00197     }
00198 
00199     m_painter->setPaintColor(m_subject->fgColor());
00200     m_painter->setBackgroundColor(m_subject->bgColor());
00201     m_painter->setBrush(m_subject->currentBrush());
00202 
00203 
00204     // if you're drawing on a temporary layer, the layer already sets this
00205     if (m_paintIncremental) {
00206         m_painter->setCompositeOp(m_compositeOp);
00207         m_painter->setOpacity(m_opacity);
00208     } else {
00209         m_painter->setCompositeOp(COMPOSITE_OVER);
00210         m_painter->setOpacity( OPACITY_OPAQUE );
00211 
00212     }
00213 
00214 /*    kdDebug() << "target: " << m_target << "( " << m_target->name() << " )"
00215             << " source: " << m_source << "( " << m_source->name() << " )"
00216             << ", incremental " << m_paintIncremental
00217             << ", paint on selection: " << m_paintOnSelection
00218             << ", active device has selection: " << device->hasSelection()
00219             << ", target has selection: " << m_target->hasSelection()
00220             << endl;
00221 */
00222 }
00223 
00224 void KisToolFreehand::endPaint()
00225 {
00226     m_mode = HOVER;
00227     if (m_currentImage) {
00228         
00229         if (m_painter) {
00230             // If painting in mouse release, make sure painter
00231             // is destructed or end()ed
00232             if (!m_paintIncremental) {
00233                 if (m_currentImage->undo()) m_painter->endTransaction();
00234                 KisPainter painter( m_source );
00235                 painter.setCompositeOp(m_compositeOp);
00236                 if (m_currentImage->undo()) painter.beginTransaction(m_transactionText);
00237                 painter.bitBlt(m_dirtyRect.x(), m_dirtyRect.y(), m_compositeOp, m_target, m_opacity,
00238                                m_dirtyRect.x(), m_dirtyRect.y(), m_dirtyRect.width(), m_dirtyRect.height());
00239 
00240                 if (m_currentImage->undo()) m_currentImage->undoAdapter()->addCommand(painter.endTransaction());
00241                 m_currentImage->removeLayer(m_tempLayer);
00242                 // The shared ptr layer vector in the group keeps the layer from being
00243                 // being removed if it isn't removed here. It would be much faster to
00244                 // keep the layer and clear it, but that isn't possible. Replacing the
00245                 // old templayer with a new one at the end of paint prevents at least
00246                 // the pause when painting again.
00247                 //m_target->clear();
00248                 if (m_currentImage->undo()) m_currentImage->undoAdapter()->endMacro();
00249             } else {
00250                 if (m_currentImage->undo()) m_currentImage->undoAdapter()->addCommand(m_painter->endTransaction());
00251             }
00252         }
00253         delete m_painter;
00254         m_painter = 0;
00255         notifyModified();
00256     }
00257 }
00258 
00259 void KisToolFreehand::paintAt(const KisPoint &pos,
00260                const double pressure,
00261                const double xTilt,
00262                const double yTilt)
00263 {
00264     painter()->paintAt(pos, pressure, xTilt, yTilt);
00265 }
00266 
00267 void KisToolFreehand::paintLine(const KisPoint & pos1,
00268                  const double pressure1,
00269                  const double xtilt1,
00270                  const double ytilt1,
00271                  const KisPoint & pos2,
00272                  const double pressure2,
00273                  const double xtilt2,
00274                  const double ytilt2)
00275 {
00276     m_dragDist = painter()->paintLine(pos1, pressure1, xtilt1, ytilt1, pos2, pressure2, xtilt2, ytilt2, m_dragDist);
00277 }
00278 
00279 
00280 KisImageSP KisToolFreehand::currentImage()
00281 {
00282     return m_currentImage;
00283 }
00284 
00285 
00286 void KisToolFreehand::paintOutline(const KisPoint& point) {
00287     if (!m_subject) {
00288         return;
00289     }
00290 
00291     KisCanvasController *controller = m_subject->canvasController();
00292 
00293     if (currentImage() && !currentImage()->bounds().contains(point.floorQPoint())) {
00294         if (m_paintedOutline) {
00295             controller->kiscanvas()->update();
00296             m_paintedOutline = false;
00297         }
00298         return;
00299     }
00300 
00301     KisCanvas *canvas = controller->kiscanvas();
00302     canvas->repaint();
00303 
00304     KisBrush *brush = m_subject->currentBrush();
00305     // There may not be a brush present, and we shouldn't crash in that case
00306     if (brush) {
00307         KisCanvasPainter gc(canvas);
00308         QPen pen(Qt::SolidLine);
00309 
00310         KisPoint hotSpot = brush->hotSpot();
00311 
00312         gc.setRasterOp(Qt::NotROP);
00313         gc.setPen(pen);
00314         gc.setViewport(0, 0, static_cast<Q_INT32>(canvas->width() * m_subject->zoomFactor()),
00315                        static_cast<Q_INT32>(canvas->height() * m_subject->zoomFactor()));
00316         gc.translate((- controller->horzValue()) / m_subject->zoomFactor(),
00317                         (- controller->vertValue()) / m_subject->zoomFactor());
00318 
00319         KisPoint topLeft = point - hotSpot;
00320 
00321         if (m_subject->currentPaintop().id() == "pen") {
00322             // Pen paints on whole pixels only.
00323             topLeft = topLeft.roundQPoint();
00324         }
00325 
00326         gc.translate(topLeft.x(), topLeft.y());
00327 
00328         KisBoundaryPainter::paint(brush->boundary(), gc);
00329         m_paintedOutline = true;
00330     }
00331 }
00332 
00333 
00334 #include "kis_tool_freehand.moc"
00335 
KDE Home | KDE Accessibility Home | Description of Access Keys