You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
926 lines
31 KiB
926 lines
31 KiB
14 years ago
|
/*
|
||
|
* kis_tool_crop.cc -- part of Chalk
|
||
|
*
|
||
|
* Copyright (c) 2004 Boudewijn Rempt <boud@valdyas.org>
|
||
|
* Copyright (c) 2005 Michael Thaler <michael.thaler@physik.tu-muenchen.de>
|
||
|
* Copyright (c) 2006 Cyrille Berger <cberger@cberger.net>
|
||
|
*
|
||
|
* 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 <tqcheckbox.h>
|
||
|
#include <tqcombobox.h>
|
||
|
#include <tqobject.h>
|
||
|
#include <tqpainter.h>
|
||
|
#include <tqpen.h>
|
||
|
#include <tqpushbutton.h>
|
||
|
#include <tqrect.h>
|
||
|
|
||
|
#include <kdebug.h>
|
||
|
#include <kaction.h>
|
||
|
#include <kcommand.h>
|
||
|
#include <klocale.h>
|
||
|
#include <knuminput.h>
|
||
|
#include <kdebug.h>
|
||
|
|
||
|
#include <kis_global.h>
|
||
|
#include <kis_painter.h>
|
||
|
#include <kis_canvas_controller.h>
|
||
|
#include <kis_canvas_subject.h>
|
||
|
#include <kis_cursor.h>
|
||
|
#include <kis_image.h>
|
||
|
#include <kis_undo_adapter.h>
|
||
|
#include <kis_button_press_event.h>
|
||
|
#include <kis_button_release_event.h>
|
||
|
#include <kis_move_event.h>
|
||
|
#include <kis_selected_transaction.h>
|
||
|
#include <kis_selection.h>
|
||
|
#include <kis_layer.h>
|
||
|
#include <kis_crop_visitor.h>
|
||
|
|
||
|
#include "kis_tool_crop.h"
|
||
|
#include "wdg_tool_crop.h"
|
||
|
|
||
|
#include "kis_canvas.h"
|
||
|
#include "kis_canvas_painter.h"
|
||
|
|
||
|
|
||
|
|
||
|
KisToolCrop::KisToolCrop()
|
||
|
: super(i18n("Crop"))
|
||
|
{
|
||
|
setName("tool_crop");
|
||
|
m_cropCursor = KisCursor::load("tool_crop_cursor.png", 6, 6);
|
||
|
setCursor(m_cropCursor);
|
||
|
m_subject = 0;
|
||
|
m_selecting = false;
|
||
|
m_rectCrop = TQRect(0, 0, 0, 0);
|
||
|
m_handleSize = 13;
|
||
|
m_haveCropSelection = false;
|
||
|
m_optWidget = 0;
|
||
|
}
|
||
|
|
||
|
KisToolCrop::~KisToolCrop()
|
||
|
{
|
||
|
}
|
||
|
|
||
|
void KisToolCrop::update(KisCanvasSubject *subject)
|
||
|
{
|
||
|
m_subject = subject;
|
||
|
super::update(m_subject);
|
||
|
}
|
||
|
|
||
|
void KisToolCrop::activate()
|
||
|
{
|
||
|
super::activate();
|
||
|
|
||
|
// No current crop rectangle, try to use the selection of the device to make a rectangle
|
||
|
if (m_subject && m_subject->currentImg() && m_subject->currentImg()->activeDevice()) {
|
||
|
KisPaintDeviceSP device = m_subject->currentImg()->activeDevice();
|
||
|
if (!device->hasSelection()) {
|
||
|
//m_rectCrop = m_subject->currentImg()->bounds();
|
||
|
//validateSelection();
|
||
|
m_haveCropSelection = false;
|
||
|
m_selecting = false;
|
||
|
}
|
||
|
else {
|
||
|
|
||
|
m_rectCrop = device->selection()->selectedRect();
|
||
|
validateSelection();
|
||
|
crop();
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void KisToolCrop::deactivate()
|
||
|
{
|
||
|
clearRect();
|
||
|
}
|
||
|
|
||
|
|
||
|
void KisToolCrop::paint(KisCanvasPainter& gc)
|
||
|
{
|
||
|
paintOutlineWithHandles(gc, TQRect());
|
||
|
}
|
||
|
|
||
|
void KisToolCrop::paint(KisCanvasPainter& gc, const TQRect& rc)
|
||
|
{
|
||
|
paintOutlineWithHandles(gc, rc);
|
||
|
}
|
||
|
|
||
|
void KisToolCrop::clearRect()
|
||
|
{
|
||
|
kdDebug() << "Clearing\n";
|
||
|
if (m_subject) {
|
||
|
|
||
|
KisCanvasController *controller = m_subject->canvasController();
|
||
|
KisImageSP img = m_subject->currentImg();
|
||
|
|
||
|
Q_ASSERT(controller);
|
||
|
|
||
|
controller->kiscanvas()->update();
|
||
|
|
||
|
m_rectCrop = TQRect(0,0,0,0);
|
||
|
|
||
|
updateWidgetValues();
|
||
|
m_selecting = false;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void KisToolCrop::buttonPress(KisButtonPressEvent *e)
|
||
|
{
|
||
|
if (m_subject) {
|
||
|
KisImageSP img = m_subject->currentImg();
|
||
|
|
||
|
if (img && img->activeDevice() && e->button() == Qt::LeftButton) {
|
||
|
|
||
|
TQPoint pos = e->pos().floorTQPoint();
|
||
|
TQRect b = img->bounds();
|
||
|
|
||
|
if (pos.x() < b.x())
|
||
|
pos.setX(b.x());
|
||
|
else if (pos.x() > b.x() + b.width())
|
||
|
pos.setX(b.x() + b.width());
|
||
|
|
||
|
if (pos.y() < b.y())
|
||
|
pos.setY(b.y());
|
||
|
else if (pos.y() > b.y() + b.height())
|
||
|
pos.setY(b.y() + b.height());
|
||
|
|
||
|
m_selecting = true;
|
||
|
|
||
|
if( !m_haveCropSelection ) //if the selection is not set
|
||
|
{
|
||
|
m_rectCrop = TQRect( pos.x(), pos.y(), 0, 0);
|
||
|
paintOutlineWithHandles();
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
KisCanvasController *controller = m_subject->canvasController();
|
||
|
m_mouseOnHandleType = mouseOnHandle(controller ->windowToView(pos));
|
||
|
m_dragStart = pos;
|
||
|
}
|
||
|
|
||
|
updateWidgetValues();
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void KisToolCrop::move(KisMoveEvent *e)
|
||
|
{
|
||
|
if ( m_subject && m_subject->currentImg())
|
||
|
{
|
||
|
if( m_selecting ) //if the user selects
|
||
|
{
|
||
|
if( !m_haveCropSelection ) //if the cropSelection is not yet set
|
||
|
{
|
||
|
paintOutlineWithHandles();
|
||
|
|
||
|
m_rectCrop.setBottomRight( e->pos().floorTQPoint());
|
||
|
|
||
|
KisImageSP image = m_subject->currentImg();
|
||
|
|
||
|
m_rectCrop.setRight( TQMIN(m_rectCrop.right(), image->width()));
|
||
|
m_rectCrop.setBottom( TQMIN(m_rectCrop.bottom(), image->width()));
|
||
|
m_rectCrop = m_rectCrop.normalize();
|
||
|
|
||
|
paintOutlineWithHandles();
|
||
|
}
|
||
|
else //if the crop selection is set
|
||
|
{
|
||
|
m_dragStop = e->pos().floorTQPoint();
|
||
|
if (m_mouseOnHandleType != None && m_dragStart != m_dragStop ) {
|
||
|
|
||
|
|
||
|
TQ_INT32 imageWidth = m_subject->currentImg()->width();
|
||
|
TQ_INT32 imageHeight = m_subject->currentImg()->height();
|
||
|
|
||
|
paintOutlineWithHandles();
|
||
|
|
||
|
TQPoint pos = e->pos().floorTQPoint();
|
||
|
if( m_mouseOnHandleType == Inside )
|
||
|
{
|
||
|
m_rectCrop.moveBy( ( m_dragStop.x() - m_dragStart.x() ), ( m_dragStop.y() - m_dragStart.y() ) );
|
||
|
if( m_rectCrop.left() < 0 )
|
||
|
{
|
||
|
m_rectCrop.moveLeft( 0 );
|
||
|
}
|
||
|
if( m_rectCrop.right() > imageWidth )
|
||
|
{
|
||
|
m_rectCrop.moveRight( imageWidth );
|
||
|
}
|
||
|
if( m_rectCrop.top() < 0 )
|
||
|
{
|
||
|
m_rectCrop.moveTop( 0 );
|
||
|
}
|
||
|
if( m_rectCrop.bottom() > imageHeight )
|
||
|
{
|
||
|
m_rectCrop.moveBottom( imageHeight );
|
||
|
}
|
||
|
} else if(m_optWidget->boolRatio->isChecked())
|
||
|
{
|
||
|
TQPoint drag = m_dragStop - m_dragStart;
|
||
|
if( ! m_optWidget->boolWidth->isChecked() && !m_optWidget->boolHeight->isChecked() )
|
||
|
{
|
||
|
switch (m_mouseOnHandleType)
|
||
|
{
|
||
|
case (UpperLeft):
|
||
|
{
|
||
|
TQ_INT32 dep = (drag.x() + drag.y()) / 2;
|
||
|
m_rectCrop.setTop( m_rectCrop.top() + dep );
|
||
|
m_rectCrop.setLeft( (int) ( m_rectCrop.right() - m_optWidget->doubleRatio->value() * m_rectCrop.height() ) );
|
||
|
}
|
||
|
break;
|
||
|
case (LowerRight):
|
||
|
{
|
||
|
TQ_INT32 dep = (drag.x() + drag.y()) / 2;
|
||
|
m_rectCrop.setBottom( m_rectCrop.bottom() + dep );
|
||
|
m_rectCrop.setWidth( (int) ( m_optWidget->doubleRatio->value() * m_rectCrop.height() ) );
|
||
|
break;
|
||
|
}
|
||
|
case (UpperRight):
|
||
|
{
|
||
|
TQ_INT32 dep = (drag.x() - drag.y()) / 2;
|
||
|
m_rectCrop.setTop( m_rectCrop.top() - dep );
|
||
|
m_rectCrop.setWidth( (int) ( m_optWidget->doubleRatio->value() * m_rectCrop.height() ) );
|
||
|
break;
|
||
|
}
|
||
|
case (LowerLeft):
|
||
|
{
|
||
|
TQ_INT32 dep = (drag.x() - drag.y()) / 2;
|
||
|
m_rectCrop.setBottom( m_rectCrop.bottom() - dep );
|
||
|
m_rectCrop.setLeft( (int) ( m_rectCrop.right() - m_optWidget->doubleRatio->value() * m_rectCrop.height() ) );
|
||
|
break;
|
||
|
}
|
||
|
case (Upper):
|
||
|
m_rectCrop.setTop( pos.y() + m_dy );
|
||
|
m_rectCrop.setWidth( (int) (m_rectCrop.height() * m_optWidget->doubleRatio->value()) );
|
||
|
break;
|
||
|
case (Lower):
|
||
|
m_rectCrop.setBottom( pos.y() + m_dy );
|
||
|
m_rectCrop.setWidth( (int) (m_rectCrop.height() * m_optWidget->doubleRatio->value()) );
|
||
|
break;
|
||
|
case (Left):
|
||
|
m_rectCrop.setLeft( pos.x() + m_dx );
|
||
|
m_rectCrop.setHeight( (int) (m_rectCrop.width() / m_optWidget->doubleRatio->value()) );
|
||
|
break;
|
||
|
case (Right):
|
||
|
m_rectCrop.setRight( pos.x() + m_dx );
|
||
|
m_rectCrop.setHeight( (int) (m_rectCrop.width() / m_optWidget->doubleRatio->value()) );
|
||
|
break;
|
||
|
case (Inside): // never happen
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
} else {
|
||
|
if( m_optWidget->boolWidth->isChecked() )
|
||
|
{
|
||
|
m_rectCrop.setWidth( m_optWidget->intWidth->value() + 1 );
|
||
|
} else {
|
||
|
switch (m_mouseOnHandleType)
|
||
|
{
|
||
|
case (LowerLeft):
|
||
|
case (Left):
|
||
|
case (UpperLeft):
|
||
|
m_rectCrop.setLeft( pos.x() + m_dx );
|
||
|
break;
|
||
|
case (Right):
|
||
|
case (UpperRight):
|
||
|
case (LowerRight):
|
||
|
m_rectCrop.setRight( pos.x() + m_dx );
|
||
|
break;
|
||
|
default:
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
if( m_optWidget->boolHeight->isChecked() )
|
||
|
{
|
||
|
m_rectCrop.setHeight( m_optWidget->intHeight->value() + 1 );
|
||
|
} else {
|
||
|
switch (m_mouseOnHandleType)
|
||
|
{
|
||
|
case (UpperLeft):
|
||
|
case (Upper):
|
||
|
case (UpperRight):
|
||
|
m_rectCrop.setTop( pos.y() + m_dy );
|
||
|
break;
|
||
|
case (LowerRight):
|
||
|
case (LowerLeft):
|
||
|
case (Lower):
|
||
|
m_rectCrop.setBottom( pos.y() + m_dy );
|
||
|
break;
|
||
|
default:
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
if( m_rectCrop.height() < 0)
|
||
|
{
|
||
|
if( m_mouseOnHandleType == Lower)
|
||
|
m_mouseOnHandleType = Upper;
|
||
|
else if( m_mouseOnHandleType == LowerLeft)
|
||
|
m_mouseOnHandleType = UpperLeft;
|
||
|
else if( m_mouseOnHandleType == LowerRight)
|
||
|
m_mouseOnHandleType = UpperRight;
|
||
|
else if( m_mouseOnHandleType == Upper)
|
||
|
m_mouseOnHandleType = Lower;
|
||
|
else if( m_mouseOnHandleType == UpperLeft)
|
||
|
m_mouseOnHandleType = LowerLeft;
|
||
|
else if( m_mouseOnHandleType == UpperRight)
|
||
|
m_mouseOnHandleType = LowerRight;
|
||
|
}
|
||
|
if( m_rectCrop.width() < 0)
|
||
|
{
|
||
|
if( m_mouseOnHandleType == Right)
|
||
|
m_mouseOnHandleType = Left;
|
||
|
else if( m_mouseOnHandleType == UpperRight)
|
||
|
m_mouseOnHandleType = UpperLeft;
|
||
|
else if( m_mouseOnHandleType == LowerRight)
|
||
|
m_mouseOnHandleType = LowerLeft;
|
||
|
else if( m_mouseOnHandleType == Left)
|
||
|
m_mouseOnHandleType = Right;
|
||
|
else if( m_mouseOnHandleType == UpperLeft)
|
||
|
m_mouseOnHandleType = UpperRight;
|
||
|
else if( m_mouseOnHandleType == LowerLeft)
|
||
|
m_mouseOnHandleType = LowerRight;
|
||
|
}
|
||
|
|
||
|
m_rectCrop = m_rectCrop.normalize();
|
||
|
m_rectCrop = m_rectCrop.intersect( TQRect(0,0, imageWidth + 1, imageHeight + 1 ) );
|
||
|
m_dragStart = e->pos().floorTQPoint();
|
||
|
paintOutlineWithHandles();
|
||
|
}
|
||
|
}
|
||
|
updateWidgetValues();
|
||
|
}
|
||
|
else //if we are not selecting
|
||
|
{
|
||
|
if ( m_haveCropSelection ) //if the crop selection is set
|
||
|
{
|
||
|
KisCanvasController *controller = m_subject->canvasController();
|
||
|
TQ_INT32 type = mouseOnHandle(controller->windowToView(e->pos().floorTQPoint()));
|
||
|
//set resize cursor if we are on one of the handles
|
||
|
setMoveResizeCursor(type);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void KisToolCrop::updateWidgetValues(bool updateratio)
|
||
|
{
|
||
|
TQRect r = realRectCrop();
|
||
|
setOptionWidgetX(r.x());
|
||
|
setOptionWidgetY(r.y());
|
||
|
setOptionWidgetWidth(r.width() );
|
||
|
setOptionWidgetHeight(r.height() );
|
||
|
if(updateratio && !m_optWidget->boolRatio->isChecked() )
|
||
|
setOptionWidgetRatio((double)r.width() / (double)r.height() );
|
||
|
}
|
||
|
|
||
|
void KisToolCrop::buttonRelease(KisButtonReleaseEvent *e)
|
||
|
{
|
||
|
if (m_subject && m_subject->currentImg() && m_selecting && e->button() == Qt::LeftButton) {
|
||
|
|
||
|
m_selecting = false;
|
||
|
m_haveCropSelection = true;
|
||
|
|
||
|
paintOutlineWithHandles();
|
||
|
validateSelection();
|
||
|
paintOutlineWithHandles();
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void KisToolCrop::doubleClick(KisDoubleClickEvent *)
|
||
|
{
|
||
|
if (m_haveCropSelection) crop();
|
||
|
}
|
||
|
|
||
|
void KisToolCrop::validateSelection(bool updateratio)
|
||
|
{
|
||
|
if (m_subject) {
|
||
|
KisImageSP image = m_subject->currentImg();
|
||
|
|
||
|
if (image) {
|
||
|
TQ_INT32 imageWidth = image->width();
|
||
|
TQ_INT32 imageHeight = image->height();
|
||
|
m_rectCrop.setLeft(TQMAX(0, m_rectCrop.left()));
|
||
|
m_rectCrop.setTop(TQMAX(0, m_rectCrop.top()));
|
||
|
m_rectCrop.setRight(TQMIN(imageWidth, m_rectCrop.right()));
|
||
|
m_rectCrop.setBottom(TQMIN(imageHeight, m_rectCrop.bottom()));
|
||
|
|
||
|
updateWidgetValues(updateratio);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void KisToolCrop::paintOutlineWithHandles()
|
||
|
{
|
||
|
if (m_subject) {
|
||
|
KisCanvasController *controller = m_subject->canvasController();
|
||
|
KisCanvas *canvas = controller->kiscanvas();
|
||
|
KisCanvasPainter gc(canvas);
|
||
|
TQRect rc;
|
||
|
|
||
|
paintOutlineWithHandles(gc, rc);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void KisToolCrop::paintOutlineWithHandles(KisCanvasPainter& gc, const TQRect&)
|
||
|
{
|
||
|
if (m_subject && (m_selecting || m_haveCropSelection)) {
|
||
|
KisCanvasController *controller = m_subject->canvasController();
|
||
|
RasterOp op = gc.rasterOp();
|
||
|
TQPen old = gc.pen();
|
||
|
TQPen pen(TQt::SolidLine);
|
||
|
pen.setWidth(1);
|
||
|
TQPoint start;
|
||
|
TQPoint end;
|
||
|
|
||
|
Q_ASSERT(controller);
|
||
|
start = controller->windowToView(m_rectCrop.topLeft());
|
||
|
end = controller->windowToView(m_rectCrop.bottomRight());
|
||
|
|
||
|
gc.setRasterOp(TQt::NotROP);
|
||
|
gc.setPen(pen);
|
||
|
//draw handles
|
||
|
m_handlesRegion = handles(TQRect(start, end));
|
||
|
|
||
|
TQ_INT32 startx;
|
||
|
TQ_INT32 starty;
|
||
|
TQ_INT32 endx;
|
||
|
TQ_INT32 endy;
|
||
|
if(start.x()<=end.x())
|
||
|
{
|
||
|
startx=start.x();
|
||
|
endx=end.x();
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
startx=end.x();
|
||
|
endx=start.x();
|
||
|
}
|
||
|
if(start.y()<=end.y())
|
||
|
{
|
||
|
starty=start.y();
|
||
|
endy=end.y();
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
starty=end.y();
|
||
|
endy=start.y();
|
||
|
}
|
||
|
//draw upper line of selection
|
||
|
gc.drawLine(startx + m_handleSize / 2 + 1, starty, startx + (endx - startx - m_handleSize) / 2 + 1, starty);
|
||
|
gc.drawLine(startx + (endx - startx + m_handleSize) / 2 + 1, starty, endx - m_handleSize / 2, starty);
|
||
|
//draw lower line of selection
|
||
|
gc.drawLine(startx + m_handleSize / 2 + 1, endy, startx + (endx - startx - m_handleSize) / 2 + 1, endy);
|
||
|
gc.drawLine(startx + (endx - startx + m_handleSize) / 2 + 1, endy, endx - m_handleSize / 2 , endy);
|
||
|
//draw right line of selection
|
||
|
gc.drawLine(startx, starty + m_handleSize / 2 + 1, startx, starty + (endy - starty - m_handleSize) / 2 + 1);
|
||
|
gc.drawLine(startx, starty + (endy - starty + m_handleSize) / 2 + 1, startx, endy - m_handleSize / 2);
|
||
|
//draw left line of selection
|
||
|
gc.drawLine(endx, starty + m_handleSize / 2 + 1, endx, starty + (endy - starty - m_handleSize) / 2 + 1);
|
||
|
gc.drawLine(endx, starty + (endy - starty + m_handleSize) / 2 + 1, endx, endy - m_handleSize / 2);
|
||
|
|
||
|
//draw guides
|
||
|
gc.drawLine(0,endy,startx - m_handleSize / 2,endy);
|
||
|
gc.drawLine(startx,endy + m_handleSize / 2 + 1, startx, controller->kiscanvas()->height());
|
||
|
gc.drawLine(endx,0,endx,starty - m_handleSize / 2);
|
||
|
gc.drawLine(endx + m_handleSize / 2 + 1,starty, controller->kiscanvas()->width(), starty);
|
||
|
TQMemArray <TQRect> rects = m_handlesRegion.tqrects ();
|
||
|
for (TQMemArray <TQRect>::ConstIterator it = rects.begin (); it != rects.end (); ++it)
|
||
|
{
|
||
|
gc.fillRect (*it, TQt::black);
|
||
|
}
|
||
|
|
||
|
|
||
|
gc.setRasterOp(op);
|
||
|
gc.setPen(old);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void KisToolCrop::crop() {
|
||
|
// XXX: Should cropping be part of KisImage/KisPaintDevice's API?
|
||
|
|
||
|
m_haveCropSelection = false;
|
||
|
setCursor(m_cropCursor);
|
||
|
|
||
|
KisImageSP img = m_subject->currentImg();
|
||
|
|
||
|
if (!img)
|
||
|
return;
|
||
|
|
||
|
TQRect rc = realRectCrop().normalize();
|
||
|
|
||
|
// The visitor adds the undo steps to the macro
|
||
|
if (m_optWidget->cmbType->currentItem() == 0) {
|
||
|
|
||
|
TQRect dirty = img->bounds();
|
||
|
|
||
|
// The layer(s) under the current layer will take care of adding
|
||
|
// undo information to the Crop macro.
|
||
|
if (img->undo())
|
||
|
img->undoAdapter()->beginMacro(i18n("Crop"));
|
||
|
|
||
|
KisCropVisitor v(rc, false);
|
||
|
KisLayerSP layer = img->activeLayer();
|
||
|
layer->accept(v);
|
||
|
layer->setDirty( dirty );
|
||
|
if (img->undo())
|
||
|
img->undoAdapter()->endMacro();
|
||
|
|
||
|
}
|
||
|
else {
|
||
|
// Resize creates the undo macro itself
|
||
|
img->resize(rc, true);
|
||
|
}
|
||
|
|
||
|
m_rectCrop = TQRect(0,0,0,0);
|
||
|
|
||
|
updateWidgetValues();
|
||
|
}
|
||
|
|
||
|
void KisToolCrop::setCropX(int x)
|
||
|
{
|
||
|
if (!m_haveCropSelection) {
|
||
|
m_haveCropSelection = true;
|
||
|
}
|
||
|
else {
|
||
|
paintOutlineWithHandles(); // remove outlines
|
||
|
}
|
||
|
|
||
|
m_rectCrop.setX(x);
|
||
|
|
||
|
validateSelection();
|
||
|
paintOutlineWithHandles();
|
||
|
}
|
||
|
|
||
|
void KisToolCrop::setCropY(int y)
|
||
|
{
|
||
|
if (!m_haveCropSelection) {
|
||
|
m_haveCropSelection = true;
|
||
|
}
|
||
|
else {
|
||
|
paintOutlineWithHandles(); // remove outlines
|
||
|
}
|
||
|
|
||
|
m_rectCrop.setY(y);
|
||
|
|
||
|
validateSelection();
|
||
|
paintOutlineWithHandles();
|
||
|
|
||
|
}
|
||
|
|
||
|
void KisToolCrop::setCropWidth(int w)
|
||
|
{
|
||
|
if (!m_haveCropSelection) {
|
||
|
m_haveCropSelection = true;
|
||
|
}
|
||
|
else {
|
||
|
paintOutlineWithHandles(); // remove outlines
|
||
|
}
|
||
|
|
||
|
m_rectCrop.setWidth(w + 1);
|
||
|
|
||
|
if( m_optWidget->boolRatio->isChecked() )
|
||
|
{
|
||
|
m_rectCrop.setHeight( (int) ( w / m_optWidget->doubleRatio->value() ) );
|
||
|
} else {
|
||
|
setOptionWidgetRatio((double)m_rectCrop.width() / (double)m_rectCrop.height() );
|
||
|
}
|
||
|
|
||
|
validateSelection();
|
||
|
paintOutlineWithHandles();
|
||
|
|
||
|
}
|
||
|
|
||
|
void KisToolCrop::setCropHeight(int h)
|
||
|
{
|
||
|
if (!m_haveCropSelection) {
|
||
|
m_haveCropSelection = true;
|
||
|
}
|
||
|
else {
|
||
|
paintOutlineWithHandles(); // remove outlines
|
||
|
}
|
||
|
|
||
|
m_rectCrop.setHeight(h + 1);
|
||
|
|
||
|
if( m_optWidget->boolRatio->isChecked() )
|
||
|
{
|
||
|
m_rectCrop.setWidth( (int) ( h * m_optWidget->doubleRatio->value() ) );
|
||
|
} else {
|
||
|
setOptionWidgetRatio((double)m_rectCrop.width() / (double)m_rectCrop.height() );
|
||
|
}
|
||
|
|
||
|
validateSelection();
|
||
|
paintOutlineWithHandles();
|
||
|
|
||
|
}
|
||
|
|
||
|
void KisToolCrop::setRatio(double )
|
||
|
{
|
||
|
if( ! (m_optWidget->boolWidth->isChecked() && m_optWidget->boolHeight->isChecked() ))
|
||
|
{
|
||
|
if (!m_haveCropSelection) {
|
||
|
m_haveCropSelection = true;
|
||
|
}
|
||
|
else {
|
||
|
paintOutlineWithHandles(); // remove outlines
|
||
|
}
|
||
|
if( m_optWidget->boolWidth->isChecked() )
|
||
|
{
|
||
|
m_rectCrop.setHeight( (int) ( m_rectCrop.width() / m_optWidget->doubleRatio->value()) );
|
||
|
setOptionWidgetHeight( m_rectCrop.height() );
|
||
|
} else if(m_optWidget->boolHeight->isChecked()) {
|
||
|
m_rectCrop.setWidth( (int) (m_rectCrop.height() * m_optWidget->doubleRatio->value()) );
|
||
|
setOptionWidgetWidth( m_rectCrop.width() );
|
||
|
} else {
|
||
|
int newwidth = (int) (m_optWidget->doubleRatio->value() * m_rectCrop.height());
|
||
|
newwidth = (newwidth + m_rectCrop.width()) / 2;
|
||
|
m_rectCrop.setWidth( newwidth + 1);
|
||
|
setOptionWidgetWidth( newwidth );
|
||
|
m_rectCrop.setHeight( (int) (newwidth / m_optWidget->doubleRatio->value()) + 1 );
|
||
|
setOptionWidgetHeight( m_rectCrop.height() - 1 );
|
||
|
}
|
||
|
validateSelection(false);
|
||
|
paintOutlineWithHandles();
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void KisToolCrop::setOptionWidgetX(TQ_INT32 x)
|
||
|
{
|
||
|
// Disable signals otherwise we get the valueChanged signal, which we don't want
|
||
|
// to go through the logic for setting values that way.
|
||
|
m_optWidget->intX->blockSignals(true);
|
||
|
m_optWidget->intX->setValue(x);
|
||
|
m_optWidget->intX->blockSignals(false);
|
||
|
}
|
||
|
|
||
|
void KisToolCrop::setOptionWidgetY(TQ_INT32 y)
|
||
|
{
|
||
|
m_optWidget->intY->blockSignals(true);
|
||
|
m_optWidget->intY->setValue(y);
|
||
|
m_optWidget->intY->blockSignals(false);
|
||
|
}
|
||
|
|
||
|
void KisToolCrop::setOptionWidgetWidth(TQ_INT32 x)
|
||
|
{
|
||
|
m_optWidget->intWidth->blockSignals(true);
|
||
|
m_optWidget->intWidth->setValue(x);
|
||
|
m_optWidget->intWidth->blockSignals(false);
|
||
|
}
|
||
|
|
||
|
void KisToolCrop::setOptionWidgetHeight(TQ_INT32 y)
|
||
|
{
|
||
|
m_optWidget->intHeight->blockSignals(true);
|
||
|
m_optWidget->intHeight->setValue(y);
|
||
|
m_optWidget->intHeight->blockSignals(false);
|
||
|
}
|
||
|
|
||
|
void KisToolCrop::setOptionWidgetRatio(double ratio)
|
||
|
{
|
||
|
m_optWidget->doubleRatio->blockSignals(true);
|
||
|
m_optWidget->doubleRatio->setValue(ratio);
|
||
|
m_optWidget->doubleRatio->blockSignals(false);
|
||
|
}
|
||
|
|
||
|
|
||
|
TQWidget* KisToolCrop::createOptionWidget(TQWidget* tqparent)
|
||
|
{
|
||
|
m_optWidget = new WdgToolCrop(tqparent);
|
||
|
Q_CHECK_PTR(m_optWidget);
|
||
|
|
||
|
connect(m_optWidget->bnCrop, TQT_SIGNAL(clicked()), this, TQT_SLOT(crop()));
|
||
|
|
||
|
connect(m_optWidget->intX, TQT_SIGNAL(valueChanged(int)), this, TQT_SLOT(setCropX(int)));
|
||
|
connect(m_optWidget->intY, TQT_SIGNAL(valueChanged(int)), this, TQT_SLOT(setCropY(int)));
|
||
|
connect(m_optWidget->intWidth, TQT_SIGNAL(valueChanged(int)), this, TQT_SLOT(setCropWidth(int)));
|
||
|
connect(m_optWidget->intHeight, TQT_SIGNAL(valueChanged(int)), this, TQT_SLOT(setCropHeight(int)));
|
||
|
connect(m_optWidget->doubleRatio, TQT_SIGNAL(valueChanged(double)), this, TQT_SLOT(setRatio( double )));
|
||
|
|
||
|
return m_optWidget;
|
||
|
}
|
||
|
|
||
|
TQWidget* KisToolCrop::optionWidget()
|
||
|
{
|
||
|
return m_optWidget;
|
||
|
}
|
||
|
|
||
|
void KisToolCrop::setup(KActionCollection *collection)
|
||
|
{
|
||
|
m_action = static_cast<KRadioAction *>(collection->action(name()));
|
||
|
|
||
|
if (m_action == 0) {
|
||
|
m_action = new KRadioAction(i18n("&Crop"),
|
||
|
"tool_crop",
|
||
|
0,
|
||
|
this,
|
||
|
TQT_SLOT(activate()),
|
||
|
collection,
|
||
|
name());
|
||
|
Q_CHECK_PTR(m_action);
|
||
|
|
||
|
m_action->setToolTip(i18n("Crop an area"));
|
||
|
m_action->setExclusiveGroup("tools");
|
||
|
|
||
|
m_ownAction = true;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
TQRect toTQRect(double x, double y, int w, int h)
|
||
|
{
|
||
|
return TQRect(int(x), int(y), w, h);
|
||
|
}
|
||
|
|
||
|
TQRegion KisToolCrop::handles(TQRect rect)
|
||
|
{
|
||
|
TQRegion handlesRegion;
|
||
|
|
||
|
//add handle at the lower right corner
|
||
|
handlesRegion += toTQRect( TQABS( rect.width() ) - m_handleSize / 2.0, TQABS( rect.height() ) - m_handleSize / 2.0, m_handleSize, m_handleSize );
|
||
|
//add handle at the upper right corner
|
||
|
handlesRegion += toTQRect( TQABS( rect.width() ) - m_handleSize / 2.0 , 0 - m_handleSize / 2.0, m_handleSize, m_handleSize );
|
||
|
//add rectangle at the lower left corner
|
||
|
handlesRegion += toTQRect( 0 - m_handleSize / 2.0 , TQABS( rect.height() ) - m_handleSize / 2.0, m_handleSize, m_handleSize );
|
||
|
//add rectangle at the upper left corner
|
||
|
handlesRegion += toTQRect( 0 - m_handleSize / 2.0, 0 - m_handleSize / 2.0, m_handleSize, m_handleSize );
|
||
|
//add handle at the lower edge of the rectangle
|
||
|
handlesRegion += toTQRect( ( TQABS( rect.width() ) - m_handleSize ) / 2.0 , TQABS( rect.height() ) - m_handleSize / 2.0, m_handleSize, m_handleSize );
|
||
|
//add handle at the right edge of the rectangle
|
||
|
handlesRegion += toTQRect( TQABS( rect.width() ) - m_handleSize / 2.0 , ( TQABS( rect.height() ) - m_handleSize ) / 2.0, m_handleSize, m_handleSize );
|
||
|
//add handle at the upper edge of the rectangle
|
||
|
handlesRegion += toTQRect( ( TQABS( rect.width() ) - m_handleSize ) / 2.0 , 0 - m_handleSize / 2.0, m_handleSize, m_handleSize );
|
||
|
//add handle at the left edge of the rectangle
|
||
|
handlesRegion += toTQRect( 0 - m_handleSize / 2.0, ( TQABS( rect.height() ) - m_handleSize ) / 2.0, m_handleSize, m_handleSize );
|
||
|
|
||
|
//move the handles to the correct position
|
||
|
if( rect.width() >= 0 && rect.height() >= 0)
|
||
|
{
|
||
|
handlesRegion.translate ( rect.x(), rect.y() );
|
||
|
}
|
||
|
else if( rect.width() < 0 && rect.height() >= 0)
|
||
|
{
|
||
|
handlesRegion.translate ( rect.x() - TQABS( rect.width() ), rect.y() );
|
||
|
}
|
||
|
else if( rect.width() >= 0 && rect.height() < 0)
|
||
|
{
|
||
|
handlesRegion.translate ( rect.x(), rect.y() - TQABS( rect.height() ) );
|
||
|
}
|
||
|
else if( rect.width() < 0 && rect.height() < 0)
|
||
|
{
|
||
|
handlesRegion.translate ( rect.x() - TQABS( rect.width() ), rect.y() - TQABS( rect.height() ) );
|
||
|
}
|
||
|
return handlesRegion;
|
||
|
}
|
||
|
|
||
|
TQ_INT32 KisToolCrop::mouseOnHandle(TQPoint currentViewPoint)
|
||
|
{
|
||
|
KisCanvasController *controller = m_subject->canvasController();
|
||
|
Q_ASSERT(controller);
|
||
|
TQPoint start = controller->windowToView(m_rectCrop.topLeft());
|
||
|
TQPoint end = controller->windowToView(m_rectCrop.bottomRight());
|
||
|
|
||
|
TQ_INT32 startx;
|
||
|
TQ_INT32 starty;
|
||
|
TQ_INT32 endx;
|
||
|
TQ_INT32 endy;
|
||
|
if(start.x()<=end.x())
|
||
|
{
|
||
|
startx=start.x();
|
||
|
endx=end.x();
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
startx=end.x();
|
||
|
endx=start.x();
|
||
|
}
|
||
|
if(start.y()<=end.y())
|
||
|
{
|
||
|
starty=start.y();
|
||
|
endy=end.y();
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
starty=end.y();
|
||
|
endy=start.y();
|
||
|
}
|
||
|
|
||
|
if ( toTQRect ( startx - m_handleSize / 2.0, starty - m_handleSize / 2.0, m_handleSize, m_handleSize ).tqcontains( currentViewPoint ) )
|
||
|
{
|
||
|
if( !m_selecting )
|
||
|
{
|
||
|
m_dx= startx-currentViewPoint.x();
|
||
|
m_dy = starty - currentViewPoint.y();
|
||
|
}
|
||
|
return UpperLeft;
|
||
|
}
|
||
|
else if ( toTQRect ( startx - m_handleSize / 2.0, endy - m_handleSize / 2.0, m_handleSize, m_handleSize ).tqcontains( currentViewPoint ) )
|
||
|
{
|
||
|
if( !m_selecting )
|
||
|
{
|
||
|
m_dx = startx-currentViewPoint.x();
|
||
|
m_dy = endy-currentViewPoint.y();
|
||
|
}
|
||
|
return LowerLeft;
|
||
|
}
|
||
|
else if ( toTQRect ( endx - m_handleSize / 2.0, starty - m_handleSize / 2.0, m_handleSize, m_handleSize ).tqcontains( currentViewPoint ) )
|
||
|
{
|
||
|
if( !m_selecting )
|
||
|
{
|
||
|
m_dx = endx - currentViewPoint.x();
|
||
|
m_dy = starty - currentViewPoint.y() ;
|
||
|
}
|
||
|
return UpperRight;
|
||
|
}
|
||
|
else if ( toTQRect ( endx - m_handleSize / 2.0, endy - m_handleSize / 2.0, m_handleSize, m_handleSize ).tqcontains( currentViewPoint ) )
|
||
|
{
|
||
|
if( !m_selecting )
|
||
|
{
|
||
|
m_dx = endx - currentViewPoint.x();
|
||
|
m_dy= endy - currentViewPoint.y();
|
||
|
}
|
||
|
return LowerRight;
|
||
|
}
|
||
|
else if ( toTQRect ( startx + ( endx - startx - m_handleSize ) / 2.0, starty - m_handleSize / 2.0, m_handleSize, m_handleSize ).tqcontains( currentViewPoint ) )
|
||
|
{
|
||
|
if( !m_selecting )
|
||
|
{
|
||
|
m_dy = starty - currentViewPoint.y() ;
|
||
|
}
|
||
|
return Upper;
|
||
|
}
|
||
|
else if ( toTQRect ( startx + ( endx - startx - m_handleSize ) / 2.0, endy - m_handleSize / 2, m_handleSize, m_handleSize ).tqcontains( currentViewPoint ) )
|
||
|
{
|
||
|
if( !m_selecting )
|
||
|
{
|
||
|
m_dy = endy - currentViewPoint.y();
|
||
|
}
|
||
|
return Lower;
|
||
|
}
|
||
|
else if ( toTQRect ( startx - m_handleSize / 2.0, starty + ( endy - starty - m_handleSize ) / 2.0, m_handleSize, m_handleSize ).tqcontains( currentViewPoint ) )
|
||
|
{
|
||
|
if( !m_selecting )
|
||
|
{
|
||
|
m_dx = startx - currentViewPoint.x() ;
|
||
|
}
|
||
|
return Left;
|
||
|
}
|
||
|
else if ( toTQRect ( endx - m_handleSize / 2.0 , starty + ( endy - starty - m_handleSize ) / 2.0, m_handleSize, m_handleSize ).tqcontains( currentViewPoint ) )
|
||
|
{
|
||
|
if( !m_selecting )
|
||
|
{
|
||
|
m_dx = endx-currentViewPoint.x();
|
||
|
}
|
||
|
return Right;
|
||
|
}
|
||
|
else if ( toTQRect ( startx , starty, endx - startx , endy - starty ).tqcontains( currentViewPoint ) )
|
||
|
{
|
||
|
return Inside;
|
||
|
}
|
||
|
else return None;
|
||
|
}
|
||
|
|
||
|
void KisToolCrop::setMoveResizeCursor (TQ_INT32 handle)
|
||
|
{
|
||
|
switch (handle)
|
||
|
{
|
||
|
case (UpperLeft):
|
||
|
case (LowerRight):
|
||
|
m_subject->canvasController()->setCanvasCursor(KisCursor::sizeFDiagCursor());
|
||
|
return;
|
||
|
case (LowerLeft):
|
||
|
case (UpperRight):
|
||
|
m_subject->canvasController()->setCanvasCursor(KisCursor::sizeBDiagCursor());
|
||
|
return;
|
||
|
case (Upper):
|
||
|
case (Lower):
|
||
|
m_subject->canvasController()->setCanvasCursor(KisCursor::sizeVerCursor());
|
||
|
return;
|
||
|
case (Left):
|
||
|
case (Right):
|
||
|
m_subject->canvasController()->setCanvasCursor(KisCursor::sizeHorCursor());
|
||
|
return;
|
||
|
case (Inside):
|
||
|
m_subject->canvasController()->setCanvasCursor(KisCursor::sizeAllCursor());
|
||
|
return;
|
||
|
}
|
||
|
m_subject->canvasController()->setCanvasCursor(KisCursor::arrowCursor());
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
|
||
|
#include "kis_tool_crop.moc"
|