Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
#include "toonzqt/tonecurvefield.h"
Toshihiro Shimizu 890ddd
#include "toonzqt/fxhistogramrender.h"
Toshihiro Shimizu 890ddd
#include "toonzqt/intpairfield.h"
Toshihiro Shimizu 890ddd
#include "toonzqt/checkbox.h"
Toshihiro Shimizu 890ddd
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 {
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);
Shinya Kitaoka 120a6e
    if (abs(pathPoint.x() - point.x()) < 3 &&
Shinya Kitaoka 120a6e
        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 qtNorm(const QPointF &p) { return sqrt(qtNorm2(p)); }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
QPointF qtNormalize(const QPointF &p) {
Shinya Kitaoka 120a6e
  double n = qtNorm(p);
Shinya Kitaoka 120a6e
  assert(n != 0.0);
Shinya Kitaoka 120a6e
  return (1.0 / n) * p;
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
double qtDistance2(const QPointF &p1, const QPointF &p2) {
Shinya Kitaoka 120a6e
  return qtNorm2(p2 - p1);
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
double qtDistance(const QPointF &p1, const QPointF &p2) {
Shinya Kitaoka 120a6e
  return qtNorm(p2 - p1);
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
QPointF getNewFirstHandlePoint(const QPointF &p, const QPointF &nextP,
Shinya Kitaoka 120a6e
                               const QPointF &oldHandlePoint) {
Shinya Kitaoka 120a6e
  bool canMove  = (nextP.x() - p.x() > 16);
Shinya Kitaoka 120a6e
  int yDistance = nextP.y() - p.y();
Shinya Kitaoka 120a6e
  double sign   = (yDistance != 0) ? yDistance / abs(yDistance) : 1;
Shinya Kitaoka 120a6e
  double t      = qtDistance(p, oldHandlePoint);
Shinya Kitaoka 120a6e
  if (!canMove) {
Shinya Kitaoka 120a6e
    QPointF normalizedP =
Shinya Kitaoka 120a6e
        (yDistance != 0) ? qtNormalize(nextP - p) : QPoint(1, 1);
Shinya Kitaoka 120a6e
    return QPointF(p + QPointF(t * normalizedP));
Shinya Kitaoka 120a6e
  } else if (abs(oldHandlePoint.x() - p.x()) < 16)
Shinya Kitaoka 120a6e
    return QPointF(p.x() + 16, p.y() + sign * sqrt(t * t - 16 * 16));
Shinya Kitaoka 120a6e
  return oldHandlePoint;
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
QPointF getNewSecondHandlePoint(const QPointF &p, const QPointF &nextP,
Shinya Kitaoka 120a6e
                                const QPointF &oldHandlePoint) {
Shinya Kitaoka 120a6e
  bool canMove  = (nextP.x() - p.x() > 16);
Shinya Kitaoka 120a6e
  int yDistance = p.y() - nextP.y();
Shinya Kitaoka 120a6e
  double sign   = (yDistance != 0) ? yDistance / abs(yDistance) : 1;
Shinya Kitaoka 120a6e
  double s      = qtDistance(oldHandlePoint, nextP);
Shinya Kitaoka 120a6e
  if (!canMove) {
Shinya Kitaoka 120a6e
    QPointF normalizedP =
Shinya Kitaoka 120a6e
        (yDistance != 0) ? qtNormalize(nextP - p) : QPoint(1, 1);
Shinya Kitaoka 120a6e
    return QPointF(nextP - QPointF(s * normalizedP));
Shinya Kitaoka 120a6e
  } else if (abs(nextP.x() - oldHandlePoint.x()) < 16)
Shinya Kitaoka 120a6e
    return QPointF(nextP.x() - 16, nextP.y() + sign * sqrt(s * s - 16 * 16));
Shinya Kitaoka 120a6e
  return oldHandlePoint;
Toshihiro Shimizu 890ddd
}
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)
Shinya Kitaoka 120a6e
    , m_isLinear(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();
Shinya Kitaoka 120a6e
  int i;
Shinya Kitaoka 120a6e
  for (i = 0; i < points.size(); i++) {
Shinya Kitaoka 120a6e
    QPointF p = strokeToViewPoint(points.at(i));
Shinya Kitaoka 120a6e
    m_points.push_back(p);
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
  /*--ポイント位置に合わせてスライダも更新する--*/
Shinya Kitaoka 120a6e
  int firstIndex = 3;
Shinya Kitaoka 120a6e
  int lastIndex  = m_points.size() - 4;
Shinya Kitaoka 120a6e
  emit firstLastXPostionChanged(viewToStrokePoint(m_points.at(firstIndex)).x,
Shinya Kitaoka 120a6e
                                viewToStrokePoint(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;
Shinya Kitaoka 120a6e
  int i;
Shinya Kitaoka 120a6e
  for (i = 0; i < m_points.size(); i++)
Shinya Kitaoka 120a6e
    points.push_back(viewToStrokePoint(m_points.at(i)));
Shinya Kitaoka 120a6e
  return points;
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
void ChennelCurveEditor::setFirstLastXPosition(std::pair<int, int=""> values,</int,>
Shinya Kitaoka 120a6e
                                               bool isDragging) {
Shinya Kitaoka 120a6e
  if (!isDragging) {
Shinya Kitaoka 120a6e
    emit controlPointChanged(false);
Shinya Kitaoka 120a6e
    return;
Shinya Kitaoka 120a6e
  }
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  QPointF newX0 = strokeToViewPoint(TPointD(values.first, 0));
Shinya Kitaoka 120a6e
  QPointF newX1 = strokeToViewPoint(TPointD(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;
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
Shinya Kitaoka 120a6e
QPointF ChennelCurveEditor::checkPoint(const QPointF p) {
Shinya Kitaoka 120a6e
  QPointF checkedP         = p;
Shinya Kitaoka 120a6e
  int y0                   = m_TopMargin + 1;
Shinya Kitaoka 120a6e
  int y1                   = m_curveHeight + m_TopMargin;
Shinya Kitaoka 120a6e
  if (p.y() < y0) checkedP = QPointF(checkedP.x(), y0);
Shinya Kitaoka 120a6e
  if (p.y() > y1) checkedP = QPointF(checkedP.x(), y1);
Shinya Kitaoka 120a6e
  int x0                   = m_LeftRightMargin + 1;
Shinya Kitaoka 120a6e
  int x1                   = m_curveHeight + m_LeftRightMargin;
Shinya Kitaoka 120a6e
  if (p.x() < x0) checkedP = QPointF(x0, checkedP.y());
Shinya Kitaoka 120a6e
  if (p.x() > x1) checkedP = QPointF(x1, checkedP.y());
Shinya Kitaoka 120a6e
  return checkedP;
Shinya Kitaoka 120a6e
}
Shinya Kitaoka 120a6e
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
QPointF ChennelCurveEditor::strokeToViewPoint(const TPointD p) {
Shinya Kitaoka 120a6e
  double x = p.x + m_LeftRightMargin + 1;
Shinya Kitaoka 120a6e
  double y = height() - m_BottomMargin - p.y;
Shinya Kitaoka 120a6e
  return QPointF(x, y);
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
TPointD ChennelCurveEditor::viewToStrokePoint(const QPointF &p) {
Shinya Kitaoka 120a6e
  double x = p.x() - m_LeftRightMargin - 1;
Shinya Kitaoka 120a6e
  double y = m_curveHeight - (p.y() - m_TopMargin);
Shinya Kitaoka 120a6e
  return TThickPoint(x, 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;
Shinya Kitaoka 120a6e
  int i;
Shinya Kitaoka 120a6e
  for (i = 0; i < (int)m_points.size(); i++) {
Shinya Kitaoka 120a6e
    double distance2 = qtDistance2(pos, m_points.at(i));
Shinya Kitaoka 120a6e
    if (closestPointIndex < 0 || distance2 < minDistance2) {
Shinya Kitaoka 120a6e
      minDistance2      = distance2;
Shinya Kitaoka 120a6e
      closestPointIndex = i;
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)
Shinya Kitaoka 120a6e
    emit firstLastXPostionChanged(viewToStrokePoint(p).x,
Shinya Kitaoka 120a6e
                                  viewToStrokePoint(m_points.at(lastIndex)).x);
Shinya Kitaoka 120a6e
  if (index == lastIndex)
Shinya Kitaoka 120a6e
    emit firstLastXPostionChanged(viewToStrokePoint(m_points.at(firstIndex)).x,
Shinya Kitaoka 120a6e
                                  viewToStrokePoint(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)
Shinya Kitaoka 120a6e
    emit firstLastXPostionChanged(viewToStrokePoint(p).x,
Shinya Kitaoka 120a6e
                                  viewToStrokePoint(m_points.at(lastIndex)).x);
Shinya Kitaoka 120a6e
  if (index == lastIndex)
Shinya Kitaoka 120a6e
    emit firstLastXPostionChanged(viewToStrokePoint(m_points.at(firstIndex)).x,
Shinya Kitaoka 120a6e
                                  viewToStrokePoint(p).x);
Shinya Kitaoka 120a6e
}
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
//-----------------------------------------------------------------------------
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
void ChennelCurveEditor::moveCurrentControlPoint(const QPointF delta) {
Shinya Kitaoka 120a6e
  assert(m_currentControlPointIndex != -1);
Shinya Kitaoka 120a6e
  int pointCount = m_points.size();
Shinya Kitaoka 120a6e
  /*- セグメントを動かした場合 -*/
Shinya Kitaoka 120a6e
  if (isCentralControlPoint(m_currentControlPointIndex))
Shinya Kitaoka 120a6e
    moveCentralControlPoint(m_currentControlPointIndex, delta);
Shinya Kitaoka 120a6e
  /*- 左のハンドルを動かした場合 -*/
Shinya Kitaoka 120a6e
  else if (isLeftControlPoint(m_currentControlPointIndex)) {
Shinya Kitaoka 120a6e
    QPointF p0 =
Shinya Kitaoka 120a6e
        m_points.at(m_currentControlPointIndex) + QPointF(0, delta.y());
Shinya Kitaoka 120a6e
    setPoint(m_currentControlPointIndex, p0);
Shinya Kitaoka 120a6e
    if (m_currentControlPointIndex < pointCount - 5) {
Shinya Kitaoka 120a6e
      QPointF p2 =
Shinya Kitaoka 120a6e
          m_points.at(m_currentControlPointIndex + 2) - QPointF(0, delta.y());
Shinya Kitaoka 120a6e
      setPoint(m_currentControlPointIndex + 2, p2);
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
    emit controlPointChanged(true);
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
  /*- 右のハンドルを動かした場合 -*/
Shinya Kitaoka 120a6e
  else {
Shinya Kitaoka 120a6e
    assert(isRightControlPoint(m_currentControlPointIndex));
Shinya Kitaoka 120a6e
    QPointF p0 =
Shinya Kitaoka 120a6e
        m_points.at(m_currentControlPointIndex) + QPointF(0, delta.y());
Shinya Kitaoka 120a6e
    setPoint(m_currentControlPointIndex, p0);
Shinya Kitaoka 120a6e
    if (m_currentControlPointIndex > 4) {
Shinya Kitaoka 120a6e
      QPointF p2 =
Shinya Kitaoka 120a6e
          m_points.at(m_currentControlPointIndex - 2) - QPointF(0, delta.y());
Shinya Kitaoka 120a6e
      setPoint(m_currentControlPointIndex - 2, p2);
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
    emit controlPointChanged(true);
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
  update();
Shinya Kitaoka 120a6e
}
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
//-----------------------------------------------------------------------------
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
void ChennelCurveEditor::moveCentralControlPoint(int index,
Shinya Kitaoka 120a6e
                                                 const 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
Shinya Kitaoka 120a6e
  int newX         = p.x() + delta.x();
Shinya Kitaoka 120a6e
  int newY         = p.y() + delta.y();
Shinya Kitaoka 120a6e
  QPointF newPoint = checkPoint(QPoint(newX, newY));
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
Shinya Kitaoka 120a6e
  // Caso particolare: Punto di controllo corrente == primo visibile,
Shinya Kitaoka d1f6c4
  //								  Punto di controllo
Shinya Kitaoka d1f6c4
  //successivo
Shinya Kitaoka d1f6c4
  //==
Shinya Kitaoka d1f6c4
  // l'ultimo
Shinya Kitaoka 38fd86
  // visibile
Shinya Kitaoka 120a6e
  if (index == 3 && index + 3 == pointCount - 4) {
Shinya Kitaoka 120a6e
    setPoint(index + 1,
Shinya Kitaoka 120a6e
             getNewFirstHandlePoint(p, nextP, m_points.at(index + 1)));
Shinya Kitaoka 120a6e
    setPoint(index + 2,
Shinya Kitaoka 120a6e
             getNewSecondHandlePoint(p, nextP, m_points.at(index + 2)));
Shinya Kitaoka 120a6e
    if (nextDistance < 0) d = QPointF(nextP.x() - p.x(), d.y());
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
  // Caso particolare: Punto di controllo corrente == ultimo visibile,
Shinya Kitaoka d1f6c4
  //								  Punto di controllo
Shinya Kitaoka d1f6c4
  //precedente
Shinya Kitaoka d1f6c4
  //==
Shinya Kitaoka d1f6c4
  // primo
Shinya Kitaoka 38fd86
  // visibile
Shinya Kitaoka 120a6e
  else if (index - 3 == 3 && index == pointCount - 4) {
Shinya Kitaoka 120a6e
    setPoint(index - 2,
Shinya Kitaoka 120a6e
             getNewFirstHandlePoint(precP, p, m_points.at(index - 2)));
Shinya Kitaoka 120a6e
    setPoint(index - 1,
Shinya Kitaoka 120a6e
             getNewSecondHandlePoint(precP, p, m_points.at(index - 1)));
Shinya Kitaoka 120a6e
    if (precDistance < 0) d = QPointF(precP.x() - p.x(), d.y());
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
  // Altrimenti calcolo il nuovo delta
Shinya Kitaoka 120a6e
  else if (nextDistance < 16)
Shinya Kitaoka 120a6e
    d = QPointF(nextP.x() - p.x() - 16, d.y());
Shinya Kitaoka 120a6e
  else if (precDistance < 16)
Shinya Kitaoka 120a6e
    d = QPointF(precP.x() - p.x() + 16, d.y());
Shinya Kitaoka 120a6e
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
Toshihiro Shimizu 890ddd
/* Se due punti di controllo sono troppo vicini uno dei due viene eliminato.
Shinya Kitaoka 120a6e
         Ritorna vero se un punto viene eliminato.
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
Prima di richiamare il metodo nel move andava fatto questo controllo!!!
Shinya Kitaoka 120a6e
//Se il punto di controllo successivo, o precente, e' l'utlimo, o il primo,
Shinya Kitaoka 120a6e
blocco il
Shinya Kitaoka 120a6e
// movimento altrimenti elimino il punto di controllo successivo e richiamo il
Shinya Kitaoka 120a6e
move.
Toshihiro Shimizu 890ddd
int nextPX = m_points.at(index+3).x();
Toshihiro Shimizu 890ddd
if(nextPX>m_margin && nextPX<=w && newX>nextPX)
Toshihiro Shimizu 890ddd
{
Shinya Kitaoka 120a6e
        if(index+3 == pointCount-4) d = QPointF(0, d.y());
Shinya Kitaoka 120a6e
        else
Shinya Kitaoka 120a6e
        {
Shinya Kitaoka 120a6e
                moveCentralControlPoint(index, d);
Shinya Kitaoka 120a6e
                return;
Shinya Kitaoka 120a6e
        }
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
int precPX = m_points.at(index-3).x();
Toshihiro Shimizu 890ddd
if(precPX>=m_margin && precPX<=w && newX
Toshihiro Shimizu 890ddd
{
Shinya Kitaoka 120a6e
        if(index-3 == 3) d = QPointF(0, d.y());
Shinya Kitaoka 120a6e
        else
Shinya Kitaoka 120a6e
        {
Shinya Kitaoka 120a6e
                moveCentralControlPoint(index, d);
Shinya Kitaoka 120a6e
                return;
Shinya Kitaoka 120a6e
        }
Shinya Kitaoka 120a6e
}
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
bool ChennelCurveEditor::eraseControlPointWhileMove(int index, const QPointF
Shinya Kitaoka 120a6e
delta)
Shinya Kitaoka 120a6e
{
Shinya Kitaoka 120a6e
        int pointCount = m_points.size();
Shinya Kitaoka 120a6e
        QPointF p = m_points.at(index);
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 = abs((p.x()+delta.x())-nextP.x());
Shinya Kitaoka 120a6e
        double precDistance = abs((p.x()+delta.x())-precP.x());
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
        if(nextDistance>16 && precDistance>16) return false;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
        //Se vado troppo vicino al punto di controllo precedente, o successivo,
Shinya Kitaoka 120a6e
lo elimino.
Shinya Kitaoka 120a6e
        if(nextDistance<=16)
Shinya Kitaoka 120a6e
        {
Shinya Kitaoka 120a6e
                //Caso particolare: il successivo e' l'ultimo visibile; non
Shinya Kitaoka 120a6e
posso eliminare l'ultimo punto di controllo visibile.
Shinya Kitaoka 120a6e
                if(index+3 == pointCount-4)
Shinya Kitaoka 120a6e
                {
Shinya Kitaoka 120a6e
                        //Se il punto di controllo in index e' il primo visibile
Shinya Kitaoka 120a6e
sto gestendo il
Shinya Kitaoka 120a6e
                        // primo e l'ultimo punto, entrambi non possono essere
Shinya Kitaoka 120a6e
eliminati.
Shinya Kitaoka 120a6e
                        if(index == 3)
Shinya Kitaoka 120a6e
                        {
Shinya Kitaoka 120a6e
                                setPoint(index+1,nextP);
Shinya Kitaoka 120a6e
                                setPoint(index+2,p+delta);
Shinya Kitaoka 120a6e
                                return false;
Shinya Kitaoka 120a6e
                        }
Shinya Kitaoka 120a6e
                        else	//Altrimenti elimino il penultimo.
Shinya Kitaoka 120a6e
                        {
Shinya Kitaoka 120a6e
                                removeControlPoint(index);
Shinya Kitaoka 120a6e
                                m_currentControlPointIndex += 3;
Shinya Kitaoka 120a6e
                                return true;
Shinya Kitaoka 120a6e
                        }
Shinya Kitaoka 120a6e
                }
Shinya Kitaoka 120a6e
                removeControlPoint(index+3);
Shinya Kitaoka 120a6e
                return true;
Shinya Kitaoka 120a6e
        }
Shinya Kitaoka 120a6e
        if(precDistance<=16)
Shinya Kitaoka 120a6e
        {
Shinya Kitaoka 120a6e
                //Caso particolare: il precedente e' il primo visibile; non
Shinya Kitaoka 120a6e
posso eliminare il primo punto di controllo visibile.
Shinya Kitaoka 120a6e
                if(index-3 == 3)
Shinya Kitaoka 120a6e
                {
Shinya Kitaoka 120a6e
                        //Se il punto di controllo in index e' l'ultimo visibile
Shinya Kitaoka 120a6e
sto gestendo il
Shinya Kitaoka 120a6e
                        // primo e l'ultimo punto, entrambi non possono essere
Shinya Kitaoka 120a6e
eliminati.
Shinya Kitaoka 120a6e
                        if(index == pointCount-4)
Shinya Kitaoka 120a6e
                        {
Shinya Kitaoka 120a6e
                                setPoint(index-1,precP);
Shinya Kitaoka 120a6e
                                setPoint(index-2,p+delta);
Shinya Kitaoka 120a6e
                                return false;
Shinya Kitaoka 120a6e
                        }
Shinya Kitaoka 120a6e
                        else	//Altrimenti elimino il secondo.
Shinya Kitaoka 120a6e
                        {
Shinya Kitaoka 120a6e
                                removeControlPoint(index);
Shinya Kitaoka 120a6e
                                return true;
Shinya Kitaoka 120a6e
                        }
Shinya Kitaoka 120a6e
                }
Shinya Kitaoka 120a6e
                removeControlPoint(index-3);
Shinya Kitaoka 120a6e
                m_currentControlPointIndex += 3;
Shinya Kitaoka 120a6e
                return true;
Shinya Kitaoka 120a6e
        }
Shinya Kitaoka 120a6e
        return false;
Toshihiro Shimizu 890ddd
}
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
Shinya Kitaoka 120a6e
  if (abs(p.x() - p0.x()) <= 16) 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
Shinya Kitaoka 120a6e
  if (abs(p3.x() - p.x()) <= 16) 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;
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
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) {
Shinya Kitaoka 120a6e
    setPoint(0, strokeToViewPoint(TPointD(-40, 0)));
Shinya Kitaoka 120a6e
    setPoint(1, strokeToViewPoint(TPointD(-20, 0)));
Shinya Kitaoka 120a6e
    setPoint(2, strokeToViewPoint(TPointD(-20, 0)));
Shinya Kitaoka 120a6e
    setPoint(3, strokeToViewPoint(TPointD(0, 0)));
Shinya Kitaoka 120a6e
    setPoint(4, strokeToViewPoint(TPointD(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;
Shinya Kitaoka 120a6e
    setPoint(i, strokeToViewPoint(TPointD(239, 239)));
Shinya Kitaoka 120a6e
    setPoint(i + 1, strokeToViewPoint(TPointD(255, 255)));
Shinya Kitaoka 120a6e
    setPoint(i + 2, strokeToViewPoint(TPointD(275, 255)));
Shinya Kitaoka 120a6e
    setPoint(i + 3, strokeToViewPoint(TPointD(275, 255)));
Shinya Kitaoka 120a6e
    setPoint(i + 4, strokeToViewPoint(TPointD(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;
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);
Shinya Kitaoka 120a6e
    if (!m_isLinear)
Shinya Kitaoka 120a6e
      path.cubicTo(p1, p2, p3);
Shinya Kitaoka 120a6e
    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.
Shinya Kitaoka 120a6e
  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
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
  int i;
Shinya Kitaoka 120a6e
  int d = m_curveHeight * 0.25;
Shinya Kitaoka 120a6e
  for (i = 1; i < 16; i++) {
Shinya Kitaoka 120a6e
    // linee orizzontali
Shinya Kitaoka 120a6e
    int delta = m_TopMargin + 16 * i;
Shinya Kitaoka 120a6e
    int j;
Shinya Kitaoka 120a6e
    for (j = 1; j < 4; j++)
Shinya Kitaoka 120a6e
      painter.drawLine(QPoint((j - 1) * d + m_LeftRightMargin + 1, delta),
Shinya Kitaoka 120a6e
                       QPoint(j * d + m_LeftRightMargin - 1, delta));
Shinya Kitaoka 120a6e
    painter.drawLine(QPoint((4 - 1) * d + m_LeftRightMargin + 1, delta),
Shinya Kitaoka 120a6e
                     QPoint(4 * d + m_LeftRightMargin, delta));
Shinya Kitaoka 120a6e
    // linee verticali
Shinya Kitaoka 120a6e
    delta = m_LeftRightMargin + 1 + 16 * i;
Shinya Kitaoka 120a6e
    if (i % 4 == 0) continue;
Shinya Kitaoka 120a6e
    for (j = 1; j < 5; j++)
Shinya Kitaoka 120a6e
      painter.drawLine(QPoint(delta, (j - 1) * d + m_TopMargin),
Shinya Kitaoka 120a6e
                       QPoint(delta, j * d + m_TopMargin - 1));
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  // Disegno l'histogram.
Shinya Kitaoka 120a6e
  m_histogramView->draw(&painter, QPoint(m_LeftRightMargin - 10, 0));
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);
Shinya Kitaoka 120a6e
  QPainterPath path = getPainterPath();
Shinya Kitaoka 120a6e
  if (path.isEmpty()) return;
Shinya Kitaoka 120a6e
  painter.setRenderHint(QPainter::Antialiasing, true);
Shinya Kitaoka 120a6e
  painter.setPen(Qt::black);
Shinya Kitaoka 120a6e
  painter.setBrush(Qt::NoBrush);
Shinya Kitaoka 120a6e
  painter.drawPath(path);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  // Disegno i punti di controllo (esclusi i primi tre e gli ultimi tre)
Shinya Kitaoka 120a6e
  r         = r.adjusted(-5, -5, 5, 5);
Shinya Kitaoka 120a6e
  int n     = m_points.size();
Shinya Kitaoka 120a6e
  QPointF p = m_points.at(3);
Shinya Kitaoka 120a6e
  for (i = 3; i < n - 3; i++) {
Shinya Kitaoka 120a6e
    QBrush brush(Qt::white);
Shinya Kitaoka 120a6e
    int rad       = 3;
Shinya Kitaoka 120a6e
    QPointF nextP = m_points.at(i + 1);
Shinya Kitaoka 120a6e
    if (isCentralControlPoint(i))
Shinya Kitaoka 120a6e
      rad = 4;
Shinya Kitaoka 120a6e
    else if (m_isLinear) {
Shinya Kitaoka 120a6e
      p = nextP;
Shinya Kitaoka 120a6e
      continue;
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
    if (m_currentControlPointIndex == i) brush = QBrush(Qt::black);
Shinya Kitaoka 120a6e
    painter.setBrush(brush);
Shinya Kitaoka 120a6e
    painter.setPen(Qt::black);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    if (!m_isLinear) {
Shinya Kitaoka 120a6e
      if (isLeftControlPoint(i))
Shinya Kitaoka 120a6e
        painter.drawLine(p, nextP);
Shinya Kitaoka 120a6e
      else if (isCentralControlPoint(i) && i < n - 4)
Shinya Kitaoka 120a6e
        painter.drawLine(p, nextP);
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
    QPainterPath circle;
Shinya Kitaoka 120a6e
    QRectF pointRect(p.x() - rad, p.y() - rad, 2 * rad, 2 * rad);
Shinya Kitaoka 120a6e
    if (r.contains(pointRect))
Toshihiro Shimizu 890ddd
#if QT_VERSION >= 0x050000
Shinya Kitaoka 120a6e
      painter.setClipRect(pointRect.adjusted(-1, -1, 1, 1));
Toshihiro Shimizu 890ddd
#else
Shinya Kitaoka 120a6e
      painter.setClipRect(pointRect.adjusted(-1, -1, 1, 1), Qt::UniteClip);
Toshihiro Shimizu 890ddd
#endif
Shinya Kitaoka 120a6e
    circle.addEllipse(pointRect);
Shinya Kitaoka 120a6e
    painter.fillPath(circle, brush);
Shinya Kitaoka 120a6e
    painter.drawPath(circle);
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) {
Shinya Kitaoka 120a6e
  if (m_mouseButton == Qt::LeftButton && m_currentControlPointIndex != -1) {
Shinya Kitaoka 120a6e
    QPoint pos   = e->pos();
Shinya Kitaoka 120a6e
    QPointF posF = QPointF(pos.x(), pos.y());
Shinya Kitaoka 120a6e
    moveCurrentControlPoint(posF - m_points.at(m_currentControlPointIndex));
Shinya Kitaoka 120a6e
  }
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) {
Shinya Kitaoka 120a6e
    QPoint pos   = e->pos();
Shinya Kitaoka 120a6e
    QPointF posF = QPointF(pos.x(), pos.y());
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
Shinya Kitaoka 120a6e
    if (minDistance < 20)
Shinya Kitaoka 120a6e
      m_currentControlPointIndex = controlPointIndex;
Shinya Kitaoka 120a6e
    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
    }
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) {
Shinya Kitaoka 120a6e
  /*-- マウスドラッグ中はプレビューを更新しない。ここで初めて更新 --*/
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) {
Shinya Kitaoka 120a6e
  if (e->key() == Qt::Key_Delete) removeCurrentControlPoint();
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
void ChennelCurveEditor::enterEvent(QEvent *) { m_mouseButton = Qt::NoButton; }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
//-----------------------------------------------------------------------------
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
void ChennelCurveEditor::leaveEvent(QEvent *) { m_mouseButton = Qt::NoButton; }
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
  m_currentControlPointIndex = -1;
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)
Shinya Kitaoka 120a6e
    : QWidget(parent), m_toneCurveStackedWidget(0) {
Shinya Kitaoka 120a6e
  setFixedWidth(368);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  int currentChannelIndex = 0;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  QVBoxLayout *mainLayout = new QVBoxLayout(this);
Shinya Kitaoka 120a6e
  mainLayout->setMargin(0);
Shinya Kitaoka 120a6e
  mainLayout->setSpacing(0);
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";
Shinya Kitaoka 120a6e
  int channelCount = channels.size();
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  // lista canali: label+comboBox
Shinya Kitaoka 120a6e
  QWidget *channelListWidget     = new QWidget(this);
Shinya Kitaoka 120a6e
  QHBoxLayout *channelListLayout = new QHBoxLayout(channelListWidget);
Shinya Kitaoka 120a6e
  channelListLayout->setMargin(0);
Shinya Kitaoka 120a6e
  channelListLayout->setSpacing(0);
Shinya Kitaoka 120a6e
  QLabel *channelLabel = new QLabel(tr("Channel:"), channelListWidget);
Shinya Kitaoka 120a6e
  channelListLayout->addWidget(channelLabel);
Shinya Kitaoka 120a6e
  m_channelListChooser = new QComboBox(channelListWidget);
Shinya Kitaoka 120a6e
  m_channelListChooser->setFixedSize(100, 20);
Shinya Kitaoka 120a6e
  m_channelListChooser->addItems(channels);
Shinya Kitaoka 120a6e
  m_channelListChooser->setCurrentIndex(currentChannelIndex);
Shinya Kitaoka 120a6e
  channelListLayout->addWidget(m_channelListChooser);
Shinya Kitaoka 120a6e
  channelListWidget->setLayout(channelListLayout);
Shinya Kitaoka 120a6e
  mainLayout->addWidget(channelListWidget, 0, Qt::AlignCenter);
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);
Shinya Kitaoka 120a6e
    connect(c, SIGNAL(firstLastXPostionChanged(int, int)), this,
Shinya Kitaoka 120a6e
            SLOT(onFirstLastXPostionChanged(int, int)));
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  QWidget *w          = new QWidget(this);
Shinya Kitaoka 120a6e
  QHBoxLayout *layout = new QHBoxLayout(w);
Shinya Kitaoka 120a6e
  layout->setMargin(0);
Shinya Kitaoka 120a6e
  layout->setSpacing(0);
Shinya Kitaoka 120a6e
  layout->addWidget(m_toneCurveStackedWidget);
Shinya Kitaoka 120a6e
  w->setLayout(layout);
Shinya Kitaoka 120a6e
  mainLayout->addWidget(w, 0, Qt::AlignHCenter);
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++) {
Shinya Kitaoka 120a6e
    IntPairField *intPairSlider = new IntPairField(this);
Shinya Kitaoka 120a6e
    intPairSlider->setFixedHeight(20);
Shinya Kitaoka 120a6e
    intPairSlider->setLabelsEnabled(false);
Shinya Kitaoka 120a6e
    intPairSlider->setRange(0, 255);
Shinya Kitaoka 120a6e
    intPairSlider->setValues(std::make_pair(0, 255));
Shinya Kitaoka 120a6e
    m_sliderStackedWidget->addWidget(intPairSlider);
Shinya Kitaoka 120a6e
    connect(intPairSlider, SIGNAL(valuesChanged(bool)), this,
Shinya Kitaoka 120a6e
            SLOT(sliderValueChanged(bool)));
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
  mainLayout->addWidget(m_sliderStackedWidget);
Shinya Kitaoka 120a6e
  m_sliderStackedWidget->setCurrentIndex(currentChannelIndex);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  mainLayout->addSpacing(10);
Shinya Kitaoka 120a6e
  m_isLinearCheckBox = new CheckBox(QString("Linear"), this);
Shinya Kitaoka 120a6e
  mainLayout->addWidget(m_isLinearCheckBox, 0, Qt::AlignHCenter);
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)));
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  connect(m_channelListChooser, SIGNAL(currentIndexChanged(int)),
Shinya Kitaoka 120a6e
          m_toneCurveStackedWidget, SLOT(setCurrentIndex(int)));
Shinya Kitaoka 120a6e
  connect(m_channelListChooser, SIGNAL(currentIndexChanged(int)),
Shinya Kitaoka 120a6e
          m_sliderStackedWidget, SLOT(setCurrentIndex(int)));
Shinya Kitaoka 120a6e
  connect(m_channelListChooser, SIGNAL(currentIndexChanged(int)), this,
Shinya Kitaoka 120a6e
          SIGNAL(currentChannelIndexChanged(int)));
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  setLayout(mainLayout);
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
Shinya Kitaoka 120a6e
IntPairField *ToneCurveField::getCurrentSlider() const {
Shinya Kitaoka 120a6e
  return dynamic_cast<intpairfield *="">(m_sliderStackedWidget->currentWidget());</intpairfield>
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
void ToneCurveField::sliderValueChanged(bool isDragging) {
Shinya Kitaoka 120a6e
  std::pair<int, int=""> values = getCurrentSlider()->getValues();</int,>
Shinya Kitaoka 120a6e
  getCurrentChannelEditor()->setFirstLastXPosition(values, isDragging);
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
void ToneCurveField::onFirstLastXPostionChanged(int x0, int x1) {
Shinya Kitaoka 120a6e
  std::pair<int, int=""> values = getCurrentSlider()->getValues();</int,>
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
//-----------------------------------------------------------------------------
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
Shinya Kitaoka 120a6e
void ToneCurveField::setLinearManually(bool isLinear) {
Shinya Kitaoka 120a6e
  emit isLinearChanged(isLinear);
Toshihiro Shimizu 890ddd
}