Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
#include "toonzqt/tonecurvefield.h"
Toshihiro Shimizu 890ddd
#include "toonzqt/fxhistogramrender.h"
shun-iwasawa 0ed559
#include "toonzqt/doublepairfield.h"
Toshihiro Shimizu 890ddd
#include "toonzqt/checkbox.h"
shun-iwasawa 0ed559
#include "toonzqt/doublefield.h"
Toshihiro Shimizu 890ddd
#include <qpainter></qpainter>
Toshihiro Shimizu 890ddd
#include <qpainterpath></qpainterpath>
Toshihiro Shimizu 890ddd
#include <qstackedwidget></qstackedwidget>
Toshihiro Shimizu 890ddd
#include <qmouseevent></qmouseevent>
Toshihiro Shimizu 890ddd
#include <qapplication></qapplication>
Toshihiro Shimizu 890ddd
#include <qhboxlayout></qhboxlayout>
Toshihiro Shimizu 890ddd
#include <qcombobox></qcombobox>
Toshihiro Shimizu 890ddd
#include <qlabel></qlabel>
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
using namespace DVGui;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Shinya Kitaoka 120a6e
namespace {
shun-iwasawa 0ed559
shun-iwasawa 0ed559
// minimum distance between control points
shun-iwasawa 0ed559
const double cpMargin = 4.0;
shun-iwasawa 0ed559
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
double getPercentAtPoint(QPointF point, QPainterPath path) {
Shinya Kitaoka 120a6e
  int i;
Shinya Kitaoka 120a6e
  for (i = 1; i < 100; i++) {
Shinya Kitaoka 120a6e
    double p          = double(i) * 0.01;
Shinya Kitaoka 120a6e
    QPointF pathPoint = path.pointAtPercent(p);
Rozhuk Ivan 823a31
    if (std::abs(pathPoint.x() - point.x()) < 3 &&
Rozhuk Ivan 823a31
        std::abs(pathPoint.y() - point.y()) < 3)
Shinya Kitaoka 120a6e
      return p;
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
  return 0;
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
QList<qpointf> getIntersectedPoint(QRectF rect, QPainterPath path) {</qpointf>
Shinya Kitaoka 120a6e
  int y0 = rect.top();
Shinya Kitaoka 120a6e
  int y1 = rect.bottom();
Shinya Kitaoka 120a6e
  QList<qpointf> points;</qpointf>
Shinya Kitaoka 120a6e
  double g      = 1.0 / 256.0;
Shinya Kitaoka 120a6e
  QPointF prec  = path.pointAtPercent(0);
Shinya Kitaoka 120a6e
  QPointF point = path.pointAtPercent(g);
Shinya Kitaoka 120a6e
  int j         = 0;
Shinya Kitaoka 120a6e
  for (j = 2; j < 256; j++) {
Shinya Kitaoka 120a6e
    QPointF next = path.pointAtPercent(double(j) * g);
Shinya Kitaoka 120a6e
    if (prec.y() >= y0 && prec.y() <= y1) {
Shinya Kitaoka 120a6e
      if (point.y() < y0)
Shinya Kitaoka 120a6e
        points.push_back(QPointF(prec.x(), y0));
Shinya Kitaoka 120a6e
      else if (point.y() > y1)
Shinya Kitaoka 120a6e
        points.push_back(QPointF(prec.x(), y1));
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
    if (next.y() >= y0 && next.y() <= y1) {
Shinya Kitaoka 120a6e
      if (point.y() < y0)
Shinya Kitaoka 120a6e
        points.push_back(QPointF(next.x(), y0));
Shinya Kitaoka 120a6e
      else if (point.y() > y1)
Shinya Kitaoka 120a6e
        points.push_back(QPointF(next.x(), y1));
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
    prec  = point;
Shinya Kitaoka 120a6e
    point = next;
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
  return points;
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
double qtNorm2(const QPointF &p) { return p.x() * p.x() + p.y() * p.y(); }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
double qtDistance2(const QPointF &p1, const QPointF &p2) {
Shinya Kitaoka 120a6e
  return qtNorm2(p2 - p1);
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
shun-iwasawa 0ed559
//---------------------------------------------------------
shun-iwasawa 0ed559
// referred to the truncateSpeeds() in tdoubleparam.cpp
shun-iwasawa 0ed559
void truncateSpeeds(double aFrame, double bFrame, QVector2D &aSpeedTrunc,
shun-iwasawa 0ed559
                    QVector2D &bSpeedTrunc) {
shun-iwasawa 0ed559
  double deltaX = bFrame - aFrame;
shun-iwasawa 0ed559
  if (aSpeedTrunc.x() < 0) aSpeedTrunc.setX(0);
shun-iwasawa 0ed559
  if (bSpeedTrunc.x() > 0) bSpeedTrunc.setX(0);
shun-iwasawa 0ed559
shun-iwasawa 0ed559
  if (aFrame + aSpeedTrunc.x() > bFrame) {
shun-iwasawa 0ed559
    if (aSpeedTrunc.x() != 0) {
shun-iwasawa 0ed559
      aSpeedTrunc = aSpeedTrunc * (deltaX / aSpeedTrunc.x());
shun-iwasawa 0ed559
    }
shun-iwasawa 0ed559
  }
Toshihiro Shimizu 890ddd
shun-iwasawa 0ed559
  if (bFrame + bSpeedTrunc.x() < aFrame) {
shun-iwasawa 0ed559
    if (bSpeedTrunc.x() != 0) {
shun-iwasawa 0ed559
      bSpeedTrunc = -bSpeedTrunc * (deltaX / bSpeedTrunc.x());
shun-iwasawa 0ed559
    }
shun-iwasawa 0ed559
  }
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
}  // anonymous namespace
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//=============================================================================
Toshihiro Shimizu 890ddd
// ChennelCurveEditor
Toshihiro Shimizu 890ddd
//=============================================================================
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
ChennelCurveEditor::ChennelCurveEditor(QWidget *parent,
Shinya Kitaoka 120a6e
                                       HistogramView *histogramView)
Shinya Kitaoka 120a6e
    : QWidget(parent)
Shinya Kitaoka 120a6e
    , m_histogramView(histogramView)
Shinya Kitaoka 120a6e
    , m_currentControlPointIndex(-1)
Shinya Kitaoka 120a6e
    , m_mouseButton(Qt::NoButton)
Shinya Kitaoka 120a6e
    , m_curveHeight(256)
Shinya Kitaoka 120a6e
    , m_LeftRightMargin(42)
Shinya Kitaoka 120a6e
    , m_TopMargin(9)
Shinya Kitaoka 120a6e
    , m_BottomMargin(48)
shun-iwasawa 0ed559
    , m_isLinear(false)
shun-iwasawa 0ed559
    , m_isEnlarged(false) {
Shinya Kitaoka 120a6e
  setFixedSize(m_curveHeight + 2 * m_LeftRightMargin + 2,
Shinya Kitaoka 120a6e
               m_curveHeight + m_TopMargin + m_BottomMargin);
Shinya Kitaoka 120a6e
  setAttribute(Qt::WA_KeyCompression);
Shinya Kitaoka 120a6e
  setFocusPolicy(Qt::StrongFocus);
Shinya Kitaoka 120a6e
  setMouseTracking(true);
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  m_histogramView->setDrawnWidget(this);
Shinya Kitaoka 120a6e
  m_histogramView->setGraphHeight(m_curveHeight);
Shinya Kitaoka 120a6e
  m_histogramView->setGraphAlphaMask(120);
Shinya Kitaoka 120a6e
  m_verticalChannelBar =
Shinya Kitaoka 120a6e
      new ChannelBar(0, m_histogramView->getChannelBarColor(), false);
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
void ChennelCurveEditor::setPoints(QList<tpointd> points) {</tpointd>
Shinya Kitaoka 120a6e
  if (!m_points.isEmpty()) m_points.clear();
shun-iwasawa 0ed559
  for (const TPointD &point : points)
shun-iwasawa 0ed559
    m_points.push_back(QPointF(point.x, point.y));
shun-iwasawa 0ed559
  // update slider position according to the first and the last control points
Shinya Kitaoka 120a6e
  int firstIndex = 3;
Shinya Kitaoka 120a6e
  int lastIndex  = m_points.size() - 4;
shun-iwasawa 0ed559
  emit firstLastXPostionChanged(m_points.at(firstIndex).x(),
shun-iwasawa 0ed559
                                m_points.at(lastIndex).x());
Shinya Kitaoka 120a6e
  update();
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
QList<tpointd> ChennelCurveEditor::getPoints() {</tpointd>
Shinya Kitaoka 120a6e
  QList<tpointd> points;</tpointd>
Shinya Kitaoka 120a6e
  if (m_points.isEmpty()) return points;
shun-iwasawa 0ed559
  for (const QPointF &point : m_points)
shun-iwasawa 0ed559
    points.push_back(TPointD(point.x(), point.y()));
Shinya Kitaoka 120a6e
  return points;
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
shun-iwasawa 0ed559
void ChennelCurveEditor::setFirstLastXPosition(std::pair<double, double=""> values,</double,>
Shinya Kitaoka 120a6e
                                               bool isDragging) {
shun-iwasawa 0ed559
  QPointF newX0(values.first, 0);
shun-iwasawa 0ed559
  QPointF newX1(values.second, 0);
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  int indexX0 = 3;
Shinya Kitaoka 120a6e
  int indexX1 = m_points.size() - 4;
Shinya Kitaoka 120a6e
  QPointF x0  = m_points.at(indexX0);
Shinya Kitaoka 120a6e
  QPointF x1  = m_points.at(indexX1);
Shinya Kitaoka 120a6e
  if (x0.x() != newX0.x()) {
Shinya Kitaoka 120a6e
    QPointF delta(newX0.x() - x0.x(), 0);
Shinya Kitaoka 120a6e
    moveCentralControlPoint(indexX0, delta);
Shinya Kitaoka 120a6e
    update();
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
  if (x1.x() != newX1.x()) {
Shinya Kitaoka 120a6e
    QPointF delta(newX1.x() - x1.x(), 0);
Shinya Kitaoka 120a6e
    moveCentralControlPoint(indexX1, delta);
Shinya Kitaoka 120a6e
    update();
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
  m_currentControlPointIndex = -1;
shun-iwasawa 0ed559
shun-iwasawa 0ed559
  if (!isDragging) emit controlPointChanged(false);
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
void ChennelCurveEditor::setLinear(bool isLinear) {
Shinya Kitaoka 120a6e
  if (m_isLinear == isLinear) return;
Shinya Kitaoka 120a6e
  m_isLinear = isLinear;
Shinya Kitaoka 120a6e
  update();
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
shun-iwasawa 0ed559
void ChennelCurveEditor::setEnlarged(bool isEnlarged) {
shun-iwasawa 0ed559
  if (m_isEnlarged == isEnlarged) return;
shun-iwasawa 0ed559
  m_isEnlarged     = isEnlarged;
shun-iwasawa 0ed559
  int widgetHeight = (m_isEnlarged) ? m_curveHeight * 2 : m_curveHeight;
shun-iwasawa 0ed559
  setFixedSize(widgetHeight + 2 * m_LeftRightMargin + 2,
shun-iwasawa 0ed559
               widgetHeight + m_TopMargin + m_BottomMargin);
shun-iwasawa 0ed559
  m_histogramView->setGraphHeight(widgetHeight);
shun-iwasawa 0ed559
  m_verticalChannelBar->setFixedHeight(widgetHeight + 22);
shun-iwasawa 0ed559
  update();
shun-iwasawa 0ed559
}
shun-iwasawa 0ed559
shun-iwasawa 0ed559
//-----------------------------------------------------------------------------
shun-iwasawa 0ed559
shun-iwasawa 0ed559
void ChennelCurveEditor::setLabelRange(ChannelBar::Range range) {
shun-iwasawa 0ed559
  m_histogramView->channelBar()->setLabelRange(range);
shun-iwasawa 0ed559
  m_verticalChannelBar->setLabelRange(range);
shun-iwasawa 0ed559
}
shun-iwasawa 0ed559
shun-iwasawa 0ed559
//-----------------------------------------------------------------------------
shun-iwasawa 0ed559
Shinya Kitaoka 120a6e
QPointF ChennelCurveEditor::checkPoint(const QPointF p) {
shun-iwasawa 0ed559
  QPointF checkedP = p;
shun-iwasawa 0ed559
  if (p.x() < 0)
shun-iwasawa 0ed559
    checkedP.setX(0);
shun-iwasawa 0ed559
  else if (p.x() > m_curveHeight)
shun-iwasawa 0ed559
    checkedP.setX(m_curveHeight);
shun-iwasawa 0ed559
  if (p.y() < 0)
shun-iwasawa 0ed559
    checkedP.setY(0);
shun-iwasawa 0ed559
  else if (p.y() > m_curveHeight)
shun-iwasawa 0ed559
    checkedP.setY(m_curveHeight);
Shinya Kitaoka 120a6e
  return checkedP;
Shinya Kitaoka 120a6e
}
Shinya Kitaoka 120a6e
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
shun-iwasawa 0ed559
QPointF ChennelCurveEditor::getVisibleHandlePos(int index) const {
shun-iwasawa 0ed559
  QRectF rect(0.0, 0.0, m_curveHeight, m_curveHeight);
shun-iwasawa 0ed559
  QPointF handlePos(m_points.at(index));
shun-iwasawa 0ed559
  if (isCentralControlPoint(index) || rect.contains(handlePos))
shun-iwasawa 0ed559
    return handlePos;
shun-iwasawa 0ed559
shun-iwasawa 0ed559
  if (isLeftControlPoint(index)) {
shun-iwasawa 0ed559
    QPointF cp = m_points.at(index + 1);
shun-iwasawa 0ed559
    QVector2D lHandle(handlePos - cp);
shun-iwasawa 0ed559
    if (handlePos.x() < 0) {
shun-iwasawa 0ed559
      float ratio = -cp.x() / lHandle.x();
shun-iwasawa 0ed559
      handlePos   = cp + lHandle.toPointF() * ratio;
shun-iwasawa 0ed559
    }
shun-iwasawa 0ed559
    if (handlePos.y() < 0) {
shun-iwasawa 0ed559
      float ratio = -cp.y() / lHandle.y();
shun-iwasawa 0ed559
      handlePos   = cp + lHandle.toPointF() * ratio;
shun-iwasawa 0ed559
    } else if (handlePos.y() > 256) {
shun-iwasawa 0ed559
      float ratio = (256 - cp.y()) / lHandle.y();
shun-iwasawa 0ed559
      handlePos   = cp + lHandle.toPointF() * ratio;
shun-iwasawa 0ed559
    }
shun-iwasawa 0ed559
  } else {  // isRightControlPoint
shun-iwasawa 0ed559
    QPointF cp = m_points.at(index - 1);
shun-iwasawa 0ed559
    QVector2D rHandle(handlePos - cp);
shun-iwasawa 0ed559
    if (handlePos.x() > 256) {
shun-iwasawa 0ed559
      float ratio = (256 - cp.x()) / rHandle.x();
shun-iwasawa 0ed559
      handlePos   = cp + rHandle.toPointF() * ratio;
shun-iwasawa 0ed559
    }
shun-iwasawa 0ed559
    if (handlePos.y() < 0) {
shun-iwasawa 0ed559
      float ratio = -cp.y() / rHandle.y();
shun-iwasawa 0ed559
      handlePos   = cp + rHandle.toPointF() * ratio;
shun-iwasawa 0ed559
    } else if (handlePos.y() > 256) {
shun-iwasawa 0ed559
      float ratio = (256 - cp.y()) / rHandle.y();
shun-iwasawa 0ed559
      handlePos   = cp + rHandle.toPointF() * ratio;
shun-iwasawa 0ed559
    }
shun-iwasawa 0ed559
  }
shun-iwasawa 0ed559
  return handlePos;
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
shun-iwasawa 0ed559
QPointF ChennelCurveEditor::viewToStrokePoint(const QPointF &p) {
Shinya Kitaoka 120a6e
  double x = p.x() - m_LeftRightMargin - 1;
shun-iwasawa 0ed559
  double y = p.y() - m_TopMargin;
shun-iwasawa 0ed559
  if (m_isEnlarged) {
shun-iwasawa 0ed559
    x *= 0.5;
shun-iwasawa 0ed559
    y *= 0.5;
shun-iwasawa 0ed559
  }
shun-iwasawa 0ed559
  return QPointF(x, m_curveHeight - y);
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
int ChennelCurveEditor::getClosestPointIndex(const QPointF &pos,
Shinya Kitaoka 120a6e
                                             double &minDistance2) const {
Shinya Kitaoka 120a6e
  int closestPointIndex = -1;
Shinya Kitaoka 120a6e
  minDistance2          = 0;
shun-iwasawa 0ed559
  enum pointType { Handle = 0, ControlPoint, PseudoHandle } closestPointType;
shun-iwasawa 0ed559
  QRectF rect(0, 0, m_curveHeight, m_curveHeight);
Shinya Kitaoka 120a6e
  int i;
shun-iwasawa 0ed559
  for (i = 3; i < (int)m_points.size() - 3; i++) {
shun-iwasawa 0ed559
    if (m_isLinear && !isCentralControlPoint(i)) continue;
shun-iwasawa 0ed559
    QPointF visiblePoint = getVisibleHandlePos(i);
shun-iwasawa 0ed559
shun-iwasawa 0ed559
    pointType type =
shun-iwasawa 0ed559
        (isCentralControlPoint(i))
shun-iwasawa 0ed559
            ? ControlPoint
shun-iwasawa 0ed559
            : (visiblePoint == m_points.at(i)) ? Handle : PseudoHandle;
shun-iwasawa 0ed559
shun-iwasawa 0ed559
    double distance2 = qtDistance2(pos, visiblePoint);
shun-iwasawa 0ed559
    if (closestPointIndex < 0 || distance2 < minDistance2 ||
shun-iwasawa 0ed559
        (distance2 == minDistance2 && type < closestPointType)) {
Shinya Kitaoka 120a6e
      minDistance2      = distance2;
Shinya Kitaoka 120a6e
      closestPointIndex = i;
shun-iwasawa 0ed559
      closestPointType  = type;
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
  return closestPointIndex;
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
void ChennelCurveEditor::movePoint(int index, const QPointF delta) {
Shinya Kitaoka 120a6e
  QPointF p = m_points.at(index);
Shinya Kitaoka 120a6e
  p += delta;
Shinya Kitaoka 120a6e
  setPoint(index, p);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  int firstIndex = 3;
Shinya Kitaoka 120a6e
  int lastIndex  = m_points.size() - 4;
Shinya Kitaoka 120a6e
  if (index == firstIndex)
shun-iwasawa 0ed559
    emit firstLastXPostionChanged(p.x(), m_points.at(lastIndex).x());
Shinya Kitaoka 120a6e
  if (index == lastIndex)
shun-iwasawa 0ed559
    emit firstLastXPostionChanged(m_points.at(firstIndex).x(), p.x());
Shinya Kitaoka 120a6e
}
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
//-----------------------------------------------------------------------------
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
void ChennelCurveEditor::setPoint(int index, const QPointF p) {
Shinya Kitaoka 120a6e
  m_points.removeAt(index);
Shinya Kitaoka 120a6e
  m_points.insert(index, p);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  int firstIndex = 3;
Shinya Kitaoka 120a6e
  int lastIndex  = m_points.size() - 4;
Shinya Kitaoka 120a6e
  if (index == firstIndex)
shun-iwasawa 0ed559
    emit firstLastXPostionChanged(p.x(), m_points.at(lastIndex).x());
Shinya Kitaoka 120a6e
  if (index == lastIndex)
shun-iwasawa 0ed559
    emit firstLastXPostionChanged(m_points.at(firstIndex).x(), p.x());
Shinya Kitaoka 120a6e
}
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
//-----------------------------------------------------------------------------
Shinya Kitaoka 120a6e
shun-iwasawa 0ed559
void ChennelCurveEditor::moveCurrentControlPoint(QPointF delta) {
Shinya Kitaoka 120a6e
  assert(m_currentControlPointIndex != -1);
Shinya Kitaoka 120a6e
  int pointCount = m_points.size();
shun-iwasawa 0ed559
  // in case moving the control point
Shinya Kitaoka 120a6e
  if (isCentralControlPoint(m_currentControlPointIndex))
Shinya Kitaoka 120a6e
    moveCentralControlPoint(m_currentControlPointIndex, delta);
shun-iwasawa 0ed559
  // in case moving the left handle
Shinya Kitaoka 120a6e
  else if (isLeftControlPoint(m_currentControlPointIndex)) {
shun-iwasawa 0ed559
    QPointF cp   = m_points.at(m_currentControlPointIndex + 1);
shun-iwasawa 0ed559
    QPointF left = m_points.at(m_currentControlPointIndex);
shun-iwasawa 0ed559
shun-iwasawa 0ed559
    // handle should not move across the control point
shun-iwasawa 0ed559
    if (left.x() + delta.x() > cp.x()) delta.setX(cp.x() - left.x());
shun-iwasawa 0ed559
shun-iwasawa 0ed559
    left += delta;
shun-iwasawa 0ed559
    setPoint(m_currentControlPointIndex, left);
shun-iwasawa 0ed559
shun-iwasawa 0ed559
    // rotate the opposite handle keeping the handle length unchanged
Shinya Kitaoka 120a6e
    if (m_currentControlPointIndex < pointCount - 5) {
shun-iwasawa 0ed559
      QVector2D lHandle(cp - left);
shun-iwasawa 0ed559
      if (!lHandle.isNull()) {
shun-iwasawa 0ed559
        QPointF right = m_points.at(m_currentControlPointIndex + 2);
shun-iwasawa 0ed559
        QVector2D rHandle(right - cp);
shun-iwasawa 0ed559
        QVector2D newRHandle = lHandle.normalized() * rHandle.length();
shun-iwasawa 0ed559
        setPoint(m_currentControlPointIndex + 2, cp + newRHandle.toPointF());
shun-iwasawa 0ed559
      }
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
    emit controlPointChanged(true);
Shinya Kitaoka 120a6e
  }
shun-iwasawa 0ed559
  // in case moving the right handle
Shinya Kitaoka 120a6e
  else {
Shinya Kitaoka 120a6e
    assert(isRightControlPoint(m_currentControlPointIndex));
shun-iwasawa 0ed559
    QPointF cp    = m_points.at(m_currentControlPointIndex - 1);
shun-iwasawa 0ed559
    QPointF right = m_points.at(m_currentControlPointIndex);
shun-iwasawa 0ed559
shun-iwasawa 0ed559
    // handle should not move across the control point
shun-iwasawa 0ed559
    if (right.x() + delta.x() < cp.x()) delta.setX(cp.x() - right.x());
shun-iwasawa 0ed559
shun-iwasawa 0ed559
    right += delta;
shun-iwasawa 0ed559
    setPoint(m_currentControlPointIndex, right);
shun-iwasawa 0ed559
shun-iwasawa 0ed559
    // rotate the opposite handle keeping the handle length unchanged
Shinya Kitaoka 120a6e
    if (m_currentControlPointIndex > 4) {
shun-iwasawa 0ed559
      QVector2D rHandle(cp - right);
shun-iwasawa 0ed559
      if (!rHandle.isNull()) {
shun-iwasawa 0ed559
        QPointF left = m_points.at(m_currentControlPointIndex - 2);
shun-iwasawa 0ed559
        QVector2D lHandle(left - cp);
shun-iwasawa 0ed559
        QVector2D newLHandle = rHandle.normalized() * lHandle.length();
shun-iwasawa 0ed559
        setPoint(m_currentControlPointIndex - 2, cp + newLHandle.toPointF());
shun-iwasawa 0ed559
      }
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
    emit controlPointChanged(true);
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
  update();
shun-iwasawa 0ed559
  emit updateCurrentPosition(m_currentControlPointIndex,
shun-iwasawa 0ed559
                             m_points.at(m_currentControlPointIndex));
Shinya Kitaoka 120a6e
}
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
//-----------------------------------------------------------------------------
Shinya Kitaoka 120a6e
shun-iwasawa 0ed559
void ChennelCurveEditor::moveCentralControlPoint(int index, QPointF delta) {
Shinya Kitaoka 120a6e
  int pointCount = m_points.size();
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  assert(index < pointCount - 3 && index > 2);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  QPointF p = m_points.at(index);
Shinya Kitaoka 120a6e
  QPointF d = delta;
Shinya Kitaoka 120a6e
  // Trovo il valore di delta im modo tale che il punto di controllo non sia
Shinya Kitaoka 120a6e
  // trascinato fuori dal range consentito
shun-iwasawa 0ed559
  QPointF newPoint = checkPoint(p + delta);
Shinya Kitaoka 120a6e
  d                = newPoint - p;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  QPointF nextP       = m_points.at(index + 3);
Shinya Kitaoka 120a6e
  QPointF precP       = m_points.at(index - 3);
Shinya Kitaoka 120a6e
  double nextDistance = nextP.x() - (p.x() + d.x());
Shinya Kitaoka 120a6e
  double precDistance = (p.x() + d.x()) - precP.x();
Shinya Kitaoka 120a6e
shun-iwasawa 0ed559
  if (nextDistance < cpMargin)
shun-iwasawa 0ed559
    d = QPointF(nextP.x() - p.x() - cpMargin, d.y());
shun-iwasawa 0ed559
  else if (precDistance < cpMargin)
shun-iwasawa 0ed559
    d = QPointF(precP.x() - p.x() + cpMargin, d.y());
Shinya Kitaoka 120a6e
shun-iwasawa 4c05e2
  if (d.isNull()) return;
shun-iwasawa 4c05e2
Shinya Kitaoka 120a6e
  // Punto di controllo speciale: il primo visualizzato.
Shinya Kitaoka 120a6e
  if (index == 3) {
Shinya Kitaoka 120a6e
    QPointF dY = QPointF(0, d.y());
Shinya Kitaoka 120a6e
    movePoint(index - 1, dY);
Shinya Kitaoka 120a6e
    movePoint(index - 2, dY);
Shinya Kitaoka 120a6e
    movePoint(index - 3, dY);
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
  // Punto di controllo speciale: l'ultimo visualizzato.
Shinya Kitaoka 120a6e
  if (index == pointCount - 4) {
Shinya Kitaoka 120a6e
    QPointF dY = QPointF(0, d.y());
Shinya Kitaoka 120a6e
    movePoint(index + 1, dY);
Shinya Kitaoka 120a6e
    movePoint(index + 2, dY);
Shinya Kitaoka 120a6e
    movePoint(index + 3, dY);
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
  if (index > 3) movePoint(index - 1, d);
Shinya Kitaoka 120a6e
  if (index < pointCount - 4) movePoint(index + 1, d);
Shinya Kitaoka 120a6e
  movePoint(index, d);
Shinya Kitaoka 120a6e
  emit controlPointChanged(true);
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
void ChennelCurveEditor::addControlPoint(double percent) {
Shinya Kitaoka 120a6e
  QPainterPath path = getPainterPath();
Shinya Kitaoka 120a6e
  QPointF p         = path.pointAtPercent(percent);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  // Cerco il punto di controllo precedente
Shinya Kitaoka 120a6e
  int pointCount = m_points.size();
Shinya Kitaoka 120a6e
  int beforeControlPointIndex;
Shinya Kitaoka 120a6e
  for (beforeControlPointIndex = pointCount - 1; beforeControlPointIndex >= 0;
Shinya Kitaoka 120a6e
       beforeControlPointIndex--) {
Shinya Kitaoka 120a6e
    QPointF point = m_points.at(beforeControlPointIndex);
Shinya Kitaoka 120a6e
    if (isCentralControlPoint(beforeControlPointIndex) && point.x() < p.x())
Shinya Kitaoka 120a6e
      break;
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  if (beforeControlPointIndex == 0 || beforeControlPointIndex == pointCount - 4)
Shinya Kitaoka 120a6e
    return;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  QPointF p0 = checkPoint(m_points.at(beforeControlPointIndex));
Shinya Kitaoka 120a6e
  // Se sono troppo vicino al punto di controllo precedente ritorno
Rozhuk Ivan 823a31
  if (std::abs(p.x() - p0.x()) <= cpMargin) return;
Shinya Kitaoka 120a6e
  double beforeControlPointPercent = getPercentAtPoint(p0, path);
Shinya Kitaoka 120a6e
  QPointF p1 = checkPoint(m_points.at(beforeControlPointIndex + 1));
Shinya Kitaoka 120a6e
  QPointF p2 = checkPoint(m_points.at(beforeControlPointIndex + 2));
Shinya Kitaoka 120a6e
  QPointF p3 = checkPoint(m_points.at(beforeControlPointIndex + 3));
Shinya Kitaoka 120a6e
  // Se sono troppo vicino al punto di controllo successivo ritorno
Rozhuk Ivan 823a31
  if (std::abs(p3.x() - p.x()) <= cpMargin) return;
Shinya Kitaoka 120a6e
  double nextControlPointPercent = getPercentAtPoint(p3, path);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  // Calcolo la velocita' e quindi il coiffciente angolare.
Shinya Kitaoka 120a6e
  double t =
Shinya Kitaoka 120a6e
      percent * 100 / (nextControlPointPercent - beforeControlPointPercent);
Shinya Kitaoka 120a6e
  double s = t - 1;
Shinya Kitaoka 120a6e
  QPointF speed =
Shinya Kitaoka 120a6e
      3.0 * ((p1 - p0) * s * s + 2 * (p2 - p0) * s * t + (p3 - p2) * t * t);
Shinya Kitaoka 120a6e
  double m = speed.y() / speed.x();
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  int newControlPointIndex = beforeControlPointIndex + 3;
Shinya Kitaoka 120a6e
  m_points.insert(newControlPointIndex - 1,
Shinya Kitaoka 120a6e
                  QPointF(p.x() - 16, p.y() - 16 * m));
Shinya Kitaoka 120a6e
  m_points.insert(newControlPointIndex, p);
Shinya Kitaoka 120a6e
  m_points.insert(newControlPointIndex + 1,
Shinya Kitaoka 120a6e
                  QPointF(p.x() + 16, p.y() + 16 * m));
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  m_currentControlPointIndex = newControlPointIndex;
shun-iwasawa 0ed559
  m_preMousePos              = p;
Shinya Kitaoka 120a6e
  emit controlPointAdded(newControlPointIndex);
Shinya Kitaoka 120a6e
  update();
Shinya Kitaoka 120a6e
}
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
//-----------------------------------------------------------------------------
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
void ChennelCurveEditor::removeCurrentControlPoint() {
Shinya Kitaoka 120a6e
  removeControlPoint(m_currentControlPointIndex);
Shinya Kitaoka 120a6e
}
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
//-----------------------------------------------------------------------------
Shinya Kitaoka 120a6e
shun-iwasawa 0ed559
void ChennelCurveEditor::selectNextControlPoint() {
Martin van Zijl 9c0391
  int controlPointCount = (int)m_points.size();
Martin van Zijl 9c0391
shun-iwasawa 0ed559
  if (controlPointCount == 0) return;
Martin van Zijl 9c0391
Martin van Zijl 9c0391
  int firstVisibleControlPoint = 3;
shun-iwasawa 0ed559
  int lastVisibleControlPoint  = m_points.size() - 4;
Martin van Zijl 9c0391
Martin van Zijl 9c0391
  m_currentControlPointIndex++;
shun-iwasawa 0ed559
  if (m_currentControlPointIndex < firstVisibleControlPoint ||
shun-iwasawa 0ed559
      m_currentControlPointIndex > lastVisibleControlPoint)
Martin van Zijl 9c0391
    m_currentControlPointIndex = firstVisibleControlPoint;
Martin van Zijl 9c0391
shun-iwasawa 0ed559
  emit updateCurrentPosition(m_currentControlPointIndex,
shun-iwasawa 0ed559
                             m_points.at(m_currentControlPointIndex));
Martin van Zijl 9c0391
  update();
Martin van Zijl 9c0391
}
Martin van Zijl 9c0391
Martin van Zijl 9c0391
//-----------------------------------------------------------------------------
Martin van Zijl 9c0391
shun-iwasawa 0ed559
void ChennelCurveEditor::selectPreviousControlPoint() {
Martin van Zijl 9c0391
  int controlPointCount = (int)m_points.size();
Martin van Zijl 9c0391
shun-iwasawa 0ed559
  if (controlPointCount == 0) return;
Martin van Zijl 9c0391
Martin van Zijl 9c0391
  int firstVisibleControlPoint = 3;
shun-iwasawa 0ed559
  int lastVisibleControlPoint  = m_points.size() - 4;
Martin van Zijl 9c0391
Martin van Zijl 9c0391
  m_currentControlPointIndex--;
shun-iwasawa 0ed559
  if (m_currentControlPointIndex < firstVisibleControlPoint ||
shun-iwasawa 0ed559
      m_currentControlPointIndex > lastVisibleControlPoint)
Martin van Zijl 9c0391
    m_currentControlPointIndex = lastVisibleControlPoint;
Martin van Zijl 9c0391
shun-iwasawa 0ed559
  emit updateCurrentPosition(m_currentControlPointIndex,
shun-iwasawa 0ed559
                             m_points.at(m_currentControlPointIndex));
Martin van Zijl 9c0391
  update();
Martin van Zijl 9c0391
}
Martin van Zijl 9c0391
Martin van Zijl 9c0391
//-----------------------------------------------------------------------------
Martin van Zijl 9c0391
Shinya Kitaoka 120a6e
void ChennelCurveEditor::removeControlPoint(int index) {
Shinya Kitaoka 120a6e
  // Non posso eliminare il primo punto di controllo visibile quindi lo rimetto
Shinya Kitaoka 120a6e
  // in condizione iniziale
Shinya Kitaoka 120a6e
  if (index <= 4) {
shun-iwasawa 0ed559
    setPoint(0, QPointF(-40, 0));
shun-iwasawa 0ed559
    setPoint(1, QPointF(-20, 0));
shun-iwasawa 0ed559
    setPoint(2, QPointF(-20, 0));
shun-iwasawa 0ed559
    setPoint(3, QPointF(0, 0));
shun-iwasawa 0ed559
    setPoint(4, QPointF(16, 16));
Shinya Kitaoka 120a6e
    update();
Shinya Kitaoka 120a6e
    emit controlPointChanged(false);
Shinya Kitaoka 120a6e
    return;
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
  // Non posso eliminare il l'ultimo punto di controllo visibile quindi lo
Shinya Kitaoka 120a6e
  // rimetto in condizione iniziale
Shinya Kitaoka 120a6e
  if (index >= m_points.size() - 5) {
Shinya Kitaoka 120a6e
    int i = m_points.size() - 5;
shun-iwasawa 0ed559
    setPoint(i, QPointF(239, 239));
shun-iwasawa 0ed559
    setPoint(i + 1, QPointF(255, 255));
shun-iwasawa 0ed559
    setPoint(i + 2, QPointF(275, 255));
shun-iwasawa 0ed559
    setPoint(i + 3, QPointF(275, 255));
shun-iwasawa 0ed559
    setPoint(i + 4, QPointF(295, 255));
Shinya Kitaoka 120a6e
    update();
Shinya Kitaoka 120a6e
    emit controlPointChanged(false);
Shinya Kitaoka 120a6e
    return;
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  int firstIndex = 0;
Shinya Kitaoka 120a6e
  if (isCentralControlPoint(index))
Shinya Kitaoka 120a6e
    firstIndex = index - 1;
Shinya Kitaoka 120a6e
  else if (isLeftControlPoint(index))
Shinya Kitaoka 120a6e
    firstIndex = index;
Shinya Kitaoka 120a6e
  else
Shinya Kitaoka 120a6e
    firstIndex = index - 2;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  m_points.removeAt(firstIndex);
Shinya Kitaoka 120a6e
  m_points.removeAt(firstIndex);
Shinya Kitaoka 120a6e
  m_points.removeAt(firstIndex);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  emit controlPointRemoved(firstIndex + 1);
Shinya Kitaoka 120a6e
  m_currentControlPointIndex = firstIndex - 2;
shun-iwasawa 0ed559
shun-iwasawa 0ed559
  emit updateCurrentPosition(m_currentControlPointIndex,
shun-iwasawa 0ed559
                             m_points.at(m_currentControlPointIndex));
shun-iwasawa 0ed559
Shinya Kitaoka 120a6e
  update();
Shinya Kitaoka 120a6e
}
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
//-----------------------------------------------------------------------------
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
QPainterPath ChennelCurveEditor::getPainterPath() {
Shinya Kitaoka 120a6e
  int pointCount = m_points.size();
Shinya Kitaoka 120a6e
  if (pointCount == 0) return QPainterPath();
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  QPointF p0 = m_points.at(0);
Shinya Kitaoka 120a6e
  QPainterPath path(p0);
Shinya Kitaoka 120a6e
  int i;
Shinya Kitaoka 120a6e
  for (i = 1; i < pointCount; i++) {
Shinya Kitaoka 120a6e
    QPointF p1 = m_points.at(i);
Shinya Kitaoka 120a6e
    QPointF p2 = m_points.at(++i);
Shinya Kitaoka 120a6e
    QPointF p3 = m_points.at(++i);
Shinya Kitaoka 120a6e
    path.moveTo(p0);
shun-iwasawa 0ed559
    if (!m_isLinear) {
shun-iwasawa 0ed559
      // truncate speed
shun-iwasawa 0ed559
      QVector2D aSpeed(p1 - p0);
shun-iwasawa 0ed559
      QVector2D bSpeed(p2 - p3);
shun-iwasawa 0ed559
      truncateSpeeds(p0.x(), p3.x(), aSpeed, bSpeed);
shun-iwasawa 0ed559
      path.cubicTo(p0 + aSpeed.toPointF(), p3 + bSpeed.toPointF(), p3);
shun-iwasawa 0ed559
    } else
Shinya Kitaoka 120a6e
      path.lineTo(p3);
Shinya Kitaoka 120a6e
    p0 = p3;
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  // Cerco le eventuali intersezioni con il bordo.
shun-iwasawa 0ed559
  QRectF rect(0, 0, m_curveHeight, m_curveHeight);
shun-iwasawa 0ed559
  // QRectF rect(m_LeftRightMargin, m_TopMargin, m_curveHeight, m_curveHeight);
Shinya Kitaoka 120a6e
  QRectF r = path.boundingRect();
Shinya Kitaoka 120a6e
  if (!rect.contains(QRect(rect.left(), r.top(), rect.width(), r.height()))) {
Shinya Kitaoka 120a6e
    QList<qpointf> points = getIntersectedPoint(rect, path);</qpointf>
Shinya Kitaoka 120a6e
    // Se trovo punti di intersezione (per come e' definita la curva devono
Shinya Kitaoka 120a6e
    // essere pari)
Shinya Kitaoka 120a6e
    // faccio l'unione del path calcolato e di nuovi path lineari.
Shinya Kitaoka 120a6e
    int j = 0;
Shinya Kitaoka 120a6e
    for (j = 0; j < points.size(); j++) {
Shinya Kitaoka 120a6e
      QPointF p0 = points.at(j);
Shinya Kitaoka 120a6e
      QPointF p1 = points.at(++j);
Shinya Kitaoka 120a6e
      QPainterPath line(p0);
Shinya Kitaoka 120a6e
      line.lineTo(p1);
Shinya Kitaoka 120a6e
      path.addPath(line);
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  return path;
Shinya Kitaoka 120a6e
}
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
//-----------------------------------------------------------------------------
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
void ChennelCurveEditor::paintEvent(QPaintEvent *e) {
Shinya Kitaoka 120a6e
  QPainter painter(this);
Shinya Kitaoka 120a6e
shun-iwasawa 0ed559
  double scale = (m_isEnlarged) ? 2.0 : 1.0;
Shinya Kitaoka 120a6e
  // Disegno il reticolato
Shinya Kitaoka 120a6e
  painter.setRenderHint(QPainter::Antialiasing, false);
Shinya Kitaoka 120a6e
  painter.setPen(QColor(250, 250, 250));
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  // Disegno l'histogram.
shun-iwasawa 0ed559
  m_histogramView->draw(&painter, QPoint(m_LeftRightMargin - 10, 0),
shun-iwasawa 0ed559
                        m_curveHeight * scale);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  // Disegno la barra verticale a sinistra.
Shinya Kitaoka 120a6e
  m_verticalChannelBar->draw(
Shinya Kitaoka 120a6e
      &painter,
Shinya Kitaoka 120a6e
      QPoint(0, -2));  //-1 == m_topMargin- il margine della barra(=10+1).
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  QRectF r = rect().adjusted(m_LeftRightMargin, m_TopMargin, -m_LeftRightMargin,
Shinya Kitaoka 120a6e
                             -m_BottomMargin);
Shinya Kitaoka 120a6e
  // Disegno la curva entro i limiti del grafo
Shinya Kitaoka 120a6e
  painter.setClipRect(r, Qt::IntersectClip);
shun-iwasawa 0ed559
shun-iwasawa 0ed559
  painter.translate(m_LeftRightMargin + 1, height() - m_BottomMargin);
shun-iwasawa 0ed559
  painter.scale(scale, -scale);
shun-iwasawa 0ed559
Shinya Kitaoka 120a6e
  QPainterPath path = getPainterPath();
Shinya Kitaoka 120a6e
  if (path.isEmpty()) return;
Shinya Kitaoka 120a6e
  painter.setRenderHint(QPainter::Antialiasing, true);
shun-iwasawa 0ed559
  QPen blackPen(Qt::black);
shun-iwasawa 0ed559
  QPen bluePen(Qt::blue);
shun-iwasawa 0ed559
  blackPen.setWidthF(1.0 / scale);
shun-iwasawa 0ed559
  bluePen.setWidthF(1.0 / scale);
shun-iwasawa 0ed559
shun-iwasawa 0ed559
  painter.setPen(blackPen);
Shinya Kitaoka 120a6e
  painter.setBrush(Qt::NoBrush);
Shinya Kitaoka 120a6e
  painter.drawPath(path);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  int n     = m_points.size();
Shinya Kitaoka 120a6e
  QPointF p = m_points.at(3);
shun-iwasawa 0ed559
  for (int i = 3; i < n - 3; i++) {
Shinya Kitaoka 120a6e
    QBrush brush(Qt::white);
shun-iwasawa 0ed559
    int rad       = (m_isEnlarged) ? 1 : 2;
Shinya Kitaoka 120a6e
    QPointF nextP = m_points.at(i + 1);
Shinya Kitaoka 120a6e
    if (isCentralControlPoint(i))
shun-iwasawa 0ed559
      rad = (m_isEnlarged) ? 2 : 3;
Shinya Kitaoka 120a6e
    else if (m_isLinear) {
Shinya Kitaoka 120a6e
      p = nextP;
Shinya Kitaoka 120a6e
      continue;
Shinya Kitaoka 120a6e
    }
shun-iwasawa 0ed559
    painter.setPen(blackPen);
Shinya Kitaoka 120a6e
shun-iwasawa 0ed559
    QPointF handlePos = p;
Shinya Kitaoka 120a6e
    if (!m_isLinear) {
shun-iwasawa 0ed559
      if (isLeftControlPoint(i)) {
Shinya Kitaoka 120a6e
        painter.drawLine(p, nextP);
shun-iwasawa 0ed559
      } else if (isCentralControlPoint(i) && i < n - 4)
Shinya Kitaoka 120a6e
        painter.drawLine(p, nextP);
shun-iwasawa 0ed559
shun-iwasawa 0ed559
      handlePos = getVisibleHandlePos(i);
Shinya Kitaoka 120a6e
    }
shun-iwasawa 0ed559
shun-iwasawa 0ed559
    painter.setBrush((m_currentControlPointIndex != i)
shun-iwasawa 0ed559
                         ? Qt::white
shun-iwasawa 0ed559
                         : (p == handlePos) ? Qt::black : Qt::blue);
shun-iwasawa 0ed559
    painter.setPen((p == handlePos) ? blackPen : bluePen);
shun-iwasawa 0ed559
shun-iwasawa 0ed559
    QRectF pointRect(handlePos.x() - rad, handlePos.y() - rad, 2 * rad,
shun-iwasawa 0ed559
                     2 * rad);
shun-iwasawa 4c05e2
    painter.drawEllipse(pointRect);
Shinya Kitaoka 120a6e
    p = nextP;
Shinya Kitaoka 120a6e
  }
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
void ChennelCurveEditor::mouseMoveEvent(QMouseEvent *e) {
shun-iwasawa 0ed559
  QPointF posF = viewToStrokePoint(QPointF(e->pos()));
Shinya Kitaoka 120a6e
  if (m_mouseButton == Qt::LeftButton && m_currentControlPointIndex != -1) {
shun-iwasawa 0ed559
    moveCurrentControlPoint(posF - m_preMousePos);
shun-iwasawa 0ed559
    m_preMousePos = posF;
shun-iwasawa 0ed559
  } else if (m_currentControlPointIndex == -1)
shun-iwasawa 0ed559
    emit updateCurrentPosition(-1, posF);
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
void ChennelCurveEditor::mousePressEvent(QMouseEvent *e) {
Shinya Kitaoka 120a6e
  m_mouseButton = e->button();
Shinya Kitaoka 120a6e
  setFocus();
Shinya Kitaoka 120a6e
  if (m_mouseButton == Qt::LeftButton) {
shun-iwasawa 0ed559
    QPointF posF = viewToStrokePoint(QPointF(e->pos()));
Shinya Kitaoka 120a6e
    double minDistance;
Shinya Kitaoka 120a6e
    int controlPointIndex = getClosestPointIndex(posF, minDistance);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    // Se la distanza e' piccola seleziono il control point corrente
shun-iwasawa 0ed559
    if (minDistance < 20) {
Shinya Kitaoka 120a6e
      m_currentControlPointIndex = controlPointIndex;
shun-iwasawa 0ed559
      m_preMousePos              = posF;
shun-iwasawa 0ed559
    } else {
Shinya Kitaoka 120a6e
      m_currentControlPointIndex = -1;
Shinya Kitaoka 120a6e
      // Se sono sufficentemente lontano da un punto di controllo, ma abbastanza
Shinya Kitaoka 120a6e
      // vicino alla curva
Shinya Kitaoka 120a6e
      // aggiungo un punto di controllo
Shinya Kitaoka 120a6e
      double percent = getPercentAtPoint(posF, getPainterPath());
Shinya Kitaoka 120a6e
      if (percent != 0 && minDistance > 20) addControlPoint(percent);
Shinya Kitaoka 120a6e
    }
shun-iwasawa 0ed559
    QPointF currentPointPos = (m_currentControlPointIndex == -1)
shun-iwasawa 0ed559
                                  ? posF
shun-iwasawa 0ed559
                                  : m_points.at(m_currentControlPointIndex);
shun-iwasawa 0ed559
shun-iwasawa 0ed559
    emit updateCurrentPosition(m_currentControlPointIndex, currentPointPos);
Shinya Kitaoka 120a6e
    update();
Shinya Kitaoka 120a6e
  }
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
void ChennelCurveEditor::mouseReleaseEvent(QMouseEvent *e) {
shun-iwasawa 0ed559
  // fx preview updates here ( it does not update while mouse dragging )
Shinya Kitaoka 120a6e
  if (m_mouseButton == Qt::LeftButton && m_currentControlPointIndex != -1 &&
Shinya Kitaoka 120a6e
      e->button() == Qt::LeftButton)
Shinya Kitaoka 120a6e
    emit controlPointChanged(false);
Shinya Kitaoka 120a6e
  m_mouseButton = Qt::NoButton;
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
void ChennelCurveEditor::keyPressEvent(QKeyEvent *e) {
shun-iwasawa 0ed559
  if (m_currentControlPointIndex == -1) return;
Toshihiro Shimizu 890ddd
shun-iwasawa 0ed559
  if (e->key() == Qt::Key_Delete) {
shun-iwasawa 0ed559
    removeCurrentControlPoint();
shun-iwasawa 0ed559
    return;
shun-iwasawa 0ed559
  }
Shinya Kitaoka 120a6e
shun-iwasawa 0ed559
  bool controlPressed = e->modifiers() & Qt::ControlModifier;
shun-iwasawa 0ed559
  bool shiftPressed   = e->modifiers() & Qt::ShiftModifier;
shun-iwasawa 0ed559
  float delta         = (shiftPressed) ? 10.0 : 1.0;
Shinya Kitaoka 120a6e
shun-iwasawa 0ed559
  if (e->key() == Qt::Key_Right) {
shun-iwasawa 0ed559
    if (controlPressed)
shun-iwasawa 0ed559
      selectNextControlPoint();
shun-iwasawa 0ed559
    else
shun-iwasawa 0ed559
      moveCurrentControlPoint(QPointF(delta, 0.0));
shun-iwasawa 0ed559
  } else if (e->key() == Qt::Key_Left) {
shun-iwasawa 0ed559
    if (controlPressed)
shun-iwasawa 0ed559
      selectPreviousControlPoint();
shun-iwasawa 0ed559
    else
shun-iwasawa 0ed559
      moveCurrentControlPoint(QPointF(-delta, 0.0));
shun-iwasawa 0ed559
  } else if (e->key() == Qt::Key_Up)
shun-iwasawa 0ed559
    moveCurrentControlPoint(QPointF(0.0, delta));
shun-iwasawa 0ed559
  else if (e->key() == Qt::Key_Down)
shun-iwasawa 0ed559
    moveCurrentControlPoint(QPointF(0.0, -delta));
shun-iwasawa 0ed559
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//--------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
bool ChennelCurveEditor::eventFilter(QObject *object, QEvent *event) {
Shinya Kitaoka 120a6e
  if (event->type() == QEvent::Shortcut ||
Shinya Kitaoka 120a6e
      event->type() == QEvent::ShortcutOverride) {
Shinya Kitaoka 120a6e
    if (!object->inherits("FxSettings")) {
Shinya Kitaoka 120a6e
      event->accept();
Shinya Kitaoka 120a6e
      return true;
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
  return false;
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//--------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
void ChennelCurveEditor::focusInEvent(QFocusEvent *fe) {
Shinya Kitaoka 120a6e
  QWidget::focusInEvent(fe);
Shinya Kitaoka 120a6e
  qApp->installEventFilter(this);
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//--------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
void ChennelCurveEditor::focusOutEvent(QFocusEvent *fe) {
Shinya Kitaoka 120a6e
  emit focusOut();
Shinya Kitaoka 120a6e
  QWidget::focusOutEvent(fe);
Shinya Kitaoka 120a6e
  qApp->removeEventFilter(this);
Shinya Kitaoka 120a6e
  update();
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//=============================================================================
Toshihiro Shimizu 890ddd
// ToneCurveField
Toshihiro Shimizu 890ddd
//=============================================================================
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
ToneCurveField::ToneCurveField(QWidget *parent,
Shinya Kitaoka 120a6e
                               FxHistogramRender *fxHistogramRender)
shun-iwasawa 0ed559
    : QWidget(parent), m_toneCurveStackedWidget(0), m_currentPointIndex(-1) {
shun-iwasawa 0ed559
  setFixedWidth(400);
shun-iwasawa 0ed559
  // setFixedWidth(368);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  QStringList channels;
Shinya Kitaoka 120a6e
  channels << "RGBA"
Shinya Kitaoka 120a6e
           << "RGB"
Shinya Kitaoka 120a6e
           << "Red"
Shinya Kitaoka 120a6e
           << "Green"
Shinya Kitaoka 120a6e
           << "Blue"
Shinya Kitaoka 120a6e
           << "Alpha";
shun-iwasawa 0ed559
  int channelCount        = channels.size();
shun-iwasawa 0ed559
  int currentChannelIndex = 0;
shun-iwasawa 0ed559
shun-iwasawa 0ed559
  m_channelListChooser = new QComboBox(this);
Shinya Kitaoka 120a6e
  m_channelListChooser->setFixedSize(100, 20);
Shinya Kitaoka 120a6e
  m_channelListChooser->addItems(channels);
Shinya Kitaoka 120a6e
  m_channelListChooser->setCurrentIndex(currentChannelIndex);
shun-iwasawa 0ed559
shun-iwasawa 0ed559
  m_rangeMode = new QComboBox(this);
shun-iwasawa 0ed559
  m_rangeMode->addItems({"0-255", "0.0-1.0"});
shun-iwasawa 0ed559
  m_rangeMode->setCurrentIndex(0);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  // stack widget dei grafi
Shinya Kitaoka 120a6e
  m_toneCurveStackedWidget = new QStackedWidget(this);
Shinya Kitaoka 120a6e
  Histograms *histograms   = new Histograms(0, true);
Shinya Kitaoka 120a6e
  fxHistogramRender->setHistograms(histograms);
Shinya Kitaoka 120a6e
  int i;
Shinya Kitaoka 120a6e
  for (i = 0; i < channelCount; i++) {
Shinya Kitaoka 120a6e
    ChennelCurveEditor *c =
Shinya Kitaoka 120a6e
        new ChennelCurveEditor(this, histograms->getHistogramView(i));
Shinya Kitaoka 120a6e
    m_toneCurveStackedWidget->addWidget(c);
shun-iwasawa 0ed559
    connect(c, SIGNAL(firstLastXPostionChanged(double, double)), this,
shun-iwasawa 0ed559
            SLOT(onFirstLastXPostionChanged(double, double)));
shun-iwasawa 0ed559
    connect(c, SIGNAL(updateCurrentPosition(int, QPointF)), this,
shun-iwasawa 0ed559
            SLOT(onUpdateCurrentPosition(int, QPointF)));
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
  m_toneCurveStackedWidget->setCurrentIndex(currentChannelIndex);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  // stack widget degli slider
Shinya Kitaoka 120a6e
  m_sliderStackedWidget = new QStackedWidget(this);
Shinya Kitaoka 120a6e
  for (i = 0; i < channelCount; i++) {
shun-iwasawa 0ed559
    DoublePairField *doublePairSlider = new DoublePairField(this);
shun-iwasawa 0ed559
    doublePairSlider->setFixedHeight(20);
shun-iwasawa 0ed559
    doublePairSlider->setLabelsEnabled(false);
shun-iwasawa 0ed559
    doublePairSlider->setRange(0.0, 255.0);
shun-iwasawa 0ed559
    doublePairSlider->setValues(std::make_pair(0.0, 255.0));
shun-iwasawa 0ed559
    m_sliderStackedWidget->addWidget(doublePairSlider);
shun-iwasawa 0ed559
    connect(doublePairSlider, SIGNAL(valuesChanged(bool)), this,
Shinya Kitaoka 120a6e
            SLOT(sliderValueChanged(bool)));
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
  m_sliderStackedWidget->setCurrentIndex(currentChannelIndex);
Shinya Kitaoka 120a6e
shun-iwasawa 0ed559
  m_isLinearCheckBox   = new CheckBox(QString("Linear"), this);
shun-iwasawa 0ed559
  m_isEnlargedCheckBox = new CheckBox(QString("Enlarge"), this);
shun-iwasawa 0ed559
  m_isEnlargedCheckBox->setChecked(false);
shun-iwasawa 0ed559
  m_currentInput  = new DoubleLineEdit(this);
shun-iwasawa 0ed559
  m_currentOutput = new DoubleLineEdit(this);
shun-iwasawa 0ed559
  m_currentInput->setFixedWidth(60);
shun-iwasawa 0ed559
  m_currentOutput->setFixedWidth(60);
shun-iwasawa 0ed559
  m_currentInput->setDecimals(2);
shun-iwasawa 0ed559
  m_currentOutput->setDecimals(2);
shun-iwasawa 0ed559
  m_currentInput->setDisabled(true);
shun-iwasawa 0ed559
  m_currentOutput->setDisabled(true);
shun-iwasawa 0ed559
shun-iwasawa 0ed559
  //------ layout
shun-iwasawa 0ed559
shun-iwasawa 0ed559
  QVBoxLayout *mainLayout = new QVBoxLayout(this);
shun-iwasawa 0ed559
  mainLayout->setMargin(0);
shun-iwasawa 0ed559
  mainLayout->setSpacing(0);
shun-iwasawa 0ed559
  {
shun-iwasawa 0ed559
    QHBoxLayout *channelListLayout = new QHBoxLayout();
shun-iwasawa 0ed559
    channelListLayout->setMargin(0);
shun-iwasawa 0ed559
    channelListLayout->setSpacing(0);
shun-iwasawa 0ed559
    channelListLayout->setAlignment(Qt::AlignCenter);
shun-iwasawa 0ed559
    {
shun-iwasawa 0ed559
      // lista canali: label+comboBox
shun-iwasawa 0ed559
      channelListLayout->addWidget(new QLabel(tr("Channel:"), this));
shun-iwasawa 0ed559
      channelListLayout->addWidget(m_channelListChooser);
shun-iwasawa 0ed559
      channelListLayout->addSpacing(20);
shun-iwasawa 0ed559
      channelListLayout->addWidget(new QLabel(tr("Range:"), this));
shun-iwasawa 0ed559
      channelListLayout->addWidget(m_rangeMode);
shun-iwasawa 0ed559
      channelListLayout->addSpacing(20);
shun-iwasawa 0ed559
      channelListLayout->addWidget(m_isEnlargedCheckBox);
shun-iwasawa 0ed559
    }
shun-iwasawa 0ed559
    mainLayout->addLayout(channelListLayout, 0);
shun-iwasawa 0ed559
shun-iwasawa 0ed559
    QGridLayout *bottomLayout = new QGridLayout();
shun-iwasawa 0ed559
    bottomLayout->setMargin(0);
shun-iwasawa 0ed559
    bottomLayout->setHorizontalSpacing(5);
shun-iwasawa 0ed559
    bottomLayout->setVerticalSpacing(0);
shun-iwasawa 0ed559
    {
shun-iwasawa 0ed559
      QVBoxLayout *currentValLayout = new QVBoxLayout();
shun-iwasawa 0ed559
      currentValLayout->setMargin(0);
shun-iwasawa 0ed559
      currentValLayout->setSpacing(0);
shun-iwasawa 0ed559
      currentValLayout->setAlignment(Qt::AlignLeft);
shun-iwasawa 0ed559
      {
shun-iwasawa 0ed559
        currentValLayout->addStretch(1);
shun-iwasawa 0ed559
        currentValLayout->addWidget(new QLabel(tr("Output:"), this));
shun-iwasawa 0ed559
        currentValLayout->addWidget(m_currentOutput);
shun-iwasawa 0ed559
        currentValLayout->addSpacing(10);
shun-iwasawa 0ed559
        currentValLayout->addWidget(new QLabel(tr("Input:"), this));
shun-iwasawa 0ed559
        currentValLayout->addWidget(m_currentInput);
shun-iwasawa 0ed559
        currentValLayout->addSpacing(10);
shun-iwasawa 0ed559
      }
shun-iwasawa 0ed559
      bottomLayout->addLayout(currentValLayout, 0, 0);
shun-iwasawa 0ed559
shun-iwasawa 0ed559
      bottomLayout->addWidget(m_toneCurveStackedWidget, 0, 1, Qt::AlignHCenter);
shun-iwasawa 0ed559
      bottomLayout->addWidget(m_sliderStackedWidget, 1, 1);
shun-iwasawa 0ed559
    }
shun-iwasawa 0ed559
    bottomLayout->setColumnStretch(1, 1);
shun-iwasawa 0ed559
    bottomLayout->setRowStretch(0, 1);
shun-iwasawa 0ed559
shun-iwasawa 0ed559
    mainLayout->addLayout(bottomLayout);
shun-iwasawa 0ed559
    mainLayout->addSpacing(10);
shun-iwasawa 0ed559
    mainLayout->addWidget(m_isLinearCheckBox, 0, Qt::AlignHCenter);
shun-iwasawa 0ed559
  }
shun-iwasawa 0ed559
  setLayout(mainLayout);
shun-iwasawa 0ed559
Shinya Kitaoka 120a6e
  connect(m_isLinearCheckBox, SIGNAL(clicked(bool)),
Shinya Kitaoka 120a6e
          SLOT(setLinearManually(bool)));
Shinya Kitaoka 120a6e
  connect(m_isLinearCheckBox, SIGNAL(toggled(bool)), SLOT(setLinear(bool)));
shun-iwasawa 0ed559
  connect(m_isEnlargedCheckBox, SIGNAL(toggled(bool)), SLOT(setEnlarged(bool)));
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  connect(m_channelListChooser, SIGNAL(currentIndexChanged(int)), this,
shun-iwasawa 0ed559
          SLOT(onCurrentChannelSwitched(int)));
shun-iwasawa 0ed559
  connect(m_rangeMode, SIGNAL(currentIndexChanged(int)), this,
shun-iwasawa 0ed559
          SLOT(onRangeModeSwitched(int)));
shun-iwasawa 0ed559
  connect(m_currentInput, SIGNAL(editingFinished()), this,
shun-iwasawa 0ed559
          SLOT(onCurrentPointEditted()));
shun-iwasawa 0ed559
  connect(m_currentOutput, SIGNAL(editingFinished()), this,
shun-iwasawa 0ed559
          SLOT(onCurrentPointEditted()));
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
void ToneCurveField::setCurrentChannel(int currentChannel) {
Shinya Kitaoka 120a6e
  m_channelListChooser->setCurrentIndex(currentChannel);
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
ChennelCurveEditor *ToneCurveField::getChannelEditor(int channel) const {
Shinya Kitaoka 120a6e
  ChennelCurveEditor *c = dynamic_cast<chennelcurveeditor *="">(</chennelcurveeditor>
Shinya Kitaoka 120a6e
      m_toneCurveStackedWidget->widget(channel));
Shinya Kitaoka 120a6e
  assert(c);
Shinya Kitaoka 120a6e
  return c;
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
ChennelCurveEditor *ToneCurveField::getCurrentChannelEditor() const {
Shinya Kitaoka 120a6e
  return getChannelEditor(m_toneCurveStackedWidget->currentIndex());
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
shun-iwasawa 0ed559
DoublePairField *ToneCurveField::getCurrentSlider() const {
shun-iwasawa 0ed559
  return dynamic_cast<doublepairfield *="">(</doublepairfield>
shun-iwasawa 0ed559
      m_sliderStackedWidget->currentWidget());
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
void ToneCurveField::sliderValueChanged(bool isDragging) {
shun-iwasawa 0ed559
  std::pair<double, double=""> values = getCurrentSlider()->getValues();</double,>
shun-iwasawa 0ed559
shun-iwasawa 0ed559
  if (m_rangeMode->currentIndex() == 1) {
shun-iwasawa 0ed559
    values.first *= 255.0;
shun-iwasawa 0ed559
    values.second *= 255.0;
shun-iwasawa 0ed559
  }
shun-iwasawa 0ed559
Shinya Kitaoka 120a6e
  getCurrentChannelEditor()->setFirstLastXPosition(values, isDragging);
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
shun-iwasawa 0ed559
void ToneCurveField::onFirstLastXPostionChanged(double x0, double x1) {
shun-iwasawa 0ed559
  if (m_rangeMode->currentIndex() == 1) {
shun-iwasawa 0ed559
    x0 /= 255.0;
shun-iwasawa 0ed559
    x1 /= 255.0;
shun-iwasawa 0ed559
  }
shun-iwasawa 0ed559
  std::pair<double, double=""> values = getCurrentSlider()->getValues();</double,>
Shinya Kitaoka 120a6e
  if (values.first != x0 || values.second != x1)
Shinya Kitaoka 120a6e
    getCurrentSlider()->setValues(std::make_pair(x0, x1));
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
shun-iwasawa 0ed559
// index = -1 when no point is selected
shun-iwasawa 0ed559
void ToneCurveField::onUpdateCurrentPosition(int index, QPointF pos) {
shun-iwasawa 0ed559
  auto modify = [&](double val) {
shun-iwasawa 0ed559
    return (m_rangeMode->currentIndex() == 0) ? val : val / 255.0;
shun-iwasawa 0ed559
  };
shun-iwasawa 0ed559
shun-iwasawa 0ed559
  QList<tpointd> points = getCurrentChannelEditor()->getPoints();</tpointd>
shun-iwasawa 0ed559
  assert(index == -1 || (index >= 3 && index < points.size() - 3));
shun-iwasawa 0ed559
  if (index != -1 && (index < 3 || index >= points.size() - 3)) return;
shun-iwasawa 0ed559
shun-iwasawa 0ed559
  double maxChanVal = 255.0;
shun-iwasawa 0ed559
shun-iwasawa 0ed559
  // if no point is selected
shun-iwasawa 0ed559
  if (index == -1) {
shun-iwasawa 0ed559
    if (m_currentPointIndex != index) {
shun-iwasawa 0ed559
      m_currentInput->setDisabled(true);
shun-iwasawa 0ed559
      m_currentOutput->setDisabled(true);
shun-iwasawa 0ed559
      m_currentInput->setRange(-(std::numeric_limits<double>::max)(),</double>
shun-iwasawa 0ed559
                               (std::numeric_limits<double>::max)());</double>
shun-iwasawa 0ed559
      m_currentOutput->setRange(-(std::numeric_limits<double>::max)(),</double>
shun-iwasawa 0ed559
                                (std::numeric_limits<double>::max)());</double>
shun-iwasawa 0ed559
      m_currentPointIndex = index;
shun-iwasawa 0ed559
    }
shun-iwasawa 0ed559
    if (pos.x() < 0.0 || pos.x() > maxChanVal || pos.y() < 0.0 ||
shun-iwasawa 0ed559
        pos.y() > maxChanVal) {
shun-iwasawa 0ed559
      m_currentInput->setText("");
shun-iwasawa 0ed559
      m_currentOutput->setText("");
shun-iwasawa 0ed559
    } else {
shun-iwasawa 0ed559
      m_currentInput->setValue(modify(pos.x()));
shun-iwasawa 0ed559
      m_currentOutput->setValue(modify(pos.y()));
shun-iwasawa 0ed559
    }
shun-iwasawa 0ed559
  } else {  // if any point is selected
shun-iwasawa 0ed559
    if (m_currentPointIndex != index) {
shun-iwasawa 0ed559
      m_currentInput->setEnabled(true);
shun-iwasawa 0ed559
      m_currentOutput->setEnabled(true);
shun-iwasawa 0ed559
      if (index % 3 == 0) {  // control point case
shun-iwasawa 0ed559
        // 前後のポイントと4離す
shun-iwasawa 0ed559
        double xmin = (index == 3) ? 0 : points.at(index - 3).x + cpMargin;
shun-iwasawa 0ed559
        double xmax = (index == points.size() - 4)
shun-iwasawa 0ed559
                          ? maxChanVal
shun-iwasawa 0ed559
                          : points.at(index + 3).x - cpMargin;
shun-iwasawa 0ed559
        m_currentInput->setRange(modify(xmin), modify(xmax));
shun-iwasawa 0ed559
        m_currentOutput->setRange(0.0, modify(maxChanVal));
shun-iwasawa 0ed559
      } else if (index % 3 == 2) {  // left handle
shun-iwasawa 0ed559
        TPointD cp = points.at(index + 1);
shun-iwasawa 0ed559
        m_currentInput->setRange(-(std::numeric_limits<double>::max)(),</double>
shun-iwasawa 0ed559
                                 modify(cp.x));
shun-iwasawa 0ed559
        m_currentOutput->setRange(-(std::numeric_limits<double>::max)(),</double>
shun-iwasawa 0ed559
                                  (std::numeric_limits<double>::max)());</double>
shun-iwasawa 0ed559
      } else {  // right handle
shun-iwasawa 0ed559
        TPointD cp = points.at(index - 1);
shun-iwasawa 0ed559
        m_currentInput->setRange(modify(cp.x),
shun-iwasawa 0ed559
                                 (std::numeric_limits<double>::max)());</double>
shun-iwasawa 0ed559
        m_currentOutput->setRange(-(std::numeric_limits<double>::max)(),</double>
shun-iwasawa 0ed559
                                  (std::numeric_limits<double>::max)());</double>
shun-iwasawa 0ed559
      }
shun-iwasawa 0ed559
      m_currentPointIndex = index;
shun-iwasawa 0ed559
    }
shun-iwasawa 0ed559
    m_currentInput->setValue(modify(pos.x()));
shun-iwasawa 0ed559
    m_currentOutput->setValue(modify(pos.y()));
shun-iwasawa 0ed559
  }
shun-iwasawa 0ed559
}
shun-iwasawa 0ed559
shun-iwasawa 0ed559
//-----------------------------------------------------------------------------
shun-iwasawa 0ed559
shun-iwasawa 0ed559
void ToneCurveField::onCurrentPointEditted() {
shun-iwasawa 0ed559
  TPointD oldPos =
shun-iwasawa 0ed559
      getCurrentChannelEditor()->getPoints().at(m_currentPointIndex);
shun-iwasawa 0ed559
  double factor = (m_rangeMode->currentIndex() == 0) ? 1.0 : 255.0;
shun-iwasawa 0ed559
  QPointF newPos(m_currentInput->getValue() * factor,
shun-iwasawa 0ed559
                 m_currentOutput->getValue() * factor);
shun-iwasawa 0ed559
  getCurrentChannelEditor()->moveCurrentControlPoint(
shun-iwasawa 0ed559
      newPos - QPointF(oldPos.x, oldPos.y));
shun-iwasawa 0ed559
}
shun-iwasawa 0ed559
shun-iwasawa 0ed559
//-----------------------------------------------------------------------------
shun-iwasawa 0ed559
shun-iwasawa 0ed559
void ToneCurveField::onCurrentChannelSwitched(int channelIndex) {
shun-iwasawa 0ed559
  getCurrentChannelEditor()->setCurrentControlPointIndex(-1);
shun-iwasawa 0ed559
  m_toneCurveStackedWidget->setCurrentIndex(channelIndex);
shun-iwasawa 0ed559
  m_sliderStackedWidget->setCurrentIndex(channelIndex);
shun-iwasawa 0ed559
  emit currentChannelIndexChanged(channelIndex);
shun-iwasawa 0ed559
  onUpdateCurrentPosition(-1, QPointF(-1, -1));
shun-iwasawa 0ed559
}
shun-iwasawa 0ed559
shun-iwasawa 0ed559
//-----------------------------------------------------------------------------
shun-iwasawa 0ed559
shun-iwasawa 0ed559
void ToneCurveField::onRangeModeSwitched(int index) {
shun-iwasawa 0ed559
  double maxVal = (index == 0) ? 255.0 : 1.0;
shun-iwasawa 0ed559
  double factor = (index == 0) ? 255.0 : 1.0 / 255.0;
shun-iwasawa 0ed559
  ChannelBar::Range range =
shun-iwasawa 0ed559
      (index == 0) ? ChannelBar::Range_0_255 : ChannelBar::Range_0_1;
shun-iwasawa 0ed559
shun-iwasawa 0ed559
  for (int i = 0; i < m_toneCurveStackedWidget->count(); i++) {
shun-iwasawa 0ed559
    ChennelCurveEditor *c =
shun-iwasawa 0ed559
        dynamic_cast<chennelcurveeditor *="">(m_toneCurveStackedWidget->widget(i));</chennelcurveeditor>
shun-iwasawa 0ed559
    if (c) c->setLabelRange(range);
shun-iwasawa 0ed559
shun-iwasawa 0ed559
    DoublePairField *doublePairSlider =
shun-iwasawa 0ed559
        dynamic_cast<doublepairfield *="">(m_sliderStackedWidget->widget(i));</doublepairfield>
shun-iwasawa 0ed559
    if (doublePairSlider) {
shun-iwasawa 0ed559
      doublePairSlider->setRange(0.0, maxVal);
shun-iwasawa 0ed559
      std::pair<double, double=""> val = doublePairSlider->getValues();</double,>
shun-iwasawa 0ed559
      doublePairSlider->setValues(
shun-iwasawa 0ed559
          std::make_pair(val.first * factor, val.second * factor));
shun-iwasawa 0ed559
    }
shun-iwasawa 0ed559
  }
shun-iwasawa 0ed559
shun-iwasawa 0ed559
  if (m_currentPointIndex == -1) return;
shun-iwasawa 0ed559
shun-iwasawa 0ed559
  int pointIndex = m_currentPointIndex;
shun-iwasawa 0ed559
  // in order to force updating the value range
shun-iwasawa 0ed559
  m_currentPointIndex = -1;
shun-iwasawa 0ed559
  TPointD point       = getCurrentChannelEditor()->getPoints().at(pointIndex);
shun-iwasawa 0ed559
  onUpdateCurrentPosition(pointIndex, QPointF(point.x, point.y));
shun-iwasawa 0ed559
}
shun-iwasawa 0ed559
shun-iwasawa 0ed559
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
void ToneCurveField::setIsLinearCheckBox(bool isChecked) {
Shinya Kitaoka 120a6e
  if (m_isLinearCheckBox->isChecked() == isChecked) return;
Shinya Kitaoka 120a6e
  m_isLinearCheckBox->setChecked(isChecked);
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
void ToneCurveField::setLinear(bool isLinear) {
Shinya Kitaoka 120a6e
  int i;
Shinya Kitaoka 120a6e
  for (i = 0; i < m_sliderStackedWidget->count(); i++)
Shinya Kitaoka 120a6e
    getChannelEditor(i)->setLinear(isLinear);
Shinya Kitaoka 120a6e
}
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
//-----------------------------------------------------------------------------
Shinya Kitaoka 120a6e
shun-iwasawa 0ed559
void ToneCurveField::setEnlarged(bool isEnlarged) {
shun-iwasawa 0ed559
  int i;
shun-iwasawa 0ed559
  for (i = 0; i < m_sliderStackedWidget->count(); i++)
shun-iwasawa 0ed559
    getChannelEditor(i)->setEnlarged(isEnlarged);
shun-iwasawa 0ed559
  setFixedWidth((isEnlarged) ? 400 + 256 : 400);
shun-iwasawa 0ed559
  emit sizeChanged();
shun-iwasawa 0ed559
}
shun-iwasawa 0ed559
shun-iwasawa 0ed559
//-----------------------------------------------------------------------------
shun-iwasawa 0ed559
Shinya Kitaoka 120a6e
void ToneCurveField::setLinearManually(bool isLinear) {
Shinya Kitaoka 120a6e
  emit isLinearChanged(isLinear);
Toshihiro Shimizu 890ddd
}
shun-iwasawa 0ed559
shun-iwasawa 0ed559
//-----------------------------------------------------------------------------
shun-iwasawa 0ed559
shun-iwasawa 0ed559
bool ToneCurveField::isEnlarged() { return m_isEnlargedCheckBox->isChecked(); }