text: #pragma once
  
  #ifndef PLANE_VIEWER_H
  #define PLANE_VIEWER_H
  
  // TnzCore includes
  #include "tcommon.h"
  #include "traster.h"
  #include "timage.h"
  
  // TnzQt includes
  #include "toonzqt/glwidget_for_highdpi.h"
  
  // Qt includes
  #include <QOpenGLWidget>
  #include <QTouchDevice>
  
  #undef DVAPI
  #undef DVVAR
  #ifdef TOONZQT_EXPORTS
  #define DVAPI DV_EXPORT_API
  #define DVVAR DV_EXPORT_VAR
  #else
  #define DVAPI DV_IMPORT_API
  #define DVVAR DV_IMPORT_VAR
  #endif
  
  //----------------------------------------------------------------------------
  
  //  Forward declarations
  class TRasterImageP;
  class TToonzImageP;
  class TVectorImageP;
  class QTouchEvent;
  class QGestureEvent;
  
  //----------------------------------------------------------------------------
  
  /*!
    \brief    The PlaneViewer class implements a basic OpenGL widget showing a
    plane in a
              standard top-down view, and supports image drawing from the Toonz
    images API.
  
    \details  A PlaneViewer instance is designed to view bidimensional objects
    layed-out
              on a plane, providing standard mouse interaction functions and some
    built-in
              keyboard shortcuts to provide view navigation.
  
              The class implements the necessary methods to draw objects on the
    plane -
              prominently, functions to push both world and widget references for
    standard
              OpenGL drawing, conversions between world and widget coordinates,
    and
              efficient image-drawing functions for all Toonz image types.
  */
  
  /*
  CAUTION : Changing PlaneViewer to inherit QOpenGLWidget causes crash bug with
  shader fx for some unknown reasons. So I will reluctantly keep using the
  obsolete class until the shader fx being overhauled. 2016/6/22 Shun
  */
  
  class DVAPI PlaneViewer : public GLWidgetForHighDpi {
    Q_OBJECT
    bool m_touchActive                     = false;
    bool m_gestureActive                   = false;
    QTouchDevice::DeviceType m_touchDevice = QTouchDevice::TouchScreen;
    bool m_zooming                         = false;
    bool m_panning                         = false;
    double m_scaleFactor;  // used for zoom gesture
  
    bool m_stylusUsed = false;
  
    bool m_firstDraw;
  
  public:
    PlaneViewer(QWidget *parent);
  
    // Background functions
    void setBgColor(const TPixel32 &color1, const TPixel32 &color2);
    void getBgColor(TPixel32 &color1, TPixel32 &color2) const;
    void setChessSize(double size);
    void drawBackground();
  
    // Image drawing functions
    void draw(TRasterP ras, double dpiX, double dpiY, TPalette *palette = 0);
    void draw(TRasterImageP ri);
    void draw(TToonzImageP ti);
    void draw(TVectorImageP vi);
    void draw(TImageP img);
  
    // World-Widget conversion functions
    TPointD winToWorld(int x, int y) { return m_aff.inv() * TPointD(x, y); }
    TPointD worldToWin(double x, double y) { return m_aff * TPointD(x, y); }
    TPoint qtWinToWin(int x, int y) { return TPoint(x, height() - y); }
    TPointD qtWinToWorld(int x, int y) {
      return m_aff.inv() * TPointD(x, height() - y);
    }
    TPoint winToQtWin(int x, int y) { return qtWinToWin(x, y); }
    TPointD worldToQtWin(double x, double y) {
      TPointD res(worldToWin(x, y));
      return TPointD(res.x, height() - res.y);
    }
  
    // World-Widget OpenGL references
    void pushGLWorldCoordinates();
    void pushGLWinCoordinates();
    void popGLCoordinates();
  
    // View functions
    TAffine &viewAff() { return m_aff; }
    const TAffine &viewAff() const { return m_aff; }
  
    void zoomIn();
    void zoomOut();
  
    void setViewPos(double x, double y);
    void setViewZoom(double x, double y, double zoom);
    void setViewZoom(double zoom) {
      setViewZoom(0.5 * width(), 0.5 * height(), zoom);
    }
  
    void moveView(double dx, double dy) {
      setViewPos(m_aff.a13 + dx, m_aff.a23 + dy);
    }
    void zoomView(double x, double y, double delta) {
      setViewZoom(x, y, m_aff.a11 * delta);
    }
  
    void setZoomRange(double zoomMin, double zoomMax);
  
    // Auxiliary functions
    TRaster32P rasterBuffer();
    void flushRasterBuffer();
  
  public slots:
  
    void resetView();
    void fitView();
  
  protected:
    int m_xpos, m_ypos;  //!< Mouse position on mouse operations.
    TAffine m_aff;       //!< Affine transform from world to widget coords.
  
    float m_bgColorF[6];  //!< Widget bg color cast in the [0, 1] interval.
    double m_chessSize;   //!< Size of the chessboard squares (default is 40).
  
    TRaster32P m_rasterBuffer;  //!< Auxiliary buffer used to draw on the widget
                                //! directly.
  
    double m_zoomRange[2];  //!< Viewport zoom range (default: [-1024, 1024]).
  
    TRect m_imageBounds;
  
    double m_dpiX, m_dpiY;
  
  protected:
    virtual void contextMenuEvent(QContextMenuEvent *event) override;
    virtual void mouseMoveEvent(QMouseEvent *event) override;
    virtual void mousePressEvent(QMouseEvent *event) override;
    virtual void mouseReleaseEvent(QMouseEvent *event) override;
    virtual void wheelEvent(QWheelEvent *event) override;
    virtual void keyPressEvent(QKeyEvent *event) override;
    virtual void hideEvent(QHideEvent *event) override;
  
    virtual void mouseDoubleClickEvent(QMouseEvent *event) override;
    virtual void tabletEvent(QTabletEvent *e) override;
    void touchEvent(QTouchEvent *e, int type);
    void gestureEvent(QGestureEvent *e);
    virtual bool event(QEvent *e) override;
  
    void initializeGL() override final;
    void resizeGL(int width, int height) override final;
  
  private:
    GLdouble m_matrix[16];
    bool m_firstResize;
    int m_width;
    int m_height;
    QPointF m_firstPanPoint;
  };
  
  #endif  // PLANE_VIEWER_H
  