/* ============================================================
 *
 * This file is a part of digiKam project
 * http://www.digikam.org
 *
 * Date        : 2004-08-22
 * Description : a generic widget to display a panel to choose
 *               a rectangular image area.
 *
 * Copyright (C) 2004-2008 by Gilles Caulier <caulier dot gilles at gmail dot com>
 *
 * 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 <cmath>

// TQt includes.

#include <tqpainter.h>
#include <tqpixmap.h>
#include <tqpen.h>
#include <tqtimer.h>

// KDE includes.

#include <kcursor.h>

// Local includes.

#include "ddebug.h"
#include "paniconwidget.h"
#include "paniconwidget.moc"

namespace Digikam
{

class PanIconWidgetPriv
{

public:

    PanIconWidgetPriv()
    {
        moveSelection = false;
    }

    bool   moveSelection;

    int    xpos;
    int    ypos;

    TQRect  regionSelection;         // Original size image selection.

    TQImage image;
};

PanIconWidget::PanIconWidget(TQWidget *parent, WFlags flags)
             : TQWidget(parent, 0, flags)
{
    d = new PanIconWidgetPriv;
    m_flicker    = false;
    m_timerID    = 0;
    m_pixmap     = 0;
    m_zoomFactor = 1.0;  

    setBackgroundMode(TQt::NoBackground);
    setMouseTracking(true);
}

PanIconWidget::~PanIconWidget()
{
    if (m_timerID) killTimer(m_timerID);

    if (m_pixmap) delete m_pixmap;

    delete d;
}

void PanIconWidget::setImage(int previewWidth, int previewHeight, const TQImage& image)
{
    TQSize sz(image.width(), image.height());
    sz.scale(previewWidth, previewHeight, TQSize::ScaleMin);
    m_pixmap          = new TQPixmap(previewWidth, previewHeight);
    m_width           = sz.width();
    m_height          = sz.height();
    d->image          = image.smoothScale(sz.width(), sz.height());
    m_orgWidth        = image.width();
    m_orgHeight       = image.height();
    m_zoomedOrgWidth  = image.width();
    m_zoomedOrgHeight = image.height();
    setFixedSize(m_width, m_height);
 
    m_rect = TQRect(width()/2-m_width/2, height()/2-m_height/2, m_width, m_height);
    updatePixmap();
    m_timerID = startTimer(800);
}

void PanIconWidget::setImage(int previewWidth, int previewHeight, const DImg& image)
{
    DImg img(image);
    setImage(previewWidth, previewHeight, img.copyTQImage());
}

void PanIconWidget::slotZoomFactorChanged(double factor)
{
    if (m_zoomFactor == factor) return;
    m_zoomFactor      = factor;
    m_zoomedOrgWidth  = (int)(m_orgWidth  * factor);
    m_zoomedOrgHeight = (int)(m_orgHeight * factor);
    updatePixmap();
    repaint(false);
}

void PanIconWidget::setRegionSelection(const TQRect& regionSelection)
{
    d->regionSelection = regionSelection;
    m_localRegionSelection.setX( m_rect.x() + (int)((float)d->regionSelection.x() *
                                 ((float)m_width / (float)m_zoomedOrgWidth)) );
                                            
    m_localRegionSelection.setY( m_rect.y() + (int)((float)d->regionSelection.y() *
                                 ((float)m_height / (float)m_zoomedOrgHeight)) );
                                            
    m_localRegionSelection.setWidth( (int)((float)d->regionSelection.width() *
                                     ((float)m_width / (float)m_zoomedOrgWidth)) );
                                     
    m_localRegionSelection.setHeight( (int)((float)d->regionSelection.height() *
                                      ((float)m_height / (float)m_zoomedOrgHeight)) );

    updatePixmap();
    repaint(false);
}

TQRect PanIconWidget::getRegionSelection()
{
    return (d->regionSelection);
}

void PanIconWidget::setCursorToLocalRegionSelectionCenter()
{
    TQCursor::setPos(mapToGlobal(m_localRegionSelection.center()));
}

void PanIconWidget::setCenterSelection()
{
    setRegionSelection(TQRect( 
             (int)(((float)m_zoomedOrgWidth  / 2.0) - ((float)d->regionSelection.width()  / 2.0)),
             (int)(((float)m_zoomedOrgHeight / 2.0) - ((float)d->regionSelection.height() / 2.0)),
             d->regionSelection.width(),
             d->regionSelection.height()));
}

void PanIconWidget::regionSelectionMoved(bool targetDone)
{
    if (targetDone)
    {
       updatePixmap();          
       repaint(false);
    }
    
    int x = (int)lround( ((float)m_localRegionSelection.x() - (float)m_rect.x() ) *
                         ((float)m_zoomedOrgWidth / (float)m_width) );
                                            
    int y = (int)lround( ((float)m_localRegionSelection.y() - (float)m_rect.y() ) *
                         ((float)m_zoomedOrgHeight / (float)m_height) );
                                            
    int w = (int)lround( (float)m_localRegionSelection.width() *
                         ((float)m_zoomedOrgWidth / (float)m_width) );
                                     
    int h = (int)lround( (float)m_localRegionSelection.height() *
                         ((float)m_zoomedOrgHeight / (float)m_height) );
                     
    d->regionSelection.setX(x);
    d->regionSelection.setY(y);
    d->regionSelection.setWidth(w);
    d->regionSelection.setHeight(h);
       
    emit signalSelectionMoved( d->regionSelection, targetDone );
}

void PanIconWidget::updatePixmap()
{
    // Drawing background and image.
    m_pixmap->fill(colorGroup().background());
    bitBlt(m_pixmap, m_rect.x(), m_rect.y(), &d->image, 0, 0);
    
    TQPainter p(m_pixmap);
   
    // Drawing selection border

    if (m_flicker) p.setPen(TQPen(TQt::white, 1, TQt::SolidLine));
    else p.setPen(TQPen(TQt::red, 1, TQt::SolidLine));

    p.drawRect(m_localRegionSelection.x(), 
               m_localRegionSelection.y(),
               m_localRegionSelection.width(), 
               m_localRegionSelection.height());

    if (m_flicker) p.setPen(TQPen(TQt::red, 1, TQt::DotLine));
    else p.setPen(TQPen(TQt::white, 1, TQt::DotLine));

    p.drawRect(m_localRegionSelection.x(), 
               m_localRegionSelection.y(),
               m_localRegionSelection.width(), 
               m_localRegionSelection.height());

    p.end();
}

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

void PanIconWidget::setMouseFocus()
{
    raise();
    d->xpos          = m_localRegionSelection.center().x();
    d->ypos          = m_localRegionSelection.center().y();
    d->moveSelection = true;
    setCursor( KCursor::sizeAllCursor() );           
    emit signalSelectionTakeFocus();
}

void PanIconWidget::hideEvent(TQHideEvent *e)
{
    TQWidget::hideEvent(e);

    if ( d->moveSelection )
    {    
        d->moveSelection = false;
        setCursor( KCursor::arrowCursor() );           
        emit signalHiden();  
    }
}

void PanIconWidget::mousePressEvent ( TQMouseEvent * e )
{
    if ( (e->button() == TQt::LeftButton || e->button() == TQt::MidButton) &&
         m_localRegionSelection.contains( e->x(), e->y() ) )
    {
        d->xpos          = e->x();
        d->ypos          = e->y();
        d->moveSelection = true;
        setCursor( KCursor::sizeAllCursor() );           
        emit signalSelectionTakeFocus();
    }
}

void PanIconWidget::mouseMoveEvent ( TQMouseEvent * e )
{
    if ( d->moveSelection && 
         (e->state() == TQt::LeftButton || e->state() == TQt::MidButton) )
    {
        int newxpos = e->x();
        int newypos = e->y();
    
        m_localRegionSelection.moveBy (newxpos - d->xpos, newypos - d->ypos);
        
        d->xpos = newxpos;
        d->ypos = newypos;
                
        // Perform normalization of selection area.
            
        if (m_localRegionSelection.left() < m_rect.left())
            m_localRegionSelection.moveLeft(m_rect.left());
                
        if (m_localRegionSelection.top() < m_rect.top())
            m_localRegionSelection.moveTop(m_rect.top());
                
        if (m_localRegionSelection.right() > m_rect.right())
            m_localRegionSelection.moveRight(m_rect.right());
                
        if (m_localRegionSelection.bottom() > m_rect.bottom())
            m_localRegionSelection.moveBottom(m_rect.bottom());
        
        updatePixmap();
        repaint(false);
        regionSelectionMoved(false);
        return;
    }        
    else 
    {
        if ( m_localRegionSelection.contains( e->x(), e->y() ) )
            setCursor( KCursor::handCursor() );           
        else
            setCursor( KCursor::arrowCursor() );           
    }
}

void PanIconWidget::mouseReleaseEvent ( TQMouseEvent * )
{
    if ( d->moveSelection )
    {    
        d->moveSelection = false;
        setCursor( KCursor::arrowCursor() );           
        regionSelectionMoved(true);
    }
}

void PanIconWidget::timerEvent(TQTimerEvent * e)
{
    if (e->timerId() == m_timerID)
    {
        m_flicker = !m_flicker;
        updatePixmap();
        repaint(false);
    }
    else
        TQWidget::timerEvent(e);
}

}  // NameSpace Digikam
