/* * kis_tool_transform.cc -- part of Chalk * * Copyright (c) 2004 Boudewijn Rempt * Copyright (c) 2005 Casper Boemann * * 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 #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "kis_tool_transform.h" #include "wdg_tool_transform.h" #include "kis_canvas.h" #include "kis_canvas_painter.h" namespace { class TransformCmd : public KisSelectedTransaction { typedef KisSelectedTransaction super; public: TransformCmd(KisToolTransform *tool, KisPaintDeviceSP device, KisPaintDeviceSP origDevice, double scaleX, double scaleY, double tX, double tY, double a, KisSelectionSP origSel, TQPoint startPos, TQPoint endPos); virtual ~TransformCmd(); public: virtual void execute(); virtual void unexecute(); void transformArgs(double &sx, double &sy, double &tx, double &ty, double &a); KisSelectionSP origSelection(TQPoint &startPos, TQPoint &endPos); KisPaintDeviceSP theDevice(); KisPaintDeviceSP origDevice(); private: double m_scaleX; double m_scaleY; double m_translateX; double m_translateY; double m_a; KisToolTransform *m_tool; KisSelectionSP m_origSelection; TQPoint m_startPos; TQPoint m_endPos; KisPaintDeviceSP m_device; KisPaintDeviceSP m_origDevice; }; TransformCmd::TransformCmd(KisToolTransform *tool, KisPaintDeviceSP device, KisPaintDeviceSP origDevice, double scaleX, double scaleY, double tX, double tY, double a, KisSelectionSP origSel, TQPoint startPos, TQPoint endPos) : super(i18n("Transform"), device) , m_scaleX(scaleX) , m_scaleY(scaleY) , m_translateX(tX) , m_translateY(tY) , m_a(a) , m_tool(tool) , m_origSelection(origSel) , m_startPos(startPos) , m_endPos(endPos) , m_device(device) , m_origDevice(origDevice) { } TransformCmd::~TransformCmd() { } void TransformCmd::transformArgs(double &sx, double &sy, double &tx, double &ty, double &a) { sx = m_scaleX; sy = m_scaleY; tx= m_translateX; ty = m_translateY; a = m_a; } KisSelectionSP TransformCmd::origSelection(TQPoint &startPos, TQPoint &endPos) { startPos = m_startPos; endPos = m_endPos; return m_origSelection; } void TransformCmd::execute() { super::execute(); } void TransformCmd::unexecute() { super::unexecute(); } KisPaintDeviceSP TransformCmd::theDevice() { return m_device; } KisPaintDeviceSP TransformCmd::origDevice() { return m_origDevice; } } KisToolTransform::KisToolTransform() : super(i18n("Transform")) , m_wasPressed( false ) { setName("tool_transform"); setCursor(KisCursor::selectCursor()); m_subject = 0; m_selecting = false; m_startPos = TQPoint(0, 0); m_endPos = TQPoint(0, 0); m_optWidget = 0; m_sizeCursors[0] = KisCursor::sizeVerCursor(); m_sizeCursors[1] = KisCursor::sizeBDiagCursor(); m_sizeCursors[2] = KisCursor::sizeHorCursor(); m_sizeCursors[3] = KisCursor::sizeFDiagCursor(); m_sizeCursors[4] = KisCursor::sizeVerCursor(); m_sizeCursors[5] = KisCursor::sizeBDiagCursor(); m_sizeCursors[6] = KisCursor::sizeHorCursor(); m_sizeCursors[7] = KisCursor::sizeFDiagCursor(); m_origDevice = 0; m_origSelection = 0; } KisToolTransform::~KisToolTransform() { } void KisToolTransform::deactivate() { if (m_subject && m_subject->undoAdapter()) m_subject->undoAdapter()->removeCommandHistoryListener( this ); KisImageSP img = m_subject->currentImg(); if (!img) return; paintOutline(); disconnect(m_subject->currentImg().data(), TQT_SIGNAL(sigLayerActivated(KisLayerSP)), this, TQT_SLOT(slotLayerActivated(KisLayerSP))); } void KisToolTransform::activate() { if(m_subject && m_subject->currentImg() && m_subject->currentImg()->activeDevice()) { //connect(m_subject, commandExecuted(KCommand *c), this, notifyCommandAdded( KCommand * c)); m_subject->undoAdapter()->setCommandHistoryListener( this ); KisToolControllerInterface *controller = m_subject->toolController(); if (controller) controller->setCurrentTool(this); TransformCmd * cmd=0; if(m_subject->currentImg()->undoAdapter()->presentCommand()) cmd = dynamic_cast(m_subject->currentImg()->undoAdapter()->presentCommand()); if (cmd == 0) { initHandles(); } else { // One of our commands is on top if(cmd->theDevice() == m_subject->currentImg()->activeDevice()) { // and it even has the same device // We should ask for tool args and orig selection m_origDevice = cmd->origDevice(); cmd->transformArgs(m_scaleX, m_scaleY, m_translateX, m_translateY, m_a); m_origSelection = cmd->origSelection(m_startPos, m_endPos); m_org_cenX = (m_startPos.x() + m_endPos.x()) / 2.0; m_org_cenY = (m_startPos.y() + m_endPos.y()) / 2.0; paintOutline(); } else initHandles(); } } connect(m_subject->currentImg(), TQT_SIGNAL(sigLayerActivated(KisLayerSP)), this, TQT_SLOT(slotLayerActivated(KisLayerSP))); } void KisToolTransform::initHandles() { TQ_INT32 x,y,w,h; KisImageSP img = m_subject->currentImg(); KisPaintDeviceSP dev = img->activeDevice(); if (!dev ) return; // Create a lazy copy of the current state m_origDevice = new KisPaintDevice(*dev.data()); Q_ASSERT(m_origDevice); if(dev->hasSelection()) { KisSelectionSP sel = dev->selection(); m_origSelection = new KisSelection(*sel.data()); TQRect r = sel->selectedExactRect(); r.rect(&x, &y, &w, &h); } else { dev->exactBounds(x,y,w,h); m_origSelection = 0; } m_startPos = TQPoint(x, y); m_endPos = TQPoint(x+w-1, y+h-1); m_org_cenX = (m_startPos.x() + m_endPos.x()) / 2.0; m_org_cenY = (m_startPos.y() + m_endPos.y()) / 2.0; m_a = 0.0; m_scaleX = 1.0; m_scaleY = 1.0; m_translateX = m_org_cenX; m_translateY = m_org_cenY; m_subject->canvasController() ->updateCanvas(); } void KisToolTransform::paint(KisCanvasPainter& gc) { paintOutline(gc, TQRect()); } void KisToolTransform::paint(KisCanvasPainter& gc, const TQRect& rc) { paintOutline(gc, rc); } void KisToolTransform::buttonPress(KisButtonPressEvent *e) { if (m_subject && e->button() == Qt::LeftButton) { m_wasPressed = true; } if (m_subject) { KisImageSP img = m_subject->currentImg(); if (img && img->activeDevice() && e->button() == Qt::LeftButton) { switch(m_function) { case ROTATE: m_clickoffset = e->pos().floorTQPoint() - TQPoint(static_cast(m_translateX),static_cast(m_translateY)); m_clickangle = -m_a - atan2(m_clickoffset.x(),m_clickoffset.y()); m_clickoffset = TQPoint(0, 0); break; case MOVE: m_clickoffset = e->pos().floorTQPoint() - TQPoint(static_cast(m_translateX),static_cast(m_translateY)); break; case TOPSCALE: m_clickoffset = e->pos().floorTQPoint() - TQPoint((m_topleft + m_topright)/2); break; case TOPRIGHTSCALE: m_clickoffset = e->pos().floorTQPoint() - m_topright; break; case RIGHTSCALE: m_clickoffset = e->pos().floorTQPoint() - TQPoint((m_topright + m_bottomright)/2); break; case BOTTOMRIGHTSCALE: m_clickoffset = e->pos().floorTQPoint() - m_bottomright; break; case BOTTOMSCALE: m_clickoffset = e->pos().floorTQPoint() - TQPoint((m_bottomleft + m_bottomright)/2); break; case BOTTOMLEFTSCALE: m_clickoffset = e->pos().floorTQPoint() - m_bottomleft; break; case LEFTSCALE: m_clickoffset = e->pos().floorTQPoint() - TQPoint((m_topleft + m_bottomleft)/2); break; case TOPLEFTSCALE: m_clickoffset = e->pos().floorTQPoint() - m_topleft; break; } m_selecting = true; m_actualyMoveWhileSelected = false; } } } int KisToolTransform::det(TQPoint v,TQPoint w) { return v.x()*w.y()-v.y()*w.x(); } int KisToolTransform::distsq(TQPoint v,TQPoint w) { v -= w; return v.x()*v.x() + v.y()*v.y(); } void KisToolTransform::setFunctionalCursor() { int rotOctant = 8 + int(8.5 + m_a* 4 / M_PI); int s; if(m_scaleX*m_scaleY<0) s = -1; else s=1; switch(m_function) { case MOVE: setCursor(KisCursor::moveCursor()); break; case ROTATE: setCursor(KisCursor::rotateCursor()); break; case TOPSCALE: setCursor(m_sizeCursors[(0*s +rotOctant)%8]); break; case TOPRIGHTSCALE: setCursor(m_sizeCursors[(1*s +rotOctant)%8]); break; case RIGHTSCALE: setCursor(m_sizeCursors[(2*s +rotOctant)%8]); break; case BOTTOMRIGHTSCALE: setCursor(m_sizeCursors[(3*s +rotOctant)%8]); break; case BOTTOMSCALE: setCursor(m_sizeCursors[(4*s +rotOctant)%8]); break; case BOTTOMLEFTSCALE: setCursor(m_sizeCursors[(5*s +rotOctant)%8]); break; case LEFTSCALE: setCursor(m_sizeCursors[(6*s +rotOctant)%8]); break; case TOPLEFTSCALE: setCursor(m_sizeCursors[(7*s +rotOctant)%8]); break; } } void KisToolTransform::move(KisMoveEvent *e) { if (m_subject) { KisCanvasController *controller = m_subject->canvasController(); Q_ASSERT(controller); TQPoint topleft = m_topleft; TQPoint topright = m_topright; TQPoint bottomleft = m_bottomleft; TQPoint bottomright = m_bottomright; TQPoint mousePos = e->pos().floorTQPoint(); if (m_subject && m_selecting) { paintOutline(); m_actualyMoveWhileSelected = true; mousePos -= m_clickoffset; // transform mousePos coords, so it seems like it isn't rotated and centered at 0,0 double newX = invrotX(mousePos.x() - m_translateX, mousePos.y() - m_translateY); double newY = invrotY(mousePos.x() - m_translateX, mousePos.y() - m_translateY); double dx=0, dy=0; double oldScaleX = m_scaleX; double oldScaleY = m_scaleY; if(m_function == MOVE) { m_translateX += mousePos.x() - m_translateX; m_translateY += mousePos.y() - m_translateY; } if(m_function == ROTATE) { m_a = -atan2(mousePos.x() - m_translateX, mousePos.y() - m_translateY) - m_clickangle; } if(m_function == TOPSCALE) { dy = (newY - m_scaleY * (m_startPos.y() - m_org_cenY)) / 2; m_scaleY = (newY - dy) / (m_startPos.y() - m_org_cenY); // enforce same acpect if shift button is pressed if(e->state() & TQt::ShiftButton) { if(m_scaleX>0) // handle the mirrored cases m_scaleX = fabs(m_scaleY); else m_scaleX = -fabs(m_scaleY); } } if(m_function == TOPRIGHTSCALE) { dx = (newX - m_scaleX * (m_endPos.x() - m_org_cenX)) / 2; m_scaleX = (newX - dx) / (m_endPos.x() - m_org_cenX); dy = (newY - m_scaleY * (m_startPos.y() - m_org_cenY)) / 2; m_scaleY = (newY - dy) / (m_startPos.y() - m_org_cenY); // enforce same aspect if shift button is pressed if(e->state() & TQt::ShiftButton) { if(m_scaleX < m_scaleY) { if(m_scaleX>0) // handle the mirrored cases m_scaleX = fabs(m_scaleY); else m_scaleX = -fabs(m_scaleY); dx = (m_scaleX - oldScaleX) * (m_endPos.x() - m_org_cenX); } else { if(m_scaleY>0) // handle the mirrored cases m_scaleY = fabs(m_scaleX); else m_scaleY = -fabs(m_scaleX); dy = (m_scaleY - oldScaleY) * (m_startPos.y() - m_org_cenY); } } } if(m_function == RIGHTSCALE) { dx = (newX - m_scaleX * (m_endPos.x() - m_org_cenX)) / 2; m_scaleX = (newX - dx) / (m_endPos.x() - m_org_cenX); // enforce same acpect if shift button is pressed if(e->state() & TQt::ShiftButton) { if(m_scaleY>0) // handle the mirrored cases m_scaleY = fabs(m_scaleX); else m_scaleY = -fabs(m_scaleX); } } if(m_function == BOTTOMRIGHTSCALE) { dx = (newX - m_scaleX * (m_endPos.x() - m_org_cenX)) / 2; m_scaleX = (newX - dx) / (m_endPos.x() - m_org_cenX); dy = (newY - m_scaleY * (m_endPos.y() - m_org_cenY)) / 2; m_scaleY = (newY - dy) / (m_endPos.y() - m_org_cenY); // enforce same acpect if shift button is pressed if(e->state() & TQt::ShiftButton) { if(m_scaleX < m_scaleY) { if(m_scaleX>0) // handle the mirrored cases m_scaleX = fabs(m_scaleY); else m_scaleX = -fabs(m_scaleY); dx = (m_scaleX - oldScaleX) * (m_endPos.x() - m_org_cenX); } else { if(m_scaleY>0) // handle the mirrored cases m_scaleY = fabs(m_scaleX); else m_scaleY = -fabs(m_scaleX); dy = (m_scaleY - oldScaleY) * (m_endPos.y() - m_org_cenY); } } } if(m_function == BOTTOMSCALE) { dy = (newY - m_scaleY * (m_endPos.y() - m_org_cenY)) / 2; m_scaleY = (newY - dy) / (m_endPos.y() - m_org_cenY); // enforce same acpect if shift button is pressed if(e->state() & TQt::ShiftButton) { if(m_scaleX>0) // handle the mirrored cases m_scaleX = fabs(m_scaleY); else m_scaleX = -fabs(m_scaleY); } } if(m_function == BOTTOMLEFTSCALE) { dx = (newX - m_scaleX * (m_startPos.x() - m_org_cenX)) / 2; m_scaleX = (newX - dx) / (m_startPos.x() - m_org_cenX); dy = (newY - m_scaleY * (m_endPos.y() - m_org_cenY)) / 2; m_scaleY = (newY - dy) / (m_endPos.y() - m_org_cenY); // enforce same acpect if shift button is pressed if(e->state() & TQt::ShiftButton) { if(m_scaleX < m_scaleY) { if(m_scaleX>0) // handle the mirrored cases m_scaleX = fabs(m_scaleY); else m_scaleX = -fabs(m_scaleY); dx = (m_scaleX - oldScaleX) * (m_startPos.x() - m_org_cenX); } else { if(m_scaleY>0) // handle the mirrored cases m_scaleY = fabs(m_scaleX); else m_scaleY = -fabs(m_scaleX); dy = (m_scaleY - oldScaleY) * (m_endPos.y() - m_org_cenY); } } } if(m_function == LEFTSCALE) { dx = (newX - m_scaleX * (m_startPos.x() - m_org_cenX)) / 2; m_scaleX = (newX - dx) / (m_startPos.x() - m_org_cenX); // enforce same acpect if shift button is pressed if(e->state() & TQt::ShiftButton) { if(m_scaleY>0) // handle the mirrored cases m_scaleY = fabs(m_scaleX); else m_scaleY = -fabs(m_scaleX); } } if(m_function == TOPLEFTSCALE) { dx = (newX - m_scaleX * (m_startPos.x() - m_org_cenX)) / 2; m_scaleX = (newX - dx) / (m_startPos.x() - m_org_cenX); dy = (newY - m_scaleY * (m_startPos.y() - m_org_cenY)) / 2; m_scaleY = (newY - dy) / (m_startPos.y() - m_org_cenY); // enforce same acpect if shift button is pressed if(e->state() & TQt::ShiftButton) { if(m_scaleX < m_scaleY) { if(m_scaleX>0) // handle the mirrored cases m_scaleX = fabs(m_scaleY); else m_scaleX = -fabs(m_scaleY); dx = (m_scaleX - oldScaleX) * (m_startPos.x() - m_org_cenX); } else { if(m_scaleY>0) // handle the mirrored cases m_scaleY = fabs(m_scaleX); else m_scaleY = -fabs(m_scaleX); dy = (m_scaleY - oldScaleY) * (m_startPos.y() - m_org_cenY); } } } m_translateX += rotX(dx, dy); m_translateY += rotY(dx, dy); paintOutline(); } else { if(det(mousePos - topleft, topright - topleft)>0) m_function = ROTATE; else if(det(mousePos - topright, bottomright - topright)>0) m_function = ROTATE; else if(det(mousePos - bottomright, bottomleft - bottomright)>0) m_function = ROTATE; else if(det(mousePos - bottomleft, topleft - bottomleft)>0) m_function = ROTATE; else m_function = MOVE; int handleradius = int( 25 / (m_subject->zoomFactor() * m_subject->zoomFactor()) ); if(distsq(mousePos, (m_topleft + m_topright)/2)<=handleradius) m_function = TOPSCALE; if(distsq(mousePos, m_topright)<=handleradius) m_function = TOPRIGHTSCALE; if(distsq(mousePos, (m_topright + m_bottomright)/2)<=handleradius) m_function = RIGHTSCALE; if(distsq(mousePos, m_bottomright)<=handleradius) m_function = BOTTOMRIGHTSCALE; if(distsq(mousePos, (m_bottomleft + m_bottomright)/2)<=handleradius) m_function = BOTTOMSCALE; if(distsq(mousePos, m_bottomleft)<=handleradius) m_function = BOTTOMLEFTSCALE; if(distsq(mousePos, (m_topleft + m_bottomleft)/2)<=handleradius) m_function = LEFTSCALE; if(distsq(mousePos, m_topleft)<=handleradius) m_function = TOPLEFTSCALE; setFunctionalCursor(); } } } void KisToolTransform::buttonRelease(KisButtonReleaseEvent *e) { if (m_subject && e->button() == Qt::LeftButton) { if(!m_wasPressed) return; m_wasPressed = false; KisImageSP img = m_subject->currentImg(); if (!img) return; m_selecting = false; if(m_actualyMoveWhileSelected) { paintOutline(); TQApplication::setOverrideCursor(KisCursor::waitCursor()); transform(); TQApplication::restoreOverrideCursor(); } } } void KisToolTransform::paintOutline() { if (m_subject) { KisCanvasController *controller = m_subject->canvasController(); KisCanvas *canvas = controller->kiscanvas(); KisCanvasPainter gc(canvas); TQRect rc; paintOutline(gc, rc); } } void KisToolTransform::recalcOutline() { double x,y; m_sina = sin(m_a); m_cosa = cos(m_a); x = (m_startPos.x() - m_org_cenX) * m_scaleX; y = (m_startPos.y() - m_org_cenY) * m_scaleY; m_topleft = TQPoint(int(rotX(x,y) + m_translateX+0.5), int(rotY(x,y) + m_translateY+0.5)); x = (m_endPos.x() - m_org_cenX) * m_scaleX; y = (m_startPos.y() - m_org_cenY) * m_scaleY; m_topright = TQPoint(int(rotX(x,y) + m_translateX+0.5), int(rotY(x,y) + m_translateY+0.5)); x = (m_startPos.x() - m_org_cenX) * m_scaleX; y = (m_endPos.y() - m_org_cenY) * m_scaleY; m_bottomleft = TQPoint(int(rotX(x,y) + m_translateX+0.5), int(rotY(x,y) + m_translateY+0.5)); x = (m_endPos.x() - m_org_cenX) * m_scaleX; y = (m_endPos.y() - m_org_cenY) * m_scaleY; m_bottomright = TQPoint(int(rotX(x,y) + m_translateX+0.5), int(rotY(x,y) + m_translateY+0.5)); } void KisToolTransform::paintOutline(KisCanvasPainter& gc, const TQRect&) { if (m_subject) { KisCanvasController *controller = m_subject->canvasController(); RasterOp op = gc.rasterOp(); TQPen old = gc.pen(); TQPen pen(TQt::SolidLine); pen.setWidth(1); Q_ASSERT(controller); recalcOutline(); TQPoint topleft = controller->windowToView(m_topleft); TQPoint topright = controller->windowToView(m_topright); TQPoint bottomleft = controller->windowToView(m_bottomleft); TQPoint bottomright = controller->windowToView(m_bottomright); gc.setRasterOp(TQt::NotROP); gc.setPen(pen); gc.drawRect(topleft.x()-4, topleft.y()-4, 8, 8); gc.drawLine(topleft.x(), topleft.y(), (topleft.x()+topright.x())/2, (topleft.y()+topright.y())/2); gc.drawRect((topleft.x()+topright.x())/2-4, (topleft.y()+topright.y())/2-4, 8, 8); gc.drawLine((topleft.x()+topright.x())/2, (topleft.y()+topright.y())/2, topright.x(), topright.y()); gc.drawRect(topright.x()-4, topright.y()-4, 8, 8); gc.drawLine(topright.x(), topright.y(), (topright.x()+bottomright.x())/2, (topright.y()+bottomright.y())/2); gc.drawRect((topright.x()+bottomright.x())/2-4, (topright.y()+bottomright.y())/2-4, 8, 8); gc.drawLine((topright.x()+bottomright.x())/2, (topright.y()+bottomright.y())/2,bottomright.x(), bottomright.y()); gc.drawRect(bottomright.x()-4, bottomright.y()-4, 8, 8); gc.drawLine(bottomright.x(), bottomright.y(), (bottomleft.x()+bottomright.x())/2, (bottomleft.y()+bottomright.y())/2); gc.drawRect((bottomleft.x()+bottomright.x())/2-4, (bottomleft.y()+bottomright.y())/2-4, 8, 8); gc.drawLine((bottomleft.x()+bottomright.x())/2, (bottomleft.y()+bottomright.y())/2, bottomleft.x(), bottomleft.y()); gc.drawRect(bottomleft.x()-4, bottomleft.y()-4, 8, 8); gc.drawLine(bottomleft.x(), bottomleft.y(), (topleft.x()+bottomleft.x())/2, (topleft.y()+bottomleft.y())/2); gc.drawRect((topleft.x()+bottomleft.x())/2-4, (topleft.y()+bottomleft.y())/2-4, 8, 8); gc.drawLine((topleft.x()+bottomleft.x())/2, (topleft.y()+bottomleft.y())/2, topleft.x(), topleft.y()); gc.setRasterOp(op); gc.setPen(old); } } void KisToolTransform::transform() { KisImageSP img = m_subject->currentImg(); if (!img || !img->activeDevice()) return; double tx = m_translateX - rotX(m_org_cenX * m_scaleX, m_org_cenY * m_scaleY); double ty = m_translateY - rotY(m_org_cenX * m_scaleX, m_org_cenY * m_scaleY); KisProgressDisplayInterface *progress = m_subject->progressDisplay(); // This mementoes the current state of the active device. TransformCmd * transaction = new TransformCmd(this, img->activeDevice(), m_origDevice, m_scaleX, m_scaleY, m_translateX, m_translateY, m_a, m_origSelection, m_startPos, m_endPos); // Copy the original state back. TQRect rc = m_origDevice->extent(); rc = rc.normalize(); img->activeDevice()->clear(); KisPainter gc(img->activeDevice()); gc.bitBlt(rc.x(), rc.y(), COMPOSITE_COPY, m_origDevice, rc.x(), rc.y(), rc.width(), rc.height()); gc.end(); // Also restore the original selection. if(m_origSelection) { //TQRect rc = m_origSelection->extent(); TQRect rc = m_origSelection->selectedRect(); rc = rc.normalize(); img->activeDevice()->selection()->clear(); KisPainter sgc(img->activeDevice()->selection().data()); sgc.bitBlt(rc.x(), rc.y(), COMPOSITE_COPY, m_origSelection.data(), rc.x(), rc.y(), rc.width(), rc.height()); sgc.end(); } else if(img->activeDevice()->hasSelection()) img->activeDevice()->selection()->clear(); // Perform the transform. Since we copied the original state back, this doesn't degrade // after many tweaks. Since we started the transaction before the copy back, the memento // has the previous state. KisTransformWorker t(img->activeDevice(), m_scaleX, m_scaleY, 0, 0, m_a, int(tx), int(ty), progress, m_filter); t.run(); // If canceled, go back to the memento if(t.isCanceled()) { transaction->unexecute(); delete transaction; return; } img->activeDevice()->setDirty(rc); // XXX: This is not enough - should union with new extent // Else add the command -- this will have the memento from the previous state, // and the transformed state from the original device we cached in our activated() // method. if (transaction) { if (img->undo()) img->undoAdapter()->addCommand(transaction); else delete transaction; } } void KisToolTransform::notifyCommandAdded( KCommand * command) { TransformCmd * cmd = dynamic_cast(command); if (cmd == 0) { // The last added command wasn't one of ours; // we should reset to the new state of the canvas. // In effect we should treat this as if the tool has been just activated initHandles(); } } void KisToolTransform::notifyCommandExecuted( KCommand * command) { Q_UNUSED(command); TransformCmd * cmd=0; if(m_subject->currentImg()->undoAdapter()->presentCommand()) cmd = dynamic_cast(m_subject->currentImg()->undoAdapter()->presentCommand()); if (cmd == 0) { // The command now on the top of the stack isn't one of ours // We should treat this as if the tool has been just activated initHandles(); } else { // One of our commands is now on top // We should ask for tool args and orig selection cmd->transformArgs(m_scaleX, m_scaleY, m_translateX, m_translateY, m_a); m_origSelection = cmd->origSelection(m_startPos, m_endPos); m_origDevice = cmd->origDevice(); m_org_cenX = (m_startPos.x() + m_endPos.x()) / 2.0; m_org_cenY = (m_startPos.y() + m_endPos.y()) / 2.0; m_subject->canvasController() ->updateCanvas(); } } void KisToolTransform::slotSetFilter(const KisID &filterID) { m_filter = KisFilterStrategyRegistry::instance()->get(filterID); } void KisToolTransform::slotLayerActivated(KisLayerSP) { activate(); } TQWidget* KisToolTransform::createOptionWidget(TQWidget* parent) { m_optWidget = new WdgToolTransform(parent); TQ_CHECK_PTR(m_optWidget); m_optWidget->cmbFilter->clear(); m_optWidget->cmbFilter->setIDList(KisFilterStrategyRegistry::instance()->listKeys()); m_optWidget->cmbFilter->setCurrentText("Mitchell"); connect(m_optWidget->cmbFilter, TQT_SIGNAL(activated(const KisID &)), this, TQT_SLOT(slotSetFilter(const KisID &))); KisID filterID = m_optWidget->cmbFilter->currentItem(); m_filter = KisFilterStrategyRegistry::instance()->get(filterID); /* connect(m_optWidget->intStartX, TQT_SIGNAL(valueChanged(int)), this, TQT_SLOT(setStartX(int))); connect(m_optWidget->intStartY, TQT_SIGNAL(valueChanged(int)), this, TQT_SLOT(setStartY(int))); connect(m_optWidget->intEndX, TQT_SIGNAL(valueChanged(int)), this, TQT_SLOT(setEndX(int))); connect(m_optWidget->intEndY, TQT_SIGNAL(valueChanged(int)), this, TQT_SLOT(setEndY(int))); */ m_optWidget->intStartX->hide(); m_optWidget->intStartY->hide(); m_optWidget->intEndX->hide(); m_optWidget->intEndY->hide(); m_optWidget->textLabel1->hide(); m_optWidget->textLabel2->hide(); m_optWidget->textLabel3->hide(); m_optWidget->textLabel4->hide(); return m_optWidget; } TQWidget* KisToolTransform::optionWidget() { return m_optWidget; } void KisToolTransform::setup(TDEActionCollection *collection) { m_action = static_cast(collection->action(name())); if (m_action == 0) { m_action = new TDERadioAction(i18n("&Transform"), "tool_transform", 0, this, TQT_SLOT(activate()), collection, name()); TQ_CHECK_PTR(m_action); m_action->setToolTip(i18n("Transform a layer or a selection")); m_action->setExclusiveGroup("tools"); m_ownAction = true; } } #include "kis_tool_transform.moc"