// Copyright (c) 1997-2002  INRIA Sophia-Antipolis (France).
// All rights reserved.
//
// This file is part of CGAL (www.cgal.org); you may redistribute it under
// the terms of the Q Public License version 1.0.
// See the file LICENSE.QPL distributed with CGAL.
//
// Licensees holding a valid commercial license may use this file in
// accordance with the commercial license agreement provided with the software.
//
// This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
// WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
//
// $Source: /CVSROOT/CGAL/Packages/Triangulation_2/demo/Triangulation_2/triangulation_2_edit_vertex.h,v $
// $Revision: 1.5.6.1 $ $Date: 2004/12/18 17:16:16 $
// $Name:  $
//
// Author(s)     : Radu Ursu

#ifndef CGAL_TRIANGULATION_2_EDIT_VERTEX_HELPER
#define CGAL_TRIANGULATION_2_EDIT_VERTEX_HELPER

#include <CGAL/IO/Qt_widget.h>
#include <CGAL/IO/Qt_widget_layer.h>


#include <qobject.h>
#include <qpopupmenu.h>
#include <qcursor.h>



class triangulation_2_edit_vertex_helper : public CGAL::Qt_widget_layer
{
  Q_OBJECT
public:
  virtual void delete_vertexi(){};
  virtual void move_vertexi(){};
  virtual void change_weighti(){};

protected:
  void emit_signal(){emit(triangulation_changed());}

public slots:
  void stateChanged(int i);
  void delete_vertex();
  void move_vertex();
  void change_weight();
signals:
  void triangulation_changed();
};

template <class T>
class triangulation_2_edit_vertex : public triangulation_2_edit_vertex_helper
{
public:

  typedef typename T::Point                         Point;
  typedef typename T::Segment                       Segment;
  typedef typename T::Face_handle                   Face_handle;
  typedef typename T::Vertex_handle                 Vertex_handle;
  typedef typename T::Geom_traits::FT               FT;
  typedef typename T::Locate_type                   Locate_type;
protected:
  FT                                                first_x, first_y;
  FT                                                x2, y2;
  bool                                              wasrepainted;
  bool                                              on_first;
  bool                                              do_not_remove;
  Vertex_handle                                     current_v;
         //the vertex that will be process
  Point                                             old_point;
  T                                                 *dt;
  QPopupMenu                                        *popup;
public:
  triangulation_2_edit_vertex() :
    wasrepainted(true), on_first(false), do_not_remove(false) {};
  void set_Delaunay (T *t) {dt = t;}
private:
  QCursor oldcursor;

  void draw(){
    wasrepainted = true;
  };
  void mousePressEvent(QMouseEvent *e)
  {
    if(e->button() == Qt::LeftButton && on_first)
    {
      on_first = false;
      emit_signal();
    }
    if(e->button() == Qt::RightButton)
    {
      if (dt->dimension()<2) return;
      FT x, y;
      widget->x_real(e->x(), x);
      widget->y_real(e->y(), y);
      Point p(x, y);
      Vertex_handle v = dt->nearest_vertex(p);
      RasterOp old = widget->rasterOp();	//save the initial raster mode
      widget->setRasterOp(XorROP);
      widget->lock();
          *widget << CGAL::GREEN << CGAL::PointSize (7)
              << CGAL::PointStyle (CGAL::DISC);
      if(!wasrepainted)
        *widget << old_point;
      *widget << v->point();
      widget->unlock();
      widget->setRasterOp(old);
      popup->popup(widget->mapToGlobal(e->pos()));
      old_point = v->point();
      current_v = v;
      wasrepainted = FALSE;
      on_first = FALSE;
    }	
  };
  void mouseMoveEvent(QMouseEvent *e)  {
    if(on_first)   {
      FT x, y;
      widget->x_real(e->x(), x);
      widget->y_real(e->y(), y);
		
      *widget << CGAL::GREEN << CGAL::PointSize (5)
	      << CGAL::PointStyle (CGAL::DISC);
      if(!wasrepainted)
	*widget << old_point;
      *widget << Point(x, y);
      if(!do_not_remove)
	dt->remove(current_v);
      Locate_type lt;
      int li;
      Face_handle fh = dt->locate(Point(x,y), lt, li);
      if(lt != T::VERTEX){
	current_v = dt->insert(Point(x, y), lt, fh, li);
	do_not_remove = false;
      } else
	do_not_remove = true;

      widget->redraw();	//redraw the scenes
      old_point = Point(x, y);
    }
  };

  void activating()
  {
    oldcursor = widget->cursor();
    widget->setCursor(crossCursor);
    wasrepainted = TRUE;
    popup = new QPopupMenu( widget, 0);
    popup->insertItem("Delete Point", this, SLOT(delete_vertex()));
    popup->insertItem("Move Point", this,  SLOT(move_vertex()));
  };

  void deactivating()
  {
    widget->setCursor(oldcursor);
  };
  void delete_vertexi(){
    dt->remove(current_v);
    widget->redraw();	//redraw the scenes
  };
  void move_vertexi(){
    on_first = true;
    widget->cursor().setPos(widget->mapToGlobal(
                            QPoint(widget->x_pixel(
			    old_point.x()), widget->y_pixel(old_point.y()))));
  };
};//end class


template <class T>
class triangulation_2_edit_weightedpoint :
  public triangulation_2_edit_vertex_helper
{
public:

  typedef typename T::Weighted_point		      Weighted_point;
  typedef typename T::Bare_point                      Bare_point;
  typedef typename T::Segment                         Segment;
  typedef typename T::Face_handle                     Face_handle;
  typedef typename T::Vertex_handle                   Vertex_handle;
  typedef typename T::Geom_traits                     GT;
  typedef typename CGAL::Kernel_traits<Bare_point>::Kernel::FT FT;
protected:
  FT                                                  first_x, first_y;
  FT                                                  x2, y2;
  bool                                                wasrepainted;
  bool                                                on_first;
           //true if right mouse button was pressed
  bool
  move_button_pressed;
           //true if the popup's move button was pressed
  bool
  change_weight_pressed;
          //true if the popup's change_weight button was pressed
  Vertex_handle                                       current_v;
          //the vertex that will be processed
  Bare_point                                               old_point;
          //contains the old vertex that should be removed
  T                                                   *t;
          //pointer to regular triangulation being used
  QPopupMenu                                          *popup;
          //the popup being displayed when right mouse button is pressed
public:
  triangulation_2_edit_weightedpoint() : wasrepainted(true), on_first(false)
            , move_button_pressed(false), change_weight_pressed(false) {};
  void set_triangulation (T *tr) {t = tr;}

  template < class TRIANGULATION >
  Vertex_handle
  closest_vertex(const TRIANGULATION &T,
			      Face_handle f,
			      const Bare_point& p)
  {
    Vertex_handle v ;
    typename GT::Compare_distance_2 cmp =
      T.geom_traits().compare_distance_2_object();

    if( T.is_infinite(f)){
      int i = f->index(T.infinite_vertex());
      Bare_point pcwi = f->vertex(f->cw(i))->point();
      Bare_point pccwi = f->vertex(f->ccw(i))->point();
      v =  cmp(p, pcwi, pccwi) == CGAL::SMALLER ? f->vertex(f->cw(i)) :
                                                  f->vertex(f->ccw(i));
    }
    else{
      v = f->vertex(0);
      if (cmp(p, f->vertex(1)->point(), v->point()) == CGAL::SMALLER)
        v = f->vertex(1);
      if (cmp(p, f->vertex(2)->point(), v->point()) == CGAL::SMALLER)
        v = f->vertex(2);
    }
    return v;
  }
private:
  QCursor oldcursor;

  void
  draw(){
    wasrepainted = true;
  }

  void
  mousePressEvent(QMouseEvent *e)
  {
    if(e->button() == Qt::LeftButton && on_first)
    {
      on_first = FALSE;
    }
    if(e->button() == Qt::RightButton)
    {
       if (t->dimension()<2) return;
       FT x, y;
       widget->x_real(e->x(), x);
       widget->y_real(e->y(), y);
       Bare_point p(x, y);
       Face_handle f = t->locate(p);
       Vertex_handle v = closest_vertex(*t, f, p);
       RasterOp old = widget->rasterOp();	//save the initial raster mode
       widget->setRasterOp(XorROP);
       widget->lock();
        *widget << CGAL::GREEN << CGAL::PointSize (7)
              << CGAL::PointStyle (CGAL::DISC);
        if(!wasrepainted)
          *widget << old_point;
        *widget << v->point();
       widget->unlock();
       widget->setRasterOp(old);
       popup->popup(widget->mapToGlobal(e->pos()));
       old_point = v->point();
       current_v = v;
       wasrepainted = FALSE;
       on_first = FALSE;
    }	
  }

  void
  mouseMoveEvent(QMouseEvent *e)
  {
    if(on_first)
    {
      if(move_button_pressed){
        FT x, y;
        widget->x_real(e->x(), x);
        widget->y_real(e->y(), y);
    		
        *widget << CGAL::GREEN << CGAL::PointSize (5)
                << CGAL::PointStyle (CGAL::DISC);
        if(!wasrepainted)
          *widget << old_point;
        *widget << Bare_point(x, y);
        double wght = current_v->point().weight();
        t->remove(current_v);
        current_v = t->insert(Weighted_point(Bare_point(x, y), wght));
        widget->redraw();	//redraw the scenes
        old_point = Bare_point(x, y);
      } else if(change_weight_pressed){
        FT x, y;
        widget->x_real(e->x(), x);
        widget->y_real(e->y(), y);

	//        double wght = current_v->point().weight();
        Bare_point lastp = current_v->point().point();

        t->remove(current_v);
        current_v = t->insert(Weighted_point(
		    lastp, CGAL::squared_distance(lastp, Bare_point(x, y))));
        widget->redraw();	//redraw the scenes
        old_point = lastp;
      }
    }
  }

  void
  activating()
  {
    oldcursor = widget->cursor();
    widget->setCursor(crossCursor);
    wasrepainted = TRUE;
    popup = new QPopupMenu( widget, 0);
    popup->insertItem("Delete Vertex", this, SLOT(delete_vertex()));
    popup->insertItem("Move Vertex", this,  SLOT(move_vertex()));
    popup->insertItem("Change Weight", this, SLOT(change_weight()));
  }

  void
  deactivating()
  {
    widget->setCursor(oldcursor);
  }

  void
  delete_vertexi(){
    t->remove(current_v);
    widget->redraw();	//redraw the scenes
  }

  void
  move_vertexi(){
    on_first = true;
    change_weight_pressed = false;
    move_button_pressed = true;
    widget->cursor().setPos(widget->mapToGlobal(
                            QPoint(widget->x_pixel(old_point.x()),
				   widget->y_pixel(old_point.y()))));
  }

  void
  change_weighti(){
    on_first = true;
    move_button_pressed = false;
    change_weight_pressed = true;
    widget->cursor().setPos(widget->mapToGlobal(
                            QPoint(widget->x_pixel(old_point.x()),
				   widget->y_pixel(old_point.y()))));
  }
};//end class

#endif


syntax highlighted by Code2HTML, v. 0.9.1