/* ============================================================
 *
 * This file is a part of digiKam project
 * http://www.digikam.org
 *
 * Date  : 2005-01-18
 * Description : a widget class to edit perspective.
 * 
 * Copyright (C) 2005-2007 by Gilles Caulier <caulier dot gilles at gmail dot com>
 * Copyright (C) 2006-2007 by Marcel Wiesweg <marcel dot wiesweg at gmx dot de>
 * 
 * Matrix3 implementation inspired from gimp 2.0
 * Copyright (C) 1995 Spencer Kimball and Peter Mattis
 *
 * 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, 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.
 * 
 * ============================================================ */

// C++ includes.

#include <cstdio>
#include <cstdlib>
#include <cmath>

// TQt includes.

#include <tqregion.h>
#include <tqpainter.h>
#include <tqpen.h>
#include <tqbrush.h>
#include <tqpixmap.h>
#include <tqimage.h>
#include <tqpointarray.h>

// KDE includes.

#include <kstandarddirs.h>
#include <kcursor.h>
#include <kglobal.h> 
#include <kapplication.h>

// Local includes.

#include "triangle.h"
#include "ddebug.h"
#include "imageiface.h"
#include "dimgimagefilters.h"
#include "perspectivewidget.h"
#include "perspectivewidget.moc"

namespace DigikamPerspectiveImagesPlugin
{

PerspectiveWidget::PerspectiveWidget(int w, int h, TQWidget *parent)
                 : TQWidget(parent, 0, TQt::WDestructiveClose)
{
    setBackgroundMode(TQt::NoBackground);
    setMinimumSize(w, h);
    setMouseTracking(true);

    m_drawGrid        = false;
    m_drawWhileMoving = true;
    m_currentResizing = ResizingNone;
    m_guideColor      = TQt::red;
    m_guideSize       = 1;

    m_iface        = new Digikam::ImageIface(w, h);
    uchar *data    = m_iface->setPreviewImageSize(w, h);
    m_w            = m_iface->previewWidth();
    m_h            = m_iface->previewHeight();
    m_origW        = m_iface->originalWidth();
    m_origH        = m_iface->originalHeight();
    m_previewImage = Digikam::DImg(m_w, m_h, m_iface->previewSixteenBit(), m_iface->previewHasAlpha(), data, false);

    m_pixmap = new TQPixmap(w, h);

    m_rect = TQRect(w/2-m_w/2, h/2-m_h/2, m_w, m_h);
    m_grid = TQPointArray(60);

    reset();
}

PerspectiveWidget::~PerspectiveWidget()
{
    delete m_iface;
    delete m_pixmap;
}

Digikam::ImageIface* PerspectiveWidget::imageIface()
{
    return m_iface;
}

TQPoint PerspectiveWidget::getTopLeftCorner(void)
{
    return TQPoint( lroundf((float)(m_topLeftPoint.x()*m_origW) / (float)m_w),
                   lroundf((float)(m_topLeftPoint.y()*m_origH) / (float)m_h));
}

TQPoint PerspectiveWidget::getTopRightCorner(void)
{
    return TQPoint( lroundf((float)(m_topRightPoint.x()*m_origW) / (float)m_w),
                   lroundf((float)(m_topRightPoint.y()*m_origH) / (float)m_h));
}

TQPoint PerspectiveWidget::getBottomLeftCorner(void)
{
    return TQPoint( lroundf((float)(m_bottomLeftPoint.x()*m_origW) / (float)m_w),
                   lroundf((float)(m_bottomLeftPoint.y()*m_origH) / (float)m_h));
}

TQPoint PerspectiveWidget::getBottomRightCorner(void)
{
    return TQPoint( lroundf((float)(m_bottomRightPoint.x()*m_origW) / (float)m_w),
                   lroundf((float)(m_bottomRightPoint.y()*m_origH) / (float)m_h));
}

TQRect PerspectiveWidget::getTargetSize(void)
{
    TQPointArray perspectiveArea;

    perspectiveArea.putPoints( 0, 4,
                               getTopLeftCorner().x(), getTopLeftCorner().y(),
                               getTopRightCorner().x(), getTopRightCorner().y(),
                               getBottomRightCorner().x(), getBottomRightCorner().y(),
                               getBottomLeftCorner().x(), getBottomLeftCorner().y() );

    return perspectiveArea.boundingRect();
}

float PerspectiveWidget::getAngleTopLeft(void)
{
    Triangle topLeft(getTopLeftCorner(), getTopRightCorner(), getBottomLeftCorner());
    return topLeft.angleBAC();
}

float PerspectiveWidget::getAngleTopRight(void)
{
    Triangle topLeft(getTopRightCorner(), getBottomRightCorner(), getTopLeftCorner());
    return topLeft.angleBAC();
}

float PerspectiveWidget::getAngleBottomLeft(void)
{
    Triangle topLeft(getBottomLeftCorner(), getTopLeftCorner(), getBottomRightCorner());
    return topLeft.angleBAC();
}

float PerspectiveWidget::getAngleBottomRight(void)
{
    Triangle topLeft(getBottomRightCorner(), getBottomLeftCorner(), getTopRightCorner());
    return topLeft.angleBAC();
}

void PerspectiveWidget::reset(void)
{
    m_topLeftPoint.setX(0);
    m_topLeftPoint.setY(0);

    m_topRightPoint.setX(m_w-1);
    m_topRightPoint.setY(0);

    m_bottomLeftPoint.setX(0);
    m_bottomLeftPoint.setY(m_h-1);

    m_bottomRightPoint.setX(m_w-1);
    m_bottomRightPoint.setY(m_h-1);

    m_spot.setX(m_w / 2);
    m_spot.setY(m_h / 2);

    m_antiAlias = true;
    updatePixmap();
    repaint(false);
}

void PerspectiveWidget::applyPerspectiveAdjustment(void)
{
    Digikam::DImg *orgImage = m_iface->getOriginalImg();
    Digikam::DImg destImage(orgImage->width(), orgImage->height(), orgImage->sixteenBit(), orgImage->hasAlpha());

    Digikam::DColor background(0, 0, 0, orgImage->hasAlpha() ? 0 : 255, orgImage->sixteenBit());

    // Perform perspective adjustment.

    buildPerspective(TQPoint(0, 0), TQPoint(m_origW, m_origH),
                     getTopLeftCorner(), getTopRightCorner(),
                     getBottomLeftCorner(), getBottomRightCorner(),
                     orgImage, &destImage, background);

    // Perform an auto-croping around the image.

    Digikam::DImg targetImg = destImage.copy(getTargetSize());

    // Update target image.
    m_iface->putOriginalImage(i18n("Perspective Adjustment"),
                              targetImg.bits(), targetImg.width(), targetImg.height());
}

void PerspectiveWidget::slotToggleAntiAliasing(bool a)
{
    m_antiAlias = a; 
    updatePixmap();
    repaint(false);
}

void PerspectiveWidget::slotToggleDrawWhileMoving(bool draw)
{
    m_drawWhileMoving = draw;
}

void PerspectiveWidget::slotToggleDrawGrid(bool grid)
{
    m_drawGrid = grid;
    updatePixmap();
    repaint(false);
}

void PerspectiveWidget::slotChangeGuideColor(const TQColor &color)
{
    m_guideColor = color;
    updatePixmap();
    repaint(false);
}

void PerspectiveWidget::slotChangeGuideSize(int size)
{
    m_guideSize = size;
    updatePixmap();
    repaint(false);
}

void PerspectiveWidget::updatePixmap(void)
{
    m_topLeftCorner.setRect(m_topLeftPoint.x() + m_rect.topLeft().x(),
                            m_topLeftPoint.y() + m_rect.topLeft().y(), 8, 8);
    m_topRightCorner.setRect(m_topRightPoint.x() - 7 + m_rect.topLeft().x(),
                             m_topRightPoint.y() + m_rect.topLeft().y(), 8, 8);
    m_bottomLeftCorner.setRect(m_bottomLeftPoint.x() + m_rect.topLeft().x(),
                               m_bottomLeftPoint.y() - 7 + m_rect.topLeft().y(), 8, 8);
    m_bottomRightCorner.setRect(m_bottomRightPoint.x() - 7 + m_rect.topLeft().x(),
                                m_bottomRightPoint.y() - 7 + m_rect.topLeft().y(), 8, 8);

    // Compute the grid array

    int gXS = m_w / 15;
    int gYS = m_h / 15;

    for (int i = 0 ; i < 15 ; i++)
    {
        int j = i*4;

        //Horizontal line.
        m_grid.setPoint(j  , 0,   i*gYS);
        m_grid.setPoint(j+1, m_w, i*gYS);

        //Vertical line.
        m_grid.setPoint(j+2, i*gXS, 0);
        m_grid.setPoint(j+3, i*gXS, m_h);
    }

    // Draw background

    m_pixmap->fill(colorGroup().background());

    // if we are resizing with the mouse, compute and draw only if drawWhileMoving is set
    if (m_currentResizing == ResizingNone || m_drawWhileMoving)
    {
        // Create preview image

        Digikam::DImg destImage(m_previewImage.width(), m_previewImage.height(),
                                m_previewImage.sixteenBit(), m_previewImage.hasAlpha());

        Digikam::DColor background(colorGroup().background());

        m_transformedCenter = buildPerspective(TQPoint(0, 0), TQPoint(m_w, m_h),
                                               m_topLeftPoint, m_topRightPoint,
                                               m_bottomLeftPoint, m_bottomRightPoint,
                                               &m_previewImage, &destImage, background);

        m_iface->putPreviewImage(destImage.bits());

        // Draw image

        m_iface->paint(m_pixmap, m_rect.x(), m_rect.y(),
                       m_rect.width(), m_rect.height());
    }
    else
    {
        m_transformedCenter = buildPerspective(TQPoint(0, 0), TQPoint(m_w, m_h),
                                               m_topLeftPoint, m_topRightPoint,
                                               m_bottomLeftPoint, m_bottomRightPoint);
    }

    // Drawing selection borders.

    TQPainter p(m_pixmap);
    p.setPen(TQPen(TQColor(255, 64, 64), 1, TQt::SolidLine));
    p.drawLine(m_topLeftPoint+m_rect.topLeft(),     m_topRightPoint+m_rect.topLeft());
    p.drawLine(m_topRightPoint+m_rect.topLeft(),    m_bottomRightPoint+m_rect.topLeft());
    p.drawLine(m_bottomRightPoint+m_rect.topLeft(), m_bottomLeftPoint+m_rect.topLeft());
    p.drawLine(m_bottomLeftPoint+m_rect.topLeft(),  m_topLeftPoint+m_rect.topLeft());

    // Drawing selection corners.

    TQBrush brush(TQColor(255, 64, 64));
    p.fillRect(m_topLeftCorner,     brush);
    p.fillRect(m_topRightCorner,    brush);
    p.fillRect(m_bottomLeftCorner,  brush);
    p.fillRect(m_bottomRightCorner, brush);

    // Drawing the grid.

    if (m_drawGrid)
    {
        for (uint i = 0 ; i < m_grid.size() ; i += 4)
        {
            //Horizontal line.
            p.drawLine(m_grid.point(i)+m_rect.topLeft(), m_grid.point(i+1)+m_rect.topLeft());
            
            //Vertical line.
            p.drawLine(m_grid.point(i+2)+m_rect.topLeft(), m_grid.point(i+3)+m_rect.topLeft());
        }
    }

    // Drawing transformed center.

    p.setPen(TQPen(TQColor(255, 64, 64), 3, TQt::SolidLine));
    p.drawEllipse( m_transformedCenter.x()+m_rect.topLeft().x()-2, 
                   m_transformedCenter.y()+m_rect.topLeft().y()-2, 4, 4 ); 

    // Drawing vertical and horizontal guide lines.

    int xspot = m_spot.x() + m_rect.x();
    int yspot = m_spot.y() + m_rect.y();
    p.setPen(TQPen(TQt::white, m_guideSize, TQt::SolidLine));
    p.drawLine(xspot, m_rect.top(), xspot, m_rect.bottom());
    p.drawLine(m_rect.left(), yspot, m_rect.right(), yspot);
    p.setPen(TQPen(m_guideColor, m_guideSize, TQt::DotLine));
    p.drawLine(xspot, m_rect.top(), xspot, m_rect.bottom());
    p.drawLine(m_rect.left(), yspot, m_rect.right(), yspot);

    p.end();

    emit signalPerspectiveChanged(getTargetSize(), getAngleTopLeft(), getAngleTopRight(),
                                  getAngleBottomLeft(), getAngleBottomRight());
}

TQPoint PerspectiveWidget::buildPerspective(TQPoint orignTopLeft, TQPoint orignBottomRight,
                                           TQPoint transTopLeft, TQPoint transTopRight,
                                           TQPoint transBottomLeft, TQPoint transBottomRight,
                                           Digikam::DImg *orgImage, Digikam::DImg *destImage,
                                           Digikam::DColor background)
{
    Matrix matrix, transform;
    double  scalex;
    double  scaley;

    double x1 = (double)orignTopLeft.x();
    double y1 = (double)orignTopLeft.y();

    double x2 = (double)orignBottomRight.x();
    double y2 = (double)orignBottomRight.y();

    double tx1 = (double)transTopLeft.x();
    double ty1 = (double)transTopLeft.y();

    double tx2 = (double)transTopRight.x();
    double ty2 = (double)transTopRight.y();

    double tx3 = (double)transBottomLeft.x();
    double ty3 = (double)transBottomLeft.y();

    double tx4 = (double)transBottomRight.x();
    double ty4 = (double)transBottomRight.y();

    scalex = scaley = 1.0;

    if ((x2 - x1) > 0)
      scalex = 1.0 / (double) (x2 - x1);

    if ((y2 - y1) > 0)
      scaley = 1.0 / (double) (y2 - y1);

    // Determine the perspective transform that maps from
    // the unit cube to the transformed coordinates

    double dx1, dx2, dx3, dy1, dy2, dy3;

    dx1 = tx2 - tx4;
    dx2 = tx3 - tx4;
    dx3 = tx1 - tx2 + tx4 - tx3;

    dy1 = ty2 - ty4;
    dy2 = ty3 - ty4;
    dy3 = ty1 - ty2 + ty4 - ty3;

    //  Is the mapping affine?  

    if ((dx3 == 0.0) && (dy3 == 0.0))
    {
        matrix.coeff[0][0] = tx2 - tx1;
        matrix.coeff[0][1] = tx4 - tx2;
        matrix.coeff[0][2] = tx1;
        matrix.coeff[1][0] = ty2 - ty1;
        matrix.coeff[1][1] = ty4 - ty2;
        matrix.coeff[1][2] = ty1;
        matrix.coeff[2][0] = 0.0;
        matrix.coeff[2][1] = 0.0;
    }
    else
    {
        double det1, det2;

        det1 = dx3 * dy2 - dy3 * dx2;
        det2 = dx1 * dy2 - dy1 * dx2;

        if (det1 == 0.0 && det2 == 0.0)
            matrix.coeff[2][0] = 1.0;
        else
            matrix.coeff[2][0] = det1 / det2;

        det1 = dx1 * dy3 - dy1 * dx3;

        if (det1 == 0.0 && det2 == 0.0)
            matrix.coeff[2][1] = 1.0;
        else
            matrix.coeff[2][1] = det1 / det2;

        matrix.coeff[0][0] = tx2 - tx1 + matrix.coeff[2][0] * tx2;
        matrix.coeff[0][1] = tx3 - tx1 + matrix.coeff[2][1] * tx3;
        matrix.coeff[0][2] = tx1;

        matrix.coeff[1][0] = ty2 - ty1 + matrix.coeff[2][0] * ty2;
        matrix.coeff[1][1] = ty3 - ty1 + matrix.coeff[2][1] * ty3;
        matrix.coeff[1][2] = ty1;
    }

    matrix.coeff[2][2] = 1.0;

    // transform is initialized to the identity matrix
    transform.translate(-x1, -y1);
    transform.scale    (scalex, scaley);
    transform.multiply (matrix);

    // Compute perspective transformation to image if image data containers exist.
    if (orgImage && destImage)
        transformAffine(orgImage, destImage, transform, background);

    // Calculate the grid array points.
    double newX, newY;
    for (uint i = 0 ; i < m_grid.size() ; i++)
    {
        transform.transformPoint(m_grid.point(i).x(), m_grid.point(i).y(), &newX, &newY);
        m_grid.setPoint(i, lround(newX), lround(newY));
    }   

    // Calculate and return new image center.
    double newCenterX, newCenterY;
    transform.transformPoint(x2/2.0, y2/2.0, &newCenterX, &newCenterY);

    return TQPoint(lround(newCenterX), lround(newCenterY));
}

void PerspectiveWidget::transformAffine(Digikam::DImg *orgImage, Digikam::DImg *destImage,
                                        const Matrix &matrix, Digikam::DColor background)
{
    Matrix      m(matrix), inv(matrix);

    int         x1, y1, x2, y2;        // target bounding box 
    int         x, y;                  // target coordinates 
    int         u1, v1, u2, v2;        // source bounding box 
    double      uinc, vinc, winc;      // increments in source coordinates
                                       // pr horizontal target coordinate 

    double      u[5],v[5];             // source coordinates,
                                       //   2
                                       //  / \    0 is sample in the center of pixel
                                       // 1 0 3   1..4 is offset 1 pixel in each
                                       //  \ /    direction (in target space)
                                       //   4

    double      tu[5],tv[5],tw[5];     // undivided source coordinates and divisor 

    uchar      *data, *newData;
    bool        sixteenBit;
    int         coords;
    int         width, height;
    int         bytesDepth;
    int         offset;
    uchar      *dest, *d;
    Digikam::DColor color;

    bytesDepth  = orgImage->bytesDepth();
    data        = orgImage->bits();
    sixteenBit  = orgImage->sixteenBit();
    width       = orgImage->width();
    height      = orgImage->height();
    newData     = destImage->bits();

    if (sixteenBit)
        background.convertToSixteenBit();

    //destImage->fill(background);

    Digikam::DImgImageFilters filters;

    // Find the inverse of the transformation matrix
    m.invert();

    u1 = 0;
    v1 = 0;
    u2 = u1 + width;
    v2 = v1 + height;

    x1 = u1;
    y1 = v1;
    x2 = u2;
    y2 = v2;

    dest = new uchar[width * bytesDepth];

    uinc = m.coeff[0][0];
    vinc = m.coeff[1][0];
    winc = m.coeff[2][0];

    coords = 1;

    // these loops could be rearranged, depending on which bit of code
    // you'd most like to write more than once.

    for (y = y1; y < y2; y++)
    {
       // set up inverse transform steps 

        tu[0] = uinc * (x1 + 0.5) + m.coeff[0][1] * (y + 0.5) + m.coeff[0][2] - 0.5;
        tv[0] = vinc * (x1 + 0.5) + m.coeff[1][1] * (y + 0.5) + m.coeff[1][2] - 0.5;
        tw[0] = winc * (x1 + 0.5) + m.coeff[2][1] * (y + 0.5) + m.coeff[2][2];

        d = dest;

        for (x = x1; x < x2; x++)
        {
            int i;     //  normalize homogeneous coords

            for (i = 0; i < coords; i++)
            {
                if (tw[i] == 1.0)
                {
                    u[i] = tu[i];
                    v[i] = tv[i];
                }
                else if (tw[i] != 0.0)
                {
                    u[i] = tu[i] / tw[i];
                    v[i] = tv[i] / tw[i];
                }
                else
                {
                    DDebug() << "homogeneous coordinate = 0...\n" << endl;
                }
            }

            //  Set the destination pixels  

            int   iu = lround( u [0] );
            int   iv = lround( v [0] );

            if (iu >= u1 && iu < u2 && iv >= v1 && iv < v2)
            {
                // u, v coordinates into source  

                int u = iu - u1;
                int v = iv - v1;

                //TODO: Check why antialiasing shows no effect
                /*if (m_antiAlias)
                {
                    if (sixteenBit)
                    {
                        unsigned short *d16 = (unsigned short *)d;
                        filters.pixelAntiAliasing16((unsigned short *)data,
                                                  width, height, u, v, d16+3, d16+2, d16+1, d16);
                    }
                    else
                    {
                        filters.pixelAntiAliasing(data, width, height, u, v,
                                                                  d+3, d+2, d+1, d);
                    }
                }
                else
                {*/
                offset = (v * width * bytesDepth) + (u * bytesDepth);
                color.setColor(data + offset, sixteenBit);
                color.setPixel(d);
                //}

                d += bytesDepth;
            }
            else // not in source range
            {
                // set to background color

                background.setPixel(d);
                d += bytesDepth;
            }

            for (i = 0; i < coords; i++)
            {
                tu[i] += uinc;
                tv[i] += vinc;
                tw[i] += winc;
            }
        }

        //  set the pixel region row

        offset = (y - y1) * width * bytesDepth;
        memcpy(newData + offset, dest, width * bytesDepth);
    }

    delete [] dest;
}

void PerspectiveWidget::paintEvent( TQPaintEvent * )
{
    bitBlt(this, 0, 0, m_pixmap);
}

void PerspectiveWidget::resizeEvent(TQResizeEvent * e)
{
    int old_w = m_w;
    int old_h = m_h;

    delete m_pixmap;
    int w          = e->size().width();
    int h          = e->size().height();
    uchar *data    = m_iface->setPreviewImageSize(w, h);
    m_w            = m_iface->previewWidth();
    m_h            = m_iface->previewHeight();
    m_previewImage = Digikam::DImg(m_w, m_h, m_iface->previewSixteenBit(), m_iface->previewHasAlpha(), data, false);

    m_pixmap      = new TQPixmap(w, h);
    TQRect oldRect = m_rect;
    m_rect        = TQRect(w/2-m_w/2, h/2-m_h/2, m_w, m_h);

    float xFactor = (float)m_rect.width()/(float)(oldRect.width());
    float yFactor = (float)m_rect.height()/(float)(oldRect.height());

    m_topLeftPoint      = TQPoint(lroundf(m_topLeftPoint.x()*xFactor),
                                 lroundf(m_topLeftPoint.y()*yFactor));
    m_topRightPoint     = TQPoint(lroundf(m_topRightPoint.x()*xFactor),
                                 lroundf(m_topRightPoint.y()*yFactor));
    m_bottomLeftPoint   = TQPoint(lroundf(m_bottomLeftPoint.x()*xFactor),
                                 lroundf(m_bottomLeftPoint.y()*yFactor));
    m_bottomRightPoint  = TQPoint(lroundf(m_bottomRightPoint.x()*xFactor),
                                 lroundf(m_bottomRightPoint.y()*yFactor));
    m_transformedCenter = TQPoint(lroundf(m_transformedCenter.x()*xFactor),
                                 lroundf(m_transformedCenter.y()*yFactor));

    m_spot.setX((int)((float)m_spot.x() * ( (float)m_w / (float)old_w)));
    m_spot.setY((int)((float)m_spot.y() * ( (float)m_h / (float)old_h)));

    updatePixmap();
}

void PerspectiveWidget::mousePressEvent ( TQMouseEvent * e )
{
    if ( e->button() == Qt::LeftButton &&
         m_rect.contains( e->x(), e->y() ))
    {
        if ( m_topLeftCorner.contains( e->x(), e->y() ) )
            m_currentResizing = ResizingTopLeft;
        else if ( m_bottomRightCorner.contains( e->x(), e->y() ) )
            m_currentResizing = ResizingBottomRight;
        else if ( m_topRightCorner.contains( e->x(), e->y() ) )
            m_currentResizing = ResizingTopRight;
        else if ( m_bottomLeftCorner.contains( e->x(), e->y() ) )
            m_currentResizing = ResizingBottomLeft;
        else
        {
            m_spot.setX(e->x()-m_rect.x());
            m_spot.setY(e->y()-m_rect.y());
        }
    }
}

void PerspectiveWidget::mouseReleaseEvent ( TQMouseEvent * e )
{
    if ( m_currentResizing != ResizingNone )
    {
        unsetCursor();
        m_currentResizing = ResizingNone;

        // in this case, the pixmap has not been drawn on mouse move
        if (!m_drawWhileMoving)
        {
            updatePixmap();
            repaint(false);
        }
    }
    else
    {
        m_spot.setX(e->x()-m_rect.x());
        m_spot.setY(e->y()-m_rect.y());
        updatePixmap();
        repaint(false);
    }
}

void PerspectiveWidget::mouseMoveEvent ( TQMouseEvent * e )
{
    if ( e->state() == Qt::LeftButton )
    {
        if ( m_currentResizing != ResizingNone )
        {
            TQPointArray unsablePoints;
            TQPoint pm(e->x(), e->y());

            if (!m_rect.contains( pm ))
            {
                if (pm.x() > m_rect.right())
                    pm.setX(m_rect.right());
                else if (pm.x() < m_rect.left())
                    pm.setX(m_rect.left());

                if (pm.y() > m_rect.bottom())
                    pm.setY(m_rect.bottom());
                else if (pm.y() < m_rect.top())
                    pm.setY(m_rect.top());
            }

            if ( m_currentResizing == ResizingTopLeft )
            {
                unsablePoints.putPoints(0, 7,
                                        m_w-1, m_h-1,
                                        0, m_h-1,
                                        0, m_bottomLeftPoint.y()-10,
                                        m_bottomLeftPoint.x(), m_bottomLeftPoint.y()-10,
                                        m_topRightPoint.x()-10, m_topRightPoint.y(),
                                        m_topRightPoint.x()-10, 0,
                                        m_w-1, 0 );
                TQRegion unsableArea(unsablePoints);

                if ( unsableArea.contains(pm) ) return;

                m_topLeftPoint = pm - m_rect.topLeft();
                setCursor( KCursor::sizeFDiagCursor() );
            }

            else if ( m_currentResizing == ResizingTopRight )
            {
                unsablePoints.putPoints(0, 7,
                                        0, m_h-1,
                                        0, 0,
                                        m_topLeftPoint.x()+10, 0,
                                        m_topLeftPoint.x()+10, m_topLeftPoint.y(),
                                        m_bottomRightPoint.x(), m_bottomRightPoint.y()-10,
                                        m_w-1, m_bottomRightPoint.y()-10,
                                        m_w-1, m_h-1);
                TQRegion unsableArea(unsablePoints);

                if ( unsableArea.contains(pm) ) return;

                m_topRightPoint = pm - m_rect.topLeft();
                setCursor( KCursor::sizeBDiagCursor() );
            }

            else if ( m_currentResizing == ResizingBottomLeft  )
            {
                unsablePoints.putPoints(0, 7,
                                        m_w-1, 0,
                                        m_w-1, m_h-1,
                                        m_bottomRightPoint.x()-10, m_h-1,
                                        m_bottomRightPoint.x()-10, m_bottomRightPoint.y()+10,
                                        m_topLeftPoint.x(), m_topLeftPoint.y()+10,
                                        0, m_topLeftPoint.y(),
                                        0, 0);
                TQRegion unsableArea(unsablePoints);

                if ( unsableArea.contains(pm) ) return;

                m_bottomLeftPoint = pm - m_rect.topLeft();
                setCursor( KCursor::sizeBDiagCursor() );
            }

            else if ( m_currentResizing == ResizingBottomRight )
            {
                unsablePoints.putPoints(0, 7,
                                        0, 0,
                                        m_w-1, 0,
                                        m_w-1, m_topRightPoint.y()+10,
                                        m_topRightPoint.x(), m_topRightPoint.y()+10,
                                        m_bottomLeftPoint.x()+10, m_bottomLeftPoint.y(),
                                        m_bottomLeftPoint.x()+10, m_w-1,
                                        0, m_w-1);
                TQRegion unsableArea(unsablePoints);

                if ( unsableArea.contains(pm) ) return;

                m_bottomRightPoint = pm - m_rect.topLeft();
                setCursor( KCursor::sizeFDiagCursor() );
            }

            else 
            {
                m_spot.setX(e->x()-m_rect.x());
                m_spot.setY(e->y()-m_rect.y());
            }

            updatePixmap();
            repaint(false);
        }
    }
    else
    {
        if ( m_topLeftCorner.contains( e->x(), e->y() ) ||
             m_bottomRightCorner.contains( e->x(), e->y() ) )
            setCursor( KCursor::sizeFDiagCursor() );

        else if ( m_topRightCorner.contains( e->x(), e->y() ) ||
                  m_bottomLeftCorner.contains( e->x(), e->y() ) )
            setCursor( KCursor::sizeBDiagCursor() );
        else
            unsetCursor();
    }
}

}  // NameSpace DigikamPerspectiveImagesPlugin

