Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
#include "toonzqt/planeviewer.h"
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
// TnzQt includes
Toshihiro Shimizu 890ddd
#include "toonzqt/imageutils.h"
manongjohn 2c447c
#include "toonzqt/menubarcommand.h"
manongjohn 2c447c
#include "toonzqt/viewcommandids.h"
manongjohn 2c447c
manongjohn 2c447c
#include "../toonz/menubarcommandids.h"
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
// TnzLib includes
Toshihiro Shimizu 890ddd
#include "toonz/stage.h"
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
// TnzCore includes
Toshihiro Shimizu 890ddd
#include "trasterimage.h"
Toshihiro Shimizu 890ddd
#include "ttoonzimage.h"
Toshihiro Shimizu 890ddd
#include "tvectorimage.h"
Toshihiro Shimizu 890ddd
#include "trop.h"
Toshihiro Shimizu 890ddd
#include "tvectorrenderdata.h"
Toshihiro Shimizu 890ddd
#include "tgl.h"
Toshihiro Shimizu 890ddd
#include "tvectorgl.h"
Toshihiro Shimizu 890ddd
#include "tpalette.h"
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
// Qt includes
Toshihiro Shimizu 890ddd
#include <qmouseevent></qmouseevent>
Toshihiro Shimizu 890ddd
#include <qwheelevent></qwheelevent>
Toshihiro Shimizu 890ddd
#include <qresizeevent></qresizeevent>
Toshihiro Shimizu 890ddd
#include <qhideevent></qhideevent>
manongjohn 2c447c
#include <qgestureevent></qgestureevent>
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//#define PRINT_AFF
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//**********************************************************************************
Toshihiro Shimizu 890ddd
//    Local namespace  stuff
Toshihiro Shimizu 890ddd
//**********************************************************************************
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
namespace {
Toshihiro Shimizu 890ddd
Shinya Kitaoka d1f6c4
struct PlaneViewerZoomer final : public ImageUtils::ShortcutZoomer {
Shinya Kitaoka 120a6e
  PlaneViewerZoomer(PlaneViewer *planeViewer) : ShortcutZoomer(planeViewer) {}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
private:
Shinya Kitaoka 473e70
  bool zoom(bool zoomin, bool resetZoom) override;
manongjohn 2c447c
  bool fit() override;
Toshihiro Shimizu 890ddd
};
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//========================================================================
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
bool PlaneViewerZoomer::zoom(bool zoomin, bool resetZoom) {
Shinya Kitaoka 120a6e
  PlaneViewer &planeViewer = static_cast<planeviewer &="">(*getWidget());</planeviewer>
Toshihiro Shimizu 890ddd
manongjohn 2c447c
  resetZoom ? planeViewer.resetView() : zoomin ? planeViewer.zoomIn()
manongjohn 2c447c
                                               : planeViewer.zoomOut();
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  return true;
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
manongjohn 2c447c
bool PlaneViewerZoomer::fit() {
manongjohn 2c447c
  PlaneViewer &planeViewer = static_cast<planeviewer &="">(*getWidget());</planeviewer>
manongjohn 2c447c
manongjohn 2c447c
  planeViewer.fitView();
manongjohn 2c447c
manongjohn 2c447c
  return true;
manongjohn 2c447c
}
Shinya Kitaoka 120a6e
}  // namespace
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//=========================================================================================
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
PlaneViewer::PlaneViewer(QWidget *parent)
shun_iwasawa 96fddb
    : GLWidgetForHighDpi(parent)
Shinya Kitaoka 120a6e
    , m_firstResize(true)
Shinya Kitaoka 120a6e
    , m_xpos(0)
Shinya Kitaoka 120a6e
    , m_ypos(0)
Shinya Kitaoka 120a6e
    , m_aff()  // initialized at the first resize
manongjohn 2c447c
    , m_chessSize(40.0)
manongjohn 2c447c
    , m_firstDraw(true)
manongjohn 2c447c
    , m_dpiX(0.0)
manongjohn 2c447c
    , m_dpiY(0.0) {
Shinya Kitaoka 120a6e
  m_zoomRange[0] = 1e-3, m_zoomRange[1] = 1024.0;
Shinya Kitaoka 120a6e
  setBgColor(TPixel32(235, 235, 235), TPixel32(235, 235, 235));
manongjohn 2c447c
manongjohn 2c447c
  setAttribute(Qt::WA_AcceptTouchEvents);
manongjohn 2c447c
  grabGesture(Qt::SwipeGesture);
manongjohn 2c447c
  grabGesture(Qt::PanGesture);
manongjohn 2c447c
  grabGesture(Qt::PinchGesture);
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//=========================================================================================
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
void PlaneViewer::setZoomRange(double zoomMin, double zoomMax) {
Shinya Kitaoka 120a6e
  m_zoomRange[0] = zoomMin, m_zoomRange[1] = zoomMax;
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
void PlaneViewer::setBgColor(const TPixel32 &color1, const TPixel32 &color2) {
Shinya Kitaoka 120a6e
  m_bgColorF[0] = color1.r / 255.0, m_bgColorF[1] = color1.g / 255.0,
Shinya Kitaoka 120a6e
  m_bgColorF[2] = color1.b / 255.0;
Shinya Kitaoka 120a6e
  m_bgColorF[3] = color2.r / 255.0, m_bgColorF[4] = color2.g / 255.0,
Shinya Kitaoka 120a6e
  m_bgColorF[5] = color2.b / 255.0;
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
void PlaneViewer::getBgColor(TPixel32 &color1, TPixel32 &color2) const {
Shinya Kitaoka 120a6e
  color1.r = m_bgColorF[0] * 255.0, color1.g = m_bgColorF[1] * 255.0,
Shinya Kitaoka 120a6e
  color1.b = m_bgColorF[2] * 255.0;
Shinya Kitaoka 120a6e
  color2.r = m_bgColorF[3] * 255.0, color2.g = m_bgColorF[4] * 255.0,
Shinya Kitaoka 120a6e
  color2.b = m_bgColorF[5] * 255.0;
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
void PlaneViewer::drawBackground() {
Shinya Kitaoka 120a6e
  glClearColor(m_bgColorF[0], m_bgColorF[1], m_bgColorF[2], 1.0);
Shinya Kitaoka 120a6e
  glClear(GL_COLOR_BUFFER_BIT);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  if (m_bgColorF[0] != m_bgColorF[3] || m_bgColorF[1] != m_bgColorF[4] ||
Shinya Kitaoka 120a6e
      m_bgColorF[2] != m_bgColorF[5]) {
Shinya Kitaoka 120a6e
    // Cast the widget rect to world rect
Shinya Kitaoka 120a6e
    TRectD rect(winToWorld(0, 0), winToWorld(width(), height()));
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    // Deduce chess geometry
Shinya Kitaoka 120a6e
    TRect chessRect(tfloor(rect.x0 / m_chessSize),
Shinya Kitaoka 120a6e
                    tfloor(rect.y0 / m_chessSize), tceil(rect.x1 / m_chessSize),
Shinya Kitaoka 120a6e
                    tceil(rect.y1 / m_chessSize));
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    // Draw chess squares
Shinya Kitaoka 120a6e
    glColor3f(m_bgColorF[3], m_bgColorF[4], m_bgColorF[5]);
Shinya Kitaoka 120a6e
    glBegin(GL_QUADS);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    int x, y;
Shinya Kitaoka 120a6e
    TPointD pos;
Shinya Kitaoka 120a6e
    double chessSize2 = 2.0 * m_chessSize;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    for (y = chessRect.y0; y < chessRect.y1; ++y) {
Shinya Kitaoka 120a6e
      pos.y = y * m_chessSize;
Shinya Kitaoka 120a6e
      for (x = chessRect.x0 + ((chessRect.x0 + y) % 2), pos.x = x * m_chessSize;
Shinya Kitaoka 120a6e
           x < chessRect.x1; x += 2, pos.x += chessSize2) {
Shinya Kitaoka 120a6e
        glVertex2d(pos.x, pos.y);
Shinya Kitaoka 120a6e
        glVertex2d(pos.x + m_chessSize, pos.y);
Shinya Kitaoka 120a6e
        glVertex2d(pos.x + m_chessSize, pos.y + m_chessSize);
Shinya Kitaoka 120a6e
        glVertex2d(pos.x, pos.y + m_chessSize);
Shinya Kitaoka 120a6e
      }
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    glEnd();
Shinya Kitaoka 120a6e
  }
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//=========================================================================================
Toshihiro Shimizu 890ddd
shun_iwasawa 5e0d4f
void PlaneViewer::initializeGL() { initializeOpenGLFunctions(); }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
void PlaneViewer::resizeGL(int width, int height) {
shun_iwasawa 1c961d
  width *= getDevPixRatio();
shun_iwasawa 1c961d
  height *= getDevPixRatio();
Shinya Kitaoka 120a6e
  glViewport(0, 0, width, height);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  glMatrixMode(GL_PROJECTION);
Shinya Kitaoka 120a6e
  glLoadIdentity();
Shinya Kitaoka 120a6e
  gluOrtho2D(0, width, 0, height);
Shinya Kitaoka 210a8a
Shinya Kitaoka 120a6e
  glMatrixMode(GL_MODELVIEW);
Shinya Kitaoka 120a6e
  glLoadIdentity();
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  if (m_firstResize) {
Shinya Kitaoka 120a6e
    m_firstResize = false;
Shinya Kitaoka 120a6e
    m_aff         = TTranslation(0.5 * width, 0.5 * height);
Shinya Kitaoka 120a6e
    m_width       = width;
Shinya Kitaoka 120a6e
    m_height      = height;
Shinya Kitaoka 120a6e
  } else {
Shinya Kitaoka 120a6e
    TPointD oldCenter(m_width * 0.5, m_height * 0.5);
Shinya Kitaoka 120a6e
    TPointD newCenter(width * 0.5, height * 0.5);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    m_aff    = m_aff.place(m_aff.inv() * oldCenter, newCenter);
Shinya Kitaoka 120a6e
    m_width  = width;
Shinya Kitaoka 120a6e
    m_height = height;
Shinya Kitaoka 120a6e
  }
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Shinya Kitaoka 210a8a
//=========================================================================================
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
void PlaneViewer::mouseMoveEvent(QMouseEvent *event) {
manongjohn 2c447c
  if (m_gestureActive && m_touchDevice == QTouchDevice::TouchScreen &&
manongjohn 2c447c
      !m_stylusUsed) {
manongjohn 2c447c
    return;
manongjohn 2c447c
  }
manongjohn 2c447c
shun_iwasawa 96fddb
  QPoint curPos = event->pos() * getDevPixRatio();
Shinya Kitaoka 120a6e
  if (event->buttons() & Qt::MidButton)
shun_iwasawa 96fddb
    moveView(curPos.x() - m_xpos, height() - curPos.y() - m_ypos);
Toshihiro Shimizu 890ddd
shun_iwasawa 96fddb
  m_xpos = curPos.x(), m_ypos = height() - curPos.y();
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
void PlaneViewer::mousePressEvent(QMouseEvent *event) {
manongjohn 2c447c
  // qDebug() << "[mousePressEvent]";
manongjohn 2c447c
  if (m_gestureActive && m_touchDevice == QTouchDevice::TouchScreen &&
manongjohn 2c447c
      !m_stylusUsed) {
manongjohn 2c447c
    return;
manongjohn 2c447c
  }
manongjohn 2c447c
shun_iwasawa 96fddb
  m_xpos = event->x() * getDevPixRatio();
shun_iwasawa 96fddb
  m_ypos = height() - event->y() * getDevPixRatio();
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//------------------------------------------------------
Toshihiro Shimizu 890ddd
manongjohn 2c447c
void PlaneViewer::mouseDoubleClickEvent(QMouseEvent *event) {
manongjohn 2c447c
  // qDebug() << "[mouseDoubleClickEvent]";
manongjohn 2c447c
  if (m_gestureActive && !m_stylusUsed) {
manongjohn 2c447c
    m_gestureActive = false;
manongjohn 2c447c
    fitView();
manongjohn 2c447c
    return;
manongjohn 2c447c
  }
manongjohn 2c447c
}
manongjohn 2c447c
manongjohn 2c447c
//------------------------------------------------------
manongjohn 2c447c
manongjohn 2c447c
void PlaneViewer::mouseReleaseEvent(QMouseEvent *event) {
manongjohn 2c447c
  m_gestureActive = false;
manongjohn 2c447c
  m_zooming       = false;
manongjohn 2c447c
  m_panning       = false;
manongjohn 2c447c
  m_stylusUsed    = false;
manongjohn 2c447c
}
manongjohn 2c447c
manongjohn 2c447c
//------------------------------------------------------
manongjohn 2c447c
Shinya Kitaoka 120a6e
void PlaneViewer::wheelEvent(QWheelEvent *event) {
manongjohn 2c447c
  int delta = 0;
manongjohn 2c447c
  switch (event->source()) {
manongjohn 2c447c
  case Qt::MouseEventNotSynthesized: {
manongjohn 2c447c
    if (event->modifiers() & Qt::AltModifier)
manongjohn 2c447c
      delta = event->angleDelta().x();
manongjohn 2c447c
    else
manongjohn 2c447c
      delta = event->angleDelta().y();
manongjohn 2c447c
    break;
manongjohn 2c447c
  }
manongjohn 2c447c
manongjohn 2c447c
  case Qt::MouseEventSynthesizedBySystem: {
manongjohn 2c447c
    QPoint numPixels  = event->pixelDelta();
manongjohn 2c447c
    QPoint numDegrees = event->angleDelta() / 8;
manongjohn 2c447c
    if (!numPixels.isNull()) {
manongjohn 2c447c
      delta = event->pixelDelta().y();
manongjohn 2c447c
    } else if (!numDegrees.isNull()) {
manongjohn 2c447c
      QPoint numSteps = numDegrees / 15;
manongjohn 2c447c
      delta           = numSteps.y();
manongjohn 2c447c
    }
manongjohn 2c447c
    break;
manongjohn 2c447c
  }
manongjohn 2c447c
manongjohn 2c447c
  default:  // Qt::MouseEventSynthesizedByQt,
manongjohn 2c447c
            // Qt::MouseEventSynthesizedByApplication
manongjohn 2c447c
    {
manongjohn 2c447c
      std::cout << "not supported event: Qt::MouseEventSynthesizedByQt, "
manongjohn 2c447c
                   "Qt::MouseEventSynthesizedByApplication"
manongjohn 2c447c
                << std::endl;
manongjohn 2c447c
      break;
manongjohn 2c447c
    }
manongjohn 2c447c
manongjohn 2c447c
  }  // end switch
manongjohn 2c447c
manongjohn 2c447c
  if (abs(delta) > 0) {
manongjohn 2c447c
    if ((m_gestureActive == true &&
manongjohn 2c447c
         m_touchDevice == QTouchDevice::TouchScreen) ||
manongjohn 2c447c
        m_gestureActive == false) {
manongjohn 2c447c
      TPointD pos(event->x() * getDevPixRatio(),
manongjohn 2c447c
                  height() - event->y() * getDevPixRatio());
manongjohn 2c447c
      double zoom_par = 1 + event->delta() * 0.001;
Toshihiro Shimizu 890ddd
manongjohn 2c447c
      zoomView(pos.x, pos.y, zoom_par);
manongjohn 2c447c
    }
manongjohn 2c447c
  }
manongjohn 2c447c
  event->accept();
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
void PlaneViewer::keyPressEvent(QKeyEvent *event) {
Shinya Kitaoka 120a6e
  if (PlaneViewerZoomer(this).exec(event)) return;
Toshihiro Shimizu 890ddd
Jeremy Bullock 1ef2a2
  QOpenGLWidget::keyPressEvent(event);
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//! Disposes of the auxiliary internal rasterBuffer().
Shinya Kitaoka 120a6e
void PlaneViewer::hideEvent(QHideEvent *event) {
Shinya Kitaoka 120a6e
  m_rasterBuffer = TRaster32P();
manongjohn 2c447c
  m_dpiX         = 0.0;  // reset dpi
manongjohn 2c447c
  m_dpiY         = 0.0;
manongjohn 2c447c
}
manongjohn 2c447c
manongjohn 2c447c
//------------------------------------------------------------------
manongjohn 2c447c
manongjohn 2c447c
void PlaneViewer::contextMenuEvent(QContextMenuEvent *event) {
manongjohn 2c447c
  QMenu *menu = new QMenu(this);
manongjohn 2c447c
manongjohn 2c447c
  QAction *reset = menu->addAction(tr("Reset View"));
manongjohn 2c447c
  reset->setShortcut(
manongjohn 2c447c
      QKeySequence(CommandManager::instance()->getKeyFromId(V_ZoomReset)));
manongjohn 2c447c
  connect(reset, SIGNAL(triggered()), SLOT(resetView()));
manongjohn 2c447c
manongjohn 2c447c
  QAction *fit = menu->addAction(tr("Fit To Window"));
manongjohn 2c447c
  fit->setShortcut(
manongjohn 2c447c
      QKeySequence(CommandManager::instance()->getKeyFromId(V_ZoomFit)));
manongjohn 2c447c
  connect(fit, SIGNAL(triggered()), SLOT(fitView()));
manongjohn 2c447c
manongjohn 2c447c
  menu->exec(event->globalPos());
manongjohn 2c447c
manongjohn 2c447c
  delete menu;
manongjohn 2c447c
  update();
manongjohn 2c447c
}
manongjohn 2c447c
manongjohn 2c447c
//------------------------------------------------------------------
manongjohn 2c447c
manongjohn 2c447c
void PlaneViewer::tabletEvent(QTabletEvent *e) {
manongjohn 2c447c
  // qDebug() << "[tabletEvent]";
manongjohn 2c447c
  if (e->type() == QTabletEvent::TabletPress) {
manongjohn 2c447c
    m_stylusUsed = e->pointerType() ? true : false;
manongjohn 2c447c
  } else if (e->type() == QTabletEvent::TabletRelease) {
manongjohn 2c447c
    m_stylusUsed = false;
manongjohn 2c447c
  }
manongjohn 2c447c
manongjohn 2c447c
  e->accept();
manongjohn 2c447c
}
manongjohn 2c447c
manongjohn 2c447c
//------------------------------------------------------------------
manongjohn 2c447c
manongjohn 2c447c
void PlaneViewer::gestureEvent(QGestureEvent *e) {
manongjohn 2c447c
  // qDebug() << "[gestureEvent]";
manongjohn 2c447c
  m_gestureActive = false;
manongjohn 2c447c
  if (QGesture *swipe = e->gesture(Qt::SwipeGesture)) {
manongjohn 2c447c
    m_gestureActive = true;
manongjohn 2c447c
  } else if (QGesture *pan = e->gesture(Qt::PanGesture)) {
manongjohn 2c447c
    m_gestureActive = true;
manongjohn 2c447c
  }
manongjohn 2c447c
  if (QGesture *pinch = e->gesture(Qt::PinchGesture)) {
manongjohn 2c447c
    QPinchGesture *gesture = static_cast<qpinchgesture *="">(pinch);</qpinchgesture>
manongjohn 2c447c
    QPinchGesture::ChangeFlags changeFlags = gesture->changeFlags();
manongjohn 2c447c
    QPoint firstCenter                     = gesture->centerPoint().toPoint();
manongjohn 2c447c
    if (m_touchDevice == QTouchDevice::TouchScreen)
manongjohn 2c447c
      firstCenter = mapFromGlobal(firstCenter);
manongjohn 2c447c
manongjohn 2c447c
    if (gesture->state() == Qt::GestureStarted) {
manongjohn 2c447c
      m_gestureActive = true;
manongjohn 2c447c
    } else if (gesture->state() == Qt::GestureFinished) {
manongjohn 2c447c
      m_gestureActive = false;
manongjohn 2c447c
      m_zooming       = false;
manongjohn 2c447c
      m_scaleFactor   = 0.0;
manongjohn 2c447c
    } else {
manongjohn 2c447c
      if (changeFlags & QPinchGesture::ScaleFactorChanged) {
manongjohn 2c447c
        double scaleFactor = gesture->scaleFactor();
manongjohn 2c447c
        // the scale factor makes for too sensitive scaling
manongjohn 2c447c
        // divide the change in half
manongjohn 2c447c
        if (scaleFactor > 1) {
manongjohn 2c447c
          double decimalValue = scaleFactor - 1;
manongjohn 2c447c
          decimalValue /= 1.5;
manongjohn 2c447c
          scaleFactor = 1 + decimalValue;
manongjohn 2c447c
        } else if (scaleFactor < 1) {
manongjohn 2c447c
          double decimalValue = 1 - scaleFactor;
manongjohn 2c447c
          decimalValue /= 1.5;
manongjohn 2c447c
          scaleFactor = 1 - decimalValue;
manongjohn 2c447c
        }
manongjohn 2c447c
        if (!m_zooming) {
manongjohn 2c447c
          double delta = scaleFactor - 1;
manongjohn 2c447c
          m_scaleFactor += delta;
manongjohn 2c447c
          if (m_scaleFactor > .2 || m_scaleFactor < -.2) {
manongjohn 2c447c
            m_zooming = true;
manongjohn 2c447c
          }
manongjohn 2c447c
        }
manongjohn 2c447c
        if (m_zooming) {
manongjohn 2c447c
          zoomView(firstCenter.x() * getDevPixRatio(),
manongjohn 2c447c
                   firstCenter.y() * getDevPixRatio(), scaleFactor);
manongjohn 2c447c
          m_panning = false;
manongjohn 2c447c
        }
manongjohn 2c447c
        m_gestureActive = true;
manongjohn 2c447c
      }
manongjohn 2c447c
manongjohn 2c447c
      if (changeFlags & QPinchGesture::CenterPointChanged) {
manongjohn 2c447c
        QPointF centerDelta = (gesture->centerPoint() * getDevPixRatio()) -
manongjohn 2c447c
                              (gesture->lastCenterPoint() * getDevPixRatio());
manongjohn 2c447c
        if (centerDelta.manhattanLength() > 1) {
manongjohn 2c447c
          // panQt(centerDelta.toPoint());
manongjohn 2c447c
        }
manongjohn 2c447c
        m_gestureActive = true;
manongjohn 2c447c
      }
manongjohn 2c447c
    }
manongjohn 2c447c
  }
manongjohn 2c447c
  e->accept();
manongjohn 2c447c
}
manongjohn 2c447c
manongjohn 2c447c
void PlaneViewer::touchEvent(QTouchEvent *e, int type) {
manongjohn 2c447c
  // qDebug() << "[touchEvent]";
manongjohn 2c447c
  if (type == QEvent::TouchBegin) {
manongjohn 2c447c
    m_touchActive   = true;
manongjohn 2c447c
    m_firstPanPoint = e->touchPoints().at(0).pos();
manongjohn 2c447c
    // obtain device type
manongjohn 2c447c
    m_touchDevice = e->device()->type();
manongjohn 2c447c
  } else if (m_touchActive) {
manongjohn 2c447c
    // touchpads must have 2 finger panning for tools and navigation to be
manongjohn 2c447c
    // functional on other devices, 1 finger panning is preferred
manongjohn 2c447c
    if ((e->touchPoints().count() == 2 &&
manongjohn 2c447c
         m_touchDevice == QTouchDevice::TouchPad) ||
manongjohn 2c447c
        (e->touchPoints().count() == 1 &&
manongjohn 2c447c
         m_touchDevice == QTouchDevice::TouchScreen)) {
manongjohn 2c447c
      QTouchEvent::TouchPoint panPoint = e->touchPoints().at(0);
manongjohn 2c447c
      if (!m_panning) {
manongjohn 2c447c
        QPointF deltaPoint = panPoint.pos() - m_firstPanPoint;
manongjohn 2c447c
        // minimize accidental and jerky zooming/rotating during 2 finger
manongjohn 2c447c
        // panning
manongjohn 2c447c
        if ((deltaPoint.manhattanLength() > 100) && !m_zooming) {
manongjohn 2c447c
          m_panning = true;
manongjohn 2c447c
        }
manongjohn 2c447c
      }
manongjohn 2c447c
      if (m_panning) {
manongjohn 2c447c
        QPoint curPos      = panPoint.pos().toPoint() * getDevPixRatio();
manongjohn 2c447c
        QPoint lastPos     = panPoint.lastPos().toPoint() * getDevPixRatio();
manongjohn 2c447c
        QPoint centerDelta = curPos - lastPos;
manongjohn 2c447c
        moveView(centerDelta.x(), -centerDelta.y());
manongjohn 2c447c
      }
manongjohn 2c447c
    }
manongjohn 2c447c
  }
manongjohn 2c447c
  if (type == QEvent::TouchEnd || type == QEvent::TouchCancel) {
manongjohn 2c447c
    m_touchActive = false;
manongjohn 2c447c
    m_panning     = false;
manongjohn 2c447c
  }
manongjohn 2c447c
  e->accept();
manongjohn 2c447c
}
manongjohn 2c447c
manongjohn 2c447c
bool PlaneViewer::event(QEvent *e) {
manongjohn 2c447c
  /*
manongjohn 2c447c
  switch (e->type()) {
manongjohn 2c447c
  case QEvent::TabletPress: {
manongjohn 2c447c
  QTabletEvent *te = static_cast<qtabletevent *="">(e);</qtabletevent>
manongjohn 2c447c
  qDebug() << "[event] TabletPress: pointerType(" << te->pointerType()
manongjohn 2c447c
  << ") device(" << te->device() << ")";
manongjohn 2c447c
  } break;
manongjohn 2c447c
  case QEvent::TabletRelease:
manongjohn 2c447c
  qDebug() << "[event] TabletRelease";
manongjohn 2c447c
  break;
manongjohn 2c447c
  case QEvent::TouchBegin:
manongjohn 2c447c
  qDebug() << "[event] TouchBegin";
manongjohn 2c447c
  break;
manongjohn 2c447c
  case QEvent::TouchEnd:
manongjohn 2c447c
  qDebug() << "[event] TouchEnd";
manongjohn 2c447c
  break;
manongjohn 2c447c
  case QEvent::TouchCancel:
manongjohn 2c447c
  qDebug() << "[event] TouchCancel";
manongjohn 2c447c
  break;
manongjohn 2c447c
  case QEvent::MouseButtonPress:
manongjohn 2c447c
  qDebug() << "[event] MouseButtonPress";
manongjohn 2c447c
  break;
manongjohn 2c447c
  case QEvent::MouseButtonDblClick:
manongjohn 2c447c
  qDebug() << "[event] MouseButtonDblClick";
manongjohn 2c447c
  break;
manongjohn 2c447c
  case QEvent::MouseButtonRelease:
manongjohn 2c447c
  qDebug() << "[event] MouseButtonRelease";
manongjohn 2c447c
  break;
manongjohn 2c447c
  case QEvent::Gesture:
manongjohn 2c447c
  qDebug() << "[event] Gesture";
manongjohn 2c447c
  break;
manongjohn 2c447c
  default:
manongjohn 2c447c
  break;
manongjohn 2c447c
  }
manongjohn 2c447c
  */
manongjohn 2c447c
manongjohn 2c447c
  if (e->type() == QEvent::Gesture &&
manongjohn 2c447c
      CommandManager::instance()
manongjohn 2c447c
          ->getAction(MI_TouchGestureControl)
manongjohn 2c447c
          ->isChecked()) {
manongjohn 2c447c
    gestureEvent(static_cast<qgestureevent *="">(e));</qgestureevent>
manongjohn 2c447c
    return true;
manongjohn 2c447c
  }
manongjohn 2c447c
  if ((e->type() == QEvent::TouchBegin || e->type() == QEvent::TouchEnd ||
manongjohn 2c447c
       e->type() == QEvent::TouchCancel || e->type() == QEvent::TouchUpdate) &&
manongjohn 2c447c
      CommandManager::instance()
manongjohn 2c447c
          ->getAction(MI_TouchGestureControl)
manongjohn 2c447c
          ->isChecked()) {
manongjohn 2c447c
    touchEvent(static_cast<qtouchevent *="">(e), e->type());</qtouchevent>
manongjohn 2c447c
    m_gestureActive = true;
manongjohn 2c447c
    return true;
manongjohn 2c447c
  }
manongjohn 2c447c
  return GLWidgetForHighDpi::event(e);
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//=========================================================================================
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
void PlaneViewer::resetView() {
Shinya Kitaoka 120a6e
  m_aff = TTranslation(0.5 * width(), 0.5 * height());
Shinya Kitaoka 120a6e
  update();
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
manongjohn 2c447c
void PlaneViewer::fitView() {
manongjohn 2c447c
  if (m_imageBounds.isEmpty()) return;
manongjohn 2c447c
  m_aff = TTranslation(0.5 * width(), 0.5 * height());
manongjohn 2c447c
manongjohn 2c447c
  double imageScale = std::min(width() / (double)m_imageBounds.getLx(),
manongjohn 2c447c
                               height() / (double)m_imageBounds.getLy());
manongjohn 2c447c
manongjohn 2c447c
  m_aff = TScale(imageScale, imageScale);
manongjohn 2c447c
  if (m_dpiX != 0.0 && m_dpiY != 0.0)
manongjohn 2c447c
    m_aff *= TScale(m_dpiX / Stage::inch, m_dpiY / Stage::inch);
manongjohn 2c447c
  m_aff.a13 = 0.5 * width();
manongjohn 2c447c
  m_aff.a23 = 0.5 * height();
manongjohn 2c447c
manongjohn 2c447c
  update();
manongjohn 2c447c
}
manongjohn 2c447c
Toshihiro Shimizu 890ddd
//------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
void PlaneViewer::setViewPos(double x, double y) {
Shinya Kitaoka 120a6e
  m_aff.a13 = x, m_aff.a23 = y;
Shinya Kitaoka 120a6e
  update();
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
#ifdef PRINT_AFF
Shinya Kitaoka 120a6e
  qDebug("zoom = %.4f;  pos = %.4f, %.4f", m_aff.a11, m_aff.a13, m_aff.a23);
Toshihiro Shimizu 890ddd
#endif
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
void PlaneViewer::setViewZoom(double x, double y, double zoom) {
Shinya Kitaoka 120a6e
  zoom         = tcrop(zoom, m_zoomRange[0], m_zoomRange[1]);
Shinya Kitaoka 120a6e
  double delta = zoom / m_aff.a11;
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  m_aff.a13 = x + delta * (m_aff.a13 - x);
Shinya Kitaoka 120a6e
  m_aff.a23 = y + delta * (m_aff.a23 - y);
Shinya Kitaoka 120a6e
  m_aff.a11 = m_aff.a22 = zoom;
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  update();
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
#ifdef PRINT_AFF
Shinya Kitaoka 120a6e
  qDebug("zoom = %.4f;  pos = %.4f, %.4f", m_aff.a11, m_aff.a13, m_aff.a23);
Toshihiro Shimizu 890ddd
#endif
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
void PlaneViewer::zoomIn() {
Shinya Kitaoka 120a6e
  setViewZoom(ImageUtils::getQuantizedZoomFactor(m_aff.a11, true));
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
void PlaneViewer::zoomOut() {
Shinya Kitaoka 120a6e
  setViewZoom(ImageUtils::getQuantizedZoomFactor(m_aff.a11, false));
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//=========================================================================================
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
void PlaneViewer::pushGLWorldCoordinates() {
Shinya Kitaoka 120a6e
  m_matrix[0]  = m_aff.a11;
Shinya Kitaoka 120a6e
  m_matrix[4]  = m_aff.a12;
Shinya Kitaoka 120a6e
  m_matrix[12] = m_aff.a13;
Shinya Kitaoka 120a6e
  m_matrix[1]  = m_aff.a21;
Shinya Kitaoka 120a6e
  m_matrix[5]  = m_aff.a22;
Shinya Kitaoka 120a6e
  m_matrix[13] = m_aff.a23;
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  m_matrix[2] = m_matrix[3] = m_matrix[6] = m_matrix[7] = m_matrix[8] =
Shinya Kitaoka 120a6e
      m_matrix[9] = m_matrix[10] = m_matrix[11] = m_matrix[14] = 0;
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  m_matrix[15] = 1.0;
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  glPushMatrix();
Shinya Kitaoka 120a6e
  glLoadMatrixd(m_matrix);  //(GLdouble*) &m_matrix
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
void PlaneViewer::pushGLWinCoordinates() {
Shinya Kitaoka 120a6e
  glPushMatrix();
Shinya Kitaoka 120a6e
  glLoadIdentity();
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
void PlaneViewer::popGLCoordinates() { glPopMatrix(); }
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//=========================================================================================
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
TRaster32P PlaneViewer::rasterBuffer() {
Shinya Kitaoka 120a6e
  if (!m_rasterBuffer || m_rasterBuffer->getLx() != width() ||
Shinya Kitaoka 120a6e
      m_rasterBuffer->getLy() != height())
Shinya Kitaoka 120a6e
    m_rasterBuffer = TRaster32P(width(), height());
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  return m_rasterBuffer;
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
void PlaneViewer::flushRasterBuffer() {
Shinya Kitaoka 120a6e
  assert(m_rasterBuffer);
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
Shinya Kitaoka 120a6e
  glRasterPos2d(0, 0);
Shinya Kitaoka 120a6e
  glDrawPixels(width(), height(), TGL_FMT, TGL_TYPE,
Shinya Kitaoka 120a6e
               m_rasterBuffer->getRawData());
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//=========================================================================================
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
void PlaneViewer::draw(TRasterP ras, double dpiX, double dpiY, TPalette *pal) {
Shinya Kitaoka 120a6e
  TPointD rasCenter(ras->getCenterD());
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  TRaster32P aux(rasterBuffer());
Toshihiro Shimizu 890ddd
manongjohn 2c447c
  m_imageBounds = ras->getBounds();
manongjohn 2c447c
  if (m_dpiX == 0.0 || m_dpiY == 0.0) {
manongjohn 2c447c
    m_dpiX = dpiX;
manongjohn 2c447c
    m_dpiY = dpiY;
manongjohn 2c447c
  }
manongjohn 2c447c
  if (m_firstDraw && !m_imageBounds.isEmpty()) {
manongjohn 2c447c
    m_firstDraw = false;
manongjohn 2c447c
    fitView();
manongjohn 2c447c
  }
manongjohn 2c447c
Shinya Kitaoka 120a6e
  aux->lock();
Shinya Kitaoka 120a6e
  ras->lock();
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  glGetDoublev(GL_MODELVIEW_MATRIX, m_matrix);
Shinya Kitaoka 120a6e
  TAffine viewAff(m_matrix[0], m_matrix[4], m_matrix[12], m_matrix[1],
Shinya Kitaoka 120a6e
                  m_matrix[5], m_matrix[13]);
Shinya Kitaoka 120a6e
  viewAff = viewAff * TScale(Stage::inch / dpiX, Stage::inch / dpiY) *
Shinya Kitaoka 120a6e
            TTranslation(-rasCenter);
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  pushGLWinCoordinates();
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  aux->clear();
Shinya Kitaoka 120a6e
  if (pal)
Shinya Kitaoka 120a6e
    TRop::quickPut(aux, (TRasterCM32P)ras, pal, viewAff);
Shinya Kitaoka 120a6e
  else
Shinya Kitaoka 120a6e
    TRop::quickPut(aux, ras, viewAff);
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  flushRasterBuffer();
Shinya Kitaoka 120a6e
  popGLCoordinates();
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
/*NOTE:
manongjohn 2c447c
glRasterPos2d could be used, along glBitmap and glPixelZoom...
manongjohn 2c447c
however, i've never been able to use them effectively...
Toshihiro Shimizu 890ddd
*/
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
void PlaneViewer::draw(TRasterImageP ri) {
Shinya Kitaoka 120a6e
  double dpiX, dpiY;
Shinya Kitaoka 120a6e
  ri->getDpi(dpiX, dpiY);
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  if (dpiX == 0.0 || dpiY == 0.0) dpiX = dpiY = Stage::inch;
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  draw(ri->getRaster(), dpiX, dpiY);
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
void PlaneViewer::draw(TToonzImageP ti) {
Shinya Kitaoka 120a6e
  double dpiX, dpiY;
Shinya Kitaoka 120a6e
  ti->getDpi(dpiX, dpiY);
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  if (dpiX == 0.0 || dpiY == 0.0) dpiX = dpiY = Stage::inch;
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  draw(ti->getRaster(), dpiX, dpiY, ti->getPalette());
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
void PlaneViewer::draw(TVectorImageP vi) {
Shinya Kitaoka 120a6e
  TRectD bbox(vi->getBBox());
Shinya Kitaoka 120a6e
  TRect bboxI(tfloor(bbox.x0), tfloor(bbox.y0), tceil(bbox.x1) - 1,
Shinya Kitaoka 120a6e
              tceil(bbox.y1) - 1);
manongjohn 2c447c
  m_imageBounds = bboxI;
manongjohn 2c447c
  if (m_dpiX == 0.0 || m_dpiY == 0.0) {
manongjohn 2c447c
    m_dpiX = Stage::inch;
manongjohn 2c447c
    m_dpiY = Stage::inch;
manongjohn 2c447c
  }
manongjohn 2c447c
  if (m_firstDraw) {
manongjohn 2c447c
    m_firstDraw = false;
manongjohn 2c447c
    fitView();
manongjohn 2c447c
  }
Shinya Kitaoka 120a6e
  TVectorRenderData rd(TAffine(), bboxI, vi->getPalette(), 0, true, true);
Shinya Kitaoka 120a6e
  tglDraw(rd, vi.getPointer());
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
void PlaneViewer::draw(TImageP img) {
Shinya Kitaoka 120a6e
  {
Shinya Kitaoka 120a6e
    TRasterImageP ri(img);
Shinya Kitaoka 120a6e
    if (ri) {
Shinya Kitaoka 120a6e
      draw(ri);
Shinya Kitaoka 120a6e
      return;
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
  {
Shinya Kitaoka 120a6e
    TToonzImageP ti(img);
Shinya Kitaoka 120a6e
    if (ti) {
Shinya Kitaoka 120a6e
      draw(ti);
Shinya Kitaoka 120a6e
      return;
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
  {
Shinya Kitaoka 120a6e
    TVectorImageP vi(img);
Shinya Kitaoka 120a6e
    if (vi) {
Shinya Kitaoka 120a6e
      draw(vi);
Shinya Kitaoka 120a6e
      return;
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
  }
Toshihiro Shimizu 890ddd
}