/**********************************************************************
 *     EPSCAN, an EPSON ES-1200 scanner driver     
 *     Adam P. Jenkins <ajenkins@cs.umass.edu>
 *     
 *     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., 675 Mass Ave, Cambridge, MA 02139, USA.
 *
 **********************************************************************/

// implementation of a widget which displays a pixmap and lets the user
// outline a region with the mouse.
#include <qcursor.h>
#include <qpainter.h>
#include <qwmatrix.h>

#include "EPGetRegion.h"

EPGetRegion::EPGetRegion(QWidget *parent, const char *name)
  : QFrame(parent, name)
{
  region = contentsRect();
  setRange(region);
  
  regionDir = NONE;
  delta.setX(4);
  delta.setY(4);
  setMouseTracking(true);
}

EPGetRegion::~EPGetRegion()
{
				// does nothing
}

void
EPGetRegion::setRegion(const QRect &r)
{
  // first convert it to real coordinates
  QRect nr = rangeMat.invert().map(r.normalize());
  if (contentsRect().contains(nr)) {
    region = nr;
    repaint(region);
  }
}

void
EPGetRegion::setPixmap(const QPixmap &p)
{
  pix = p;
  QRect c = contentsRect();
  if (pix.size() == c.size())
    spix = pix;
  else {
    QWMatrix m;
    m.scale((float)c.width() / (float)pix.width(),
	    (float)c.height() / (float)pix.height());
    spix = pix.xForm(m);
  }
  update();
}

void
EPGetRegion::setRange(const QRect &r)
{
  QRect c = contentsRect();
  if (r.isValid() && !r.isNull()) {
    range = r;
    rangeMat.reset();
    rangeMat.scale((float)r.width() / (float)c.width(),
		   (float)r.height() / (float)c.height());
    rangeMat.translate((float)r.x(), (float)r.y());
  }
  region = contentsRect();	// reset region to max size
}

void
EPGetRegion::mousePressEvent(QMouseEvent *e)
{
  QPoint pos = e->pos();
  if (e->button() == LeftButton) {
    if (regionDir == NONE) {	// start a new region
      updateRegion();		// erase old region
      region.setRect(pos.x(), pos.y(), 0, 0);
      updateRegion();		// draw new region
      setCursor(sizeAllCursor);
    }
  } else if (e->button() == RightButton) {
    updateRegion();		// erase old region
    region = contentsRect();	// set region to maximum size
    updateRegion();
    emit regionChanged(rangeMat.map(region.normalize())); // let people know
  }
}
		     
void
EPGetRegion::mouseMoveEvent(QMouseEvent *e)
{
  QPoint pos = e->pos();

  if ((e->state() & LeftButton)) {
     updateRegion();		// erase old region
     if (pos.x() > contentsRect().left() && pos.x() < contentsRect().right()) {
	switch (regionDir) {
	 case TOPLEFT:		// left
	 case BOTTOMLEFT:
	 case LEFT:
	   region.setLeft(pos.x());
	   break;
	 case TOPRIGHT:		// right
	 case BOTTOMRIGHT:
	 case RIGHT:
	 case NONE:
	   region.setRight(pos.x());
	   break;
	}
     }
     if (pos.y() > contentsRect().top() && pos.y() < contentsRect().bottom()) {
	switch (regionDir) {
	 case TOPLEFT:		// top
	 case TOPRIGHT:
	 case TOP:
	   region.setTop(pos.y());
	   break;
	 case BOTTOMLEFT:	// bottom
	 case BOTTOMRIGHT:
	 case BOTTOM:
	 case NONE:
	   region.setBottom(pos.y());
	   break;
	}
     }
     
     updateRegion();		// show the new region
     emit regionChanged(rangeMat.map(region.normalize())); // let people know
 } else if (! (e->state() & (LeftButton|MidButton|RightButton)) ) {
    // no buttons pushed, update the pointer and regionDir
    QRect
      outer(region.topLeft() - delta, region.bottomRight() + delta),
      inner(region.topLeft() + delta, region.bottomRight() - delta);

    if (!outer.contains(pos) || inner.contains(pos) ) {
       if (regionDir != NONE) {
	  regionDir = NONE;
	  setCursor(arrowCursor); // normal cursor
       }
    } else {
       QRect
	 tr(region.topRight() - delta, region.topRight() + delta),
         tl(region.topLeft() - delta, region.topLeft() + delta),
         br(region.bottomRight() - delta, region.bottomRight() + delta),
         bl(region.bottomLeft() - delta, region.bottomLeft() + delta),
         t(tl.topRight(), tr.bottomLeft()),
         b(bl.topRight(), br.bottomLeft()),
         l(tl.bottomLeft(), bl.topRight()),
         r(tr.bottomLeft(), br.topRight());

       if (tr.contains(pos)) {
	  if (regionDir != TOPRIGHT) {
	     regionDir = TOPRIGHT;
	     setCursor(sizeBDiagCursor);
	  }
       } else if (tl.contains(pos)) {
	  if (regionDir != TOPLEFT) {
	     regionDir = TOPLEFT;
	     setCursor(sizeFDiagCursor);
	  }
       } else if (br.contains(pos)) {
	  if (regionDir != BOTTOMRIGHT) {
	     regionDir = BOTTOMRIGHT;
	     setCursor(sizeFDiagCursor);
	  }
       } else if (bl.contains(pos)) {
	  if (regionDir != BOTTOMLEFT) {
	     regionDir = BOTTOMLEFT;
	     setCursor(sizeBDiagCursor);
	  }
       } else if (t.contains(pos)) {
	  if (regionDir != TOP) {
	     regionDir = TOP;
	     setCursor(sizeVerCursor);
	  }
       } else if (b.contains(pos)) {
	  if (regionDir != BOTTOM) {
	     regionDir = BOTTOM;
	     setCursor(sizeVerCursor);
	  }
       } else if (l.contains(pos)) {
	  if (regionDir != LEFT) {
	     regionDir = LEFT;
	     setCursor(sizeHorCursor);
	  }
       } else if (r.contains(pos)) {
	  if (regionDir != RIGHT) {
	     regionDir = RIGHT;
	     setCursor(sizeHorCursor);
	  }
       }
    }
 }
}

void
EPGetRegion::mouseReleaseEvent(QMouseEvent *e)
{
   if (e->button() == LeftButton || e->button() == RightButton) {
      if (!region.isValid())
	region = region.normalize();
      if (!contentsRect().contains(e->pos()) )
	regionDir = NONE;
      if (regionDir == NONE)	// just got done creating new region
	setCursor(arrowCursor);

      emit regionSelected(rangeMat.map(region));
  }
}

void
EPGetRegion::leaveEvent(QEvent *e)
{
//    if (regionDir != NONE) {
//       regionDir = NONE;
//       setCursor(arrowCursor);	// normal cursor
//    }
}

void
EPGetRegion::paintEvent(QPaintEvent *e)
{
  QPainter paint;
  paint.begin( this );
  drawFrame(&paint);
  paint.setClipRect(contentsRect());
  
  QRect r = e->rect();
  bool redrawreg = false;
  if (r.intersects(region)) {
    erase(region);
    r = region.unite(r);
    redrawreg = true;
  }
  if (!spix.isNull() && spix.rect().intersects(r) ) {
    QRect pr = r.intersect(spix.rect());
    paint.drawPixmap(pr.topLeft(), spix, pr);
  }

  paint.end();
  
  if (redrawreg)
    updateRegion();
}

void
EPGetRegion::resizeEvent(QResizeEvent *e)
{
  QFrame::resizeEvent(e);
  if (!pix.isNull()) {
    QWMatrix m;
    QRect c = contentsRect();
    m.scale((float)c.width() / (float)pix.width(),
	    (float)c.height() / (float)pix.height());
    spix = pix.xForm(m);
  }
  setRange(range);
}

void
EPGetRegion::updateRegion()
{
   QPainter paint;
   QPen pen(darkGray, 2);
   paint.begin(this);
   paint.setClipRect(contentsRect());
   paint.setPen(pen);
   paint.setRasterOp(XorROP);
   paint.drawRect(region.normalize());
   paint.end();
}
