// -*- C++ -*-
// --------------------------------------------------------------------
// IpeCanvas
// --------------------------------------------------------------------
/*

    This file is part of the extensible drawing editor Ipe.
    Copyright (C) 1993-2004  Otfried Cheong

    Ipe 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.

    As a special exception, you have permission to link Ipe with the
    CGAL library and distribute executables, as long as you follow the
    requirements of the Gnu General Public License in regard to all of
    the software in the executable aside from CGAL.

    Ipe 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 Ipe; if not, you can find it at
    "http://www.gnu.org/copyleft/gpl.html", or write to the Free
    Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.

*/

#ifndef IPECANVAS_H
#define IPECANVAS_H

#include "ipegeo.h"
#include "ipecolor.h"
#include "ipesnap.h"
#include "ipepainter.h"
#include "ipefonts.h"

#include <qwidget.h>
#include <qpixmap.h>
#include <qpainter.h>

// --------------------------------------------------------------------

class IpeStyleSheet;
class IpePage;
class IpeOverlay;

class IpePdfObj;
class IpeFontPool;

class QMouseEvent;
class QStatusBar;

// --------------------------------------------------------------------

/*! \class IpeCanvasServices
  \brief Interface for canvas callbacks.
*/

class IpeCanvasServices : public IpeFontsServices {
public:
  //! Request an IpeOverlay object because of this mouse press.
  virtual void CvSvcRequestOverlay(QMouseEvent *ev) = 0;
  //! Notify application whether a drawing is active.
  virtual void CvSvcSetDrawingMode(bool mode) = 0;
  //! Notify application of change in zoom by wheel mouse.
  virtual void CvSvcWheelZoom(int delta) = 0;
  //! Notify application of current mouse position (in user coordinates).
  virtual void CvSvcMousePosition(const IpeVector &pos) = 0;
};

// --------------------------------------------------------------------

class IpeCanvasPainter : public IpePainter {
public:
  IpeCanvasPainter(const IpeStyleSheet *sheet,
		   IpeCanvasFonts *fonts,
		   QPixmap *pixmap, QPainter *painter,
		   double zoom, bool pretty,
		   int maxBitmapSize);
  virtual ~IpeCanvasPainter() { }

  void SetDimmed(bool dim) { iDimmed = dim; }

protected:
  virtual void DoMoveTo(const IpeVector &v);
  virtual void DoLineTo(const IpeVector &v);
  virtual void DoCurveTo(const IpeVector &v1, const IpeVector &v2,
			 const IpeVector &v3);
  virtual void DoClosePath();

  virtual void DoDrawPath();
  virtual void DoDrawBitmap(IpeBitmap bitmap);
  virtual void DoDrawText(const IpeText *text);

private:
  bool DrawChar(int ch, QRgb rgb, int x, int y);
  void Execute(const IpeBuffer &buffer);
  void ClearArgs();
  void Opcm();
  void OpBT();
  void OpTf();
  void OpTd();
  void OpTJ();
  void Opg(bool stroke);
  void Oprg(bool stroke);
  void Opw();
  void Opm();
  void Opl();

private:
  IpeCanvasFonts *iFonts;
  QPixmap *iPixmap;
  QPainter *iPainter;
  double iZoom;
  bool iPretty;
  int iMaxBitmapSize;

  bool iDimmed;

  enum TVertexType { EMoveTo, ELineTo, ECurveTo,
		     EEndPath, EEndClosedPath };

  std::vector<QPoint> iV;
  std::vector<TVertexType> iType;

  IpeAttribute iDash[4]; // dash, dot, dash dot, dash dot dot

  // PDF operator drawing
  std::vector<const IpePdfObj *> iArgs;
  uint iStrokeRgb;
  uint iFillRgb;
  double iLineWid;
  IpeVector iMoveTo;
  // text state
  IpeFaceSize *iFont;  // not owned
  double iFontSize;
  IpeVector iTextPos;
};

// --------------------------------------------------------------------

class IpeCanvas : public QWidget {
  Q_OBJECT

public:
  IpeCanvas(IpeCanvasServices *services, QStatusBar *statusBar,
	    QWidget* parent, WFlags f=0);
  ~IpeCanvas();

  void SetPage(const IpePage *page, int view, const IpeStyleSheet *sheet,
	       const IpeRect &media, IpeAttribute pageColor);
  void SetFontPool(bool antiAlias, const IpeFontPool *fontPool);
  void SetPan(const IpeVector &v);
  void SetZoom(double zoom);
  void SetSnap(const IpeSnapData &s);
  void SetDimmed(bool dimmed);
  void SetAutoOrigin(const IpeVector &v);
  void SetDoubleBuffer(bool db);
  IpeMatrix CanvasTfm() const;

  //! Return current pan.
  inline IpeVector Pan() const { return iPan; }
  //! Return current zoom.
  inline double Zoom() const { return iZoom; }
  //! Return current style sheet.
  inline const IpeStyleSheet *StyleSheet() const { return iStyleSheet; }
  //! Return current media box.
  inline IpeRect MediaBox() const { return iMediaBox; }

  //! Return center of canvas.
  inline IpeVector Center() const {
    return 0.5 * IpeVector(width(), height()); }

  //! Return last mouse position (snapped!) in user coordinates.
  inline IpeVector Pos() const { return iMousePos; }

  //! Return last unsnapped mouse position in user coordinates.
  inline IpeVector UnsnappedPos() const { return iUnsnappedMousePos; }

  //! Return current snapping information.
  inline const IpeSnapData &SnapData() const { return iSnapData; }

  void Message(QString str);
  void ClearMessage();
  void Update();
  void UpdateOverlay();

  void SetOverlay(IpeOverlay *overlay);
  inline IpeOverlay *Overlay() const { return iOverlay; }
  void FinishOverlay();

  IpeVector DevToUser(const IpeVector &arg) const;
  IpeVector UserToDev(const IpeVector &arg) const;

protected:
  virtual void resizeEvent(QResizeEvent *ev);
  virtual void paintEvent(QPaintEvent *ev);
  virtual void mousePressEvent(QMouseEvent *ev) ;
  virtual void mouseReleaseEvent(QMouseEvent *ev);
  virtual void mouseMoveEvent(QMouseEvent *ev);
  virtual void wheelEvent(QWheelEvent *ev);
  virtual QSize sizeHint() const;

private:
  void DrawGrid(QPainter &qPainter);
  void RepaintObjects();
  void ComputeFifi(QMouseEvent *ev);
  void DrawAxes(QPainter &qPainter);
  void SetOrigin();
  bool SimpleSnap();

private:
  const IpePage *iPage;
  int iView;
  const IpeStyleSheet *iStyleSheet;
  IpeCanvasServices *iServices;
  QStatusBar *iStatusBar;
  IpeAttribute iPageColor;
  IpeRect iMediaBox;

  IpeVector iPan;
  double iZoom;
  IpeSnapData iSnapData;
  bool iDimmed;
  bool iDoubleBuffer;
  bool iAutoSnap;
  IpeVector iAutoOrigin;

  IpeOverlay *iOverlay;

  bool iRepaintObjects;
  QPixmap iOffscreen;
  IpeVector iUnsnappedMousePos;
  IpeVector iMousePos;
  QPoint iFifi;
  bool iFifiVisible;

  IpeCanvasFonts *iFonts;
};

// --------------------------------------------------------------------
#endif
