tahoma2d/toonz/sources/toonzqt/tonecurvefield.cpp
Shinya Kitaoka fd19c4eedf Support Visual Studio 2015 (#544)
* Small changes, for some reason VS 2015 can't link cprintf and they added a second function std::map::count and bind couldn't resolve the function. Substituted with a lambda-expression.

* Created all 64bit version of the 3rd party libs.

* Cleanup popup opens CleanupSettings instead of CleanupSettingsPane. Not finished, panel is wrong now (also uses CleanupSettings).

* Tried to get Twain working, failed.

* When there are more then 3 peg holes create additional holes.

* When a hole touches the boundary it should still be considered a hole.

* Do not compare dot size against fixed size. Will not work in some scan resolutions. Used the same value (PERCENT * max dot size) as later in the code in compare_dots.

* When there are more than three peg holes the code looked for the best fit and used that. The problem was, that the middle hole was used as center for auto center. For three peg holes that is correct, but does not work for more than three. Now the best fit is calculated and from there the offset of the middle of the three best fit holes is calculated and applied.

* One of the last changes broke VS2015 compatibility, it chocked on a missing include.

* fix for msvs2013

* revert autopos.cpp

* apply clang-format

* use GIT-LFS
2016-07-04 17:50:30 +09:00

878 lines
30 KiB
C++

#include "toonzqt/tonecurvefield.h"
#include "toonzqt/fxhistogramrender.h"
#include "toonzqt/intpairfield.h"
#include "toonzqt/checkbox.h"
#include <QPainter>
#include <QPainterPath>
#include <QStackedWidget>
#include <QMouseEvent>
#include <QApplication>
#include <QHBoxLayout>
#include <QComboBox>
#include <QLabel>
using namespace DVGui;
//-----------------------------------------------------------------------------
namespace {
//-----------------------------------------------------------------------------
double getPercentAtPoint(QPointF point, QPainterPath path) {
int i;
for (i = 1; i < 100; i++) {
double p = double(i) * 0.01;
QPointF pathPoint = path.pointAtPercent(p);
if (abs(pathPoint.x() - point.x()) < 3 &&
abs(pathPoint.y() - point.y()) < 3)
return p;
}
return 0;
}
//-----------------------------------------------------------------------------
QList<QPointF> getIntersectedPoint(QRectF rect, QPainterPath path) {
int y0 = rect.top();
int y1 = rect.bottom();
QList<QPointF> points;
double g = 1.0 / 256.0;
QPointF prec = path.pointAtPercent(0);
QPointF point = path.pointAtPercent(g);
int j = 0;
for (j = 2; j < 256; j++) {
QPointF next = path.pointAtPercent(double(j) * g);
if (prec.y() >= y0 && prec.y() <= y1) {
if (point.y() < y0)
points.push_back(QPointF(prec.x(), y0));
else if (point.y() > y1)
points.push_back(QPointF(prec.x(), y1));
}
if (next.y() >= y0 && next.y() <= y1) {
if (point.y() < y0)
points.push_back(QPointF(next.x(), y0));
else if (point.y() > y1)
points.push_back(QPointF(next.x(), y1));
}
prec = point;
point = next;
}
return points;
}
//-----------------------------------------------------------------------------
double qtNorm2(const QPointF &p) { return p.x() * p.x() + p.y() * p.y(); }
double qtNorm(const QPointF &p) { return sqrt(qtNorm2(p)); }
QPointF qtNormalize(const QPointF &p) {
double n = qtNorm(p);
assert(n != 0.0);
return (1.0 / n) * p;
}
double qtDistance2(const QPointF &p1, const QPointF &p2) {
return qtNorm2(p2 - p1);
}
double qtDistance(const QPointF &p1, const QPointF &p2) {
return qtNorm(p2 - p1);
}
//-----------------------------------------------------------------------------
QPointF getNewFirstHandlePoint(const QPointF &p, const QPointF &nextP,
const QPointF &oldHandlePoint) {
bool canMove = (nextP.x() - p.x() > 16);
int yDistance = nextP.y() - p.y();
double sign = (yDistance != 0) ? yDistance / abs(yDistance) : 1;
double t = qtDistance(p, oldHandlePoint);
if (!canMove) {
QPointF normalizedP =
(yDistance != 0) ? qtNormalize(nextP - p) : QPoint(1, 1);
return QPointF(p + QPointF(t * normalizedP));
} else if (abs(oldHandlePoint.x() - p.x()) < 16)
return QPointF(p.x() + 16, p.y() + sign * sqrt(t * t - 16 * 16));
return oldHandlePoint;
}
//-----------------------------------------------------------------------------
QPointF getNewSecondHandlePoint(const QPointF &p, const QPointF &nextP,
const QPointF &oldHandlePoint) {
bool canMove = (nextP.x() - p.x() > 16);
int yDistance = p.y() - nextP.y();
double sign = (yDistance != 0) ? yDistance / abs(yDistance) : 1;
double s = qtDistance(oldHandlePoint, nextP);
if (!canMove) {
QPointF normalizedP =
(yDistance != 0) ? qtNormalize(nextP - p) : QPoint(1, 1);
return QPointF(nextP - QPointF(s * normalizedP));
} else if (abs(nextP.x() - oldHandlePoint.x()) < 16)
return QPointF(nextP.x() - 16, nextP.y() + sign * sqrt(s * s - 16 * 16));
return oldHandlePoint;
}
//-----------------------------------------------------------------------------
} // anonymous namespace
//-----------------------------------------------------------------------------
//=============================================================================
// ChennelCurveEditor
//=============================================================================
ChennelCurveEditor::ChennelCurveEditor(QWidget *parent,
HistogramView *histogramView)
: QWidget(parent)
, m_histogramView(histogramView)
, m_currentControlPointIndex(-1)
, m_mouseButton(Qt::NoButton)
, m_curveHeight(256)
, m_LeftRightMargin(42)
, m_TopMargin(9)
, m_BottomMargin(48)
, m_isLinear(false) {
setFixedSize(m_curveHeight + 2 * m_LeftRightMargin + 2,
m_curveHeight + m_TopMargin + m_BottomMargin);
setAttribute(Qt::WA_KeyCompression);
setFocusPolicy(Qt::StrongFocus);
setMouseTracking(true);
m_histogramView->setDrawnWidget(this);
m_histogramView->setGraphHeight(m_curveHeight);
m_histogramView->setGraphAlphaMask(120);
m_verticalChannelBar =
new ChannelBar(0, m_histogramView->getChannelBarColor(), false);
}
//-----------------------------------------------------------------------------
void ChennelCurveEditor::setPoints(QList<TPointD> points) {
if (!m_points.isEmpty()) m_points.clear();
int i;
for (i = 0; i < points.size(); i++) {
QPointF p = strokeToViewPoint(points.at(i));
m_points.push_back(p);
}
/*--ポイント位置に合わせてスライダも更新する--*/
int firstIndex = 3;
int lastIndex = m_points.size() - 4;
emit firstLastXPostionChanged(viewToStrokePoint(m_points.at(firstIndex)).x,
viewToStrokePoint(m_points.at(lastIndex)).x);
update();
}
//-----------------------------------------------------------------------------
QList<TPointD> ChennelCurveEditor::getPoints() {
QList<TPointD> points;
if (m_points.isEmpty()) return points;
int i;
for (i = 0; i < m_points.size(); i++)
points.push_back(viewToStrokePoint(m_points.at(i)));
return points;
}
//-----------------------------------------------------------------------------
void ChennelCurveEditor::setFirstLastXPosition(std::pair<int, int> values,
bool isDragging) {
if (!isDragging) {
emit controlPointChanged(false);
return;
}
QPointF newX0 = strokeToViewPoint(TPointD(values.first, 0));
QPointF newX1 = strokeToViewPoint(TPointD(values.second, 0));
int indexX0 = 3;
int indexX1 = m_points.size() - 4;
QPointF x0 = m_points.at(indexX0);
QPointF x1 = m_points.at(indexX1);
if (x0.x() != newX0.x()) {
QPointF delta(newX0.x() - x0.x(), 0);
moveCentralControlPoint(indexX0, delta);
update();
}
if (x1.x() != newX1.x()) {
QPointF delta(newX1.x() - x1.x(), 0);
moveCentralControlPoint(indexX1, delta);
update();
}
m_currentControlPointIndex = -1;
}
//-----------------------------------------------------------------------------
void ChennelCurveEditor::setLinear(bool isLinear) {
if (m_isLinear == isLinear) return;
m_isLinear = isLinear;
update();
}
//-----------------------------------------------------------------------------
QPointF ChennelCurveEditor::checkPoint(const QPointF p) {
QPointF checkedP = p;
int y0 = m_TopMargin + 1;
int y1 = m_curveHeight + m_TopMargin;
if (p.y() < y0) checkedP = QPointF(checkedP.x(), y0);
if (p.y() > y1) checkedP = QPointF(checkedP.x(), y1);
int x0 = m_LeftRightMargin + 1;
int x1 = m_curveHeight + m_LeftRightMargin;
if (p.x() < x0) checkedP = QPointF(x0, checkedP.y());
if (p.x() > x1) checkedP = QPointF(x1, checkedP.y());
return checkedP;
}
//-----------------------------------------------------------------------------
QPointF ChennelCurveEditor::strokeToViewPoint(const TPointD p) {
double x = p.x + m_LeftRightMargin + 1;
double y = height() - m_BottomMargin - p.y;
return QPointF(x, y);
}
//-----------------------------------------------------------------------------
TPointD ChennelCurveEditor::viewToStrokePoint(const QPointF &p) {
double x = p.x() - m_LeftRightMargin - 1;
double y = m_curveHeight - (p.y() - m_TopMargin);
return TThickPoint(x, y);
}
//-----------------------------------------------------------------------------
int ChennelCurveEditor::getClosestPointIndex(const QPointF &pos,
double &minDistance2) const {
int closestPointIndex = -1;
minDistance2 = 0;
int i;
for (i = 0; i < (int)m_points.size(); i++) {
double distance2 = qtDistance2(pos, m_points.at(i));
if (closestPointIndex < 0 || distance2 < minDistance2) {
minDistance2 = distance2;
closestPointIndex = i;
}
}
return closestPointIndex;
}
//-----------------------------------------------------------------------------
void ChennelCurveEditor::movePoint(int index, const QPointF delta) {
QPointF p = m_points.at(index);
p += delta;
setPoint(index, p);
int firstIndex = 3;
int lastIndex = m_points.size() - 4;
if (index == firstIndex)
emit firstLastXPostionChanged(viewToStrokePoint(p).x,
viewToStrokePoint(m_points.at(lastIndex)).x);
if (index == lastIndex)
emit firstLastXPostionChanged(viewToStrokePoint(m_points.at(firstIndex)).x,
viewToStrokePoint(p).x);
}
//-----------------------------------------------------------------------------
void ChennelCurveEditor::setPoint(int index, const QPointF p) {
m_points.removeAt(index);
m_points.insert(index, p);
int firstIndex = 3;
int lastIndex = m_points.size() - 4;
if (index == firstIndex)
emit firstLastXPostionChanged(viewToStrokePoint(p).x,
viewToStrokePoint(m_points.at(lastIndex)).x);
if (index == lastIndex)
emit firstLastXPostionChanged(viewToStrokePoint(m_points.at(firstIndex)).x,
viewToStrokePoint(p).x);
}
//-----------------------------------------------------------------------------
void ChennelCurveEditor::moveCurrentControlPoint(const QPointF delta) {
assert(m_currentControlPointIndex != -1);
int pointCount = m_points.size();
/*- セグメントを動かした場合 -*/
if (isCentralControlPoint(m_currentControlPointIndex))
moveCentralControlPoint(m_currentControlPointIndex, delta);
/*- 左のハンドルを動かした場合 -*/
else if (isLeftControlPoint(m_currentControlPointIndex)) {
QPointF p0 =
m_points.at(m_currentControlPointIndex) + QPointF(0, delta.y());
setPoint(m_currentControlPointIndex, p0);
if (m_currentControlPointIndex < pointCount - 5) {
QPointF p2 =
m_points.at(m_currentControlPointIndex + 2) - QPointF(0, delta.y());
setPoint(m_currentControlPointIndex + 2, p2);
}
emit controlPointChanged(true);
}
/*- 右のハンドルを動かした場合 -*/
else {
assert(isRightControlPoint(m_currentControlPointIndex));
QPointF p0 =
m_points.at(m_currentControlPointIndex) + QPointF(0, delta.y());
setPoint(m_currentControlPointIndex, p0);
if (m_currentControlPointIndex > 4) {
QPointF p2 =
m_points.at(m_currentControlPointIndex - 2) - QPointF(0, delta.y());
setPoint(m_currentControlPointIndex - 2, p2);
}
emit controlPointChanged(true);
}
update();
}
//-----------------------------------------------------------------------------
void ChennelCurveEditor::moveCentralControlPoint(int index,
const QPointF delta) {
int pointCount = m_points.size();
assert(index < pointCount - 3 && index > 2);
QPointF p = m_points.at(index);
QPointF d = delta;
// Trovo il valore di delta im modo tale che il punto di controllo non sia
// trascinato fuori dal range consentito
int newX = p.x() + delta.x();
int newY = p.y() + delta.y();
QPointF newPoint = checkPoint(QPoint(newX, newY));
d = newPoint - p;
QPointF nextP = m_points.at(index + 3);
QPointF precP = m_points.at(index - 3);
double nextDistance = nextP.x() - (p.x() + d.x());
double precDistance = (p.x() + d.x()) - precP.x();
// Caso particolare: Punto di controllo corrente == primo visibile,
// Punto di controllo successivo
//==
// l'ultimo
// visibile
if (index == 3 && index + 3 == pointCount - 4) {
setPoint(index + 1,
getNewFirstHandlePoint(p, nextP, m_points.at(index + 1)));
setPoint(index + 2,
getNewSecondHandlePoint(p, nextP, m_points.at(index + 2)));
if (nextDistance < 0) d = QPointF(nextP.x() - p.x(), d.y());
}
// Caso particolare: Punto di controllo corrente == ultimo visibile,
// Punto di controllo precedente
//==
// primo
// visibile
else if (index - 3 == 3 && index == pointCount - 4) {
setPoint(index - 2,
getNewFirstHandlePoint(precP, p, m_points.at(index - 2)));
setPoint(index - 1,
getNewSecondHandlePoint(precP, p, m_points.at(index - 1)));
if (precDistance < 0) d = QPointF(precP.x() - p.x(), d.y());
}
// Altrimenti calcolo il nuovo delta
else if (nextDistance < 16)
d = QPointF(nextP.x() - p.x() - 16, d.y());
else if (precDistance < 16)
d = QPointF(precP.x() - p.x() + 16, d.y());
// Punto di controllo speciale: il primo visualizzato.
if (index == 3) {
QPointF dY = QPointF(0, d.y());
movePoint(index - 1, dY);
movePoint(index - 2, dY);
movePoint(index - 3, dY);
}
// Punto di controllo speciale: l'ultimo visualizzato.
if (index == pointCount - 4) {
QPointF dY = QPointF(0, d.y());
movePoint(index + 1, dY);
movePoint(index + 2, dY);
movePoint(index + 3, dY);
}
if (index > 3) movePoint(index - 1, d);
if (index < pointCount - 4) movePoint(index + 1, d);
movePoint(index, d);
emit controlPointChanged(true);
}
//-----------------------------------------------------------------------------
void ChennelCurveEditor::addControlPoint(double percent) {
QPainterPath path = getPainterPath();
QPointF p = path.pointAtPercent(percent);
// Cerco il punto di controllo precedente
int pointCount = m_points.size();
int beforeControlPointIndex;
for (beforeControlPointIndex = pointCount - 1; beforeControlPointIndex >= 0;
beforeControlPointIndex--) {
QPointF point = m_points.at(beforeControlPointIndex);
if (isCentralControlPoint(beforeControlPointIndex) && point.x() < p.x())
break;
}
if (beforeControlPointIndex == 0 || beforeControlPointIndex == pointCount - 4)
return;
QPointF p0 = checkPoint(m_points.at(beforeControlPointIndex));
// Se sono troppo vicino al punto di controllo precedente ritorno
if (abs(p.x() - p0.x()) <= 16) return;
double beforeControlPointPercent = getPercentAtPoint(p0, path);
QPointF p1 = checkPoint(m_points.at(beforeControlPointIndex + 1));
QPointF p2 = checkPoint(m_points.at(beforeControlPointIndex + 2));
QPointF p3 = checkPoint(m_points.at(beforeControlPointIndex + 3));
// Se sono troppo vicino al punto di controllo successivo ritorno
if (abs(p3.x() - p.x()) <= 16) return;
double nextControlPointPercent = getPercentAtPoint(p3, path);
// Calcolo la velocita' e quindi il coiffciente angolare.
double t =
percent * 100 / (nextControlPointPercent - beforeControlPointPercent);
double s = t - 1;
QPointF speed =
3.0 * ((p1 - p0) * s * s + 2 * (p2 - p0) * s * t + (p3 - p2) * t * t);
double m = speed.y() / speed.x();
int newControlPointIndex = beforeControlPointIndex + 3;
m_points.insert(newControlPointIndex - 1,
QPointF(p.x() - 16, p.y() - 16 * m));
m_points.insert(newControlPointIndex, p);
m_points.insert(newControlPointIndex + 1,
QPointF(p.x() + 16, p.y() + 16 * m));
m_currentControlPointIndex = newControlPointIndex;
emit controlPointAdded(newControlPointIndex);
update();
}
//-----------------------------------------------------------------------------
void ChennelCurveEditor::removeCurrentControlPoint() {
removeControlPoint(m_currentControlPointIndex);
}
//-----------------------------------------------------------------------------
void ChennelCurveEditor::removeControlPoint(int index) {
// Non posso eliminare il primo punto di controllo visibile quindi lo rimetto
// in condizione iniziale
if (index <= 4) {
setPoint(0, strokeToViewPoint(TPointD(-40, 0)));
setPoint(1, strokeToViewPoint(TPointD(-20, 0)));
setPoint(2, strokeToViewPoint(TPointD(-20, 0)));
setPoint(3, strokeToViewPoint(TPointD(0, 0)));
setPoint(4, strokeToViewPoint(TPointD(16, 16)));
update();
emit controlPointChanged(false);
return;
}
// Non posso eliminare il l'ultimo punto di controllo visibile quindi lo
// rimetto in condizione iniziale
if (index >= m_points.size() - 5) {
int i = m_points.size() - 5;
setPoint(i, strokeToViewPoint(TPointD(239, 239)));
setPoint(i + 1, strokeToViewPoint(TPointD(255, 255)));
setPoint(i + 2, strokeToViewPoint(TPointD(275, 255)));
setPoint(i + 3, strokeToViewPoint(TPointD(275, 255)));
setPoint(i + 4, strokeToViewPoint(TPointD(295, 255)));
update();
emit controlPointChanged(false);
return;
}
int firstIndex = 0;
if (isCentralControlPoint(index))
firstIndex = index - 1;
else if (isLeftControlPoint(index))
firstIndex = index;
else
firstIndex = index - 2;
m_points.removeAt(firstIndex);
m_points.removeAt(firstIndex);
m_points.removeAt(firstIndex);
emit controlPointRemoved(firstIndex + 1);
m_currentControlPointIndex = firstIndex - 2;
update();
}
//-----------------------------------------------------------------------------
QPainterPath ChennelCurveEditor::getPainterPath() {
int pointCount = m_points.size();
if (pointCount == 0) return QPainterPath();
QPointF p0 = m_points.at(0);
QPainterPath path(p0);
int i;
for (i = 1; i < pointCount; i++) {
QPointF p1 = m_points.at(i);
QPointF p2 = m_points.at(++i);
QPointF p3 = m_points.at(++i);
path.moveTo(p0);
if (!m_isLinear)
path.cubicTo(p1, p2, p3);
else
path.lineTo(p3);
p0 = p3;
}
// Cerco le eventuali intersezioni con il bordo.
QRectF rect(m_LeftRightMargin, m_TopMargin, m_curveHeight, m_curveHeight);
QRectF r = path.boundingRect();
if (!rect.contains(QRect(rect.left(), r.top(), rect.width(), r.height()))) {
QList<QPointF> points = getIntersectedPoint(rect, path);
// Se trovo punti di intersezione (per come e' definita la curva devono
// essere pari)
// faccio l'unione del path calcolato e di nuovi path lineari.
int j = 0;
for (j = 0; j < points.size(); j++) {
QPointF p0 = points.at(j);
QPointF p1 = points.at(++j);
QPainterPath line(p0);
line.lineTo(p1);
path.addPath(line);
}
}
return path;
}
//-----------------------------------------------------------------------------
void ChennelCurveEditor::paintEvent(QPaintEvent *e) {
QPainter painter(this);
// Disegno il reticolato
painter.setRenderHint(QPainter::Antialiasing, false);
painter.setPen(QColor(250, 250, 250));
int i;
int d = m_curveHeight * 0.25;
for (i = 1; i < 16; i++) {
// linee orizzontali
int delta = m_TopMargin + 16 * i;
int j;
for (j = 1; j < 4; j++)
painter.drawLine(QPoint((j - 1) * d + m_LeftRightMargin + 1, delta),
QPoint(j * d + m_LeftRightMargin - 1, delta));
painter.drawLine(QPoint((4 - 1) * d + m_LeftRightMargin + 1, delta),
QPoint(4 * d + m_LeftRightMargin, delta));
// linee verticali
delta = m_LeftRightMargin + 1 + 16 * i;
if (i % 4 == 0) continue;
for (j = 1; j < 5; j++)
painter.drawLine(QPoint(delta, (j - 1) * d + m_TopMargin),
QPoint(delta, j * d + m_TopMargin - 1));
}
// Disegno l'histogram.
m_histogramView->draw(&painter, QPoint(m_LeftRightMargin - 10, 0));
// Disegno la barra verticale a sinistra.
m_verticalChannelBar->draw(
&painter,
QPoint(0, -2)); //-1 == m_topMargin- il margine della barra(=10+1).
QRectF r = rect().adjusted(m_LeftRightMargin, m_TopMargin, -m_LeftRightMargin,
-m_BottomMargin);
// Disegno la curva entro i limiti del grafo
painter.setClipRect(r, Qt::IntersectClip);
QPainterPath path = getPainterPath();
if (path.isEmpty()) return;
painter.setRenderHint(QPainter::Antialiasing, true);
painter.setPen(Qt::black);
painter.setBrush(Qt::NoBrush);
painter.drawPath(path);
// Disegno i punti di controllo (esclusi i primi tre e gli ultimi tre)
r = r.adjusted(-5, -5, 5, 5);
int n = m_points.size();
QPointF p = m_points.at(3);
for (i = 3; i < n - 3; i++) {
QBrush brush(Qt::white);
int rad = 3;
QPointF nextP = m_points.at(i + 1);
if (isCentralControlPoint(i))
rad = 4;
else if (m_isLinear) {
p = nextP;
continue;
}
if (m_currentControlPointIndex == i) brush = QBrush(Qt::black);
painter.setBrush(brush);
painter.setPen(Qt::black);
if (!m_isLinear) {
if (isLeftControlPoint(i))
painter.drawLine(p, nextP);
else if (isCentralControlPoint(i) && i < n - 4)
painter.drawLine(p, nextP);
}
QPainterPath circle;
QRectF pointRect(p.x() - rad, p.y() - rad, 2 * rad, 2 * rad);
if (r.contains(pointRect))
#if QT_VERSION >= 0x050000
painter.setClipRect(pointRect.adjusted(-1, -1, 1, 1));
#else
painter.setClipRect(pointRect.adjusted(-1, -1, 1, 1), Qt::UniteClip);
#endif
circle.addEllipse(pointRect);
painter.fillPath(circle, brush);
painter.drawPath(circle);
p = nextP;
}
}
//-----------------------------------------------------------------------------
void ChennelCurveEditor::mouseMoveEvent(QMouseEvent *e) {
if (m_mouseButton == Qt::LeftButton && m_currentControlPointIndex != -1) {
QPoint pos = e->pos();
QPointF posF = QPointF(pos.x(), pos.y());
moveCurrentControlPoint(posF - m_points.at(m_currentControlPointIndex));
}
}
//-----------------------------------------------------------------------------
void ChennelCurveEditor::mousePressEvent(QMouseEvent *e) {
m_mouseButton = e->button();
setFocus();
if (m_mouseButton == Qt::LeftButton) {
QPoint pos = e->pos();
QPointF posF = QPointF(pos.x(), pos.y());
double minDistance;
int controlPointIndex = getClosestPointIndex(posF, minDistance);
// Se la distanza e' piccola seleziono il control point corrente
if (minDistance < 20)
m_currentControlPointIndex = controlPointIndex;
else {
m_currentControlPointIndex = -1;
// Se sono sufficentemente lontano da un punto di controllo, ma abbastanza
// vicino alla curva
// aggiungo un punto di controllo
double percent = getPercentAtPoint(posF, getPainterPath());
if (percent != 0 && minDistance > 20) addControlPoint(percent);
}
update();
}
}
//-----------------------------------------------------------------------------
void ChennelCurveEditor::mouseReleaseEvent(QMouseEvent *e) {
/*-- マウスドラッグ中はプレビューを更新しない。ここで初めて更新 --*/
if (m_mouseButton == Qt::LeftButton && m_currentControlPointIndex != -1 &&
e->button() == Qt::LeftButton)
emit controlPointChanged(false);
m_mouseButton = Qt::NoButton;
}
//-----------------------------------------------------------------------------
void ChennelCurveEditor::keyPressEvent(QKeyEvent *e) {
if (e->key() == Qt::Key_Delete) removeCurrentControlPoint();
}
//-----------------------------------------------------------------------------
void ChennelCurveEditor::enterEvent(QEvent *) { m_mouseButton = Qt::NoButton; }
//-----------------------------------------------------------------------------
void ChennelCurveEditor::leaveEvent(QEvent *) { m_mouseButton = Qt::NoButton; }
//--------------------------------------------------------
bool ChennelCurveEditor::eventFilter(QObject *object, QEvent *event) {
if (event->type() == QEvent::Shortcut ||
event->type() == QEvent::ShortcutOverride) {
if (!object->inherits("FxSettings")) {
event->accept();
return true;
}
}
return false;
}
//--------------------------------------------------------
void ChennelCurveEditor::focusInEvent(QFocusEvent *fe) {
QWidget::focusInEvent(fe);
qApp->installEventFilter(this);
}
//--------------------------------------------------------
void ChennelCurveEditor::focusOutEvent(QFocusEvent *fe) {
m_currentControlPointIndex = -1;
emit focusOut();
QWidget::focusOutEvent(fe);
qApp->removeEventFilter(this);
update();
}
//=============================================================================
// ToneCurveField
//=============================================================================
ToneCurveField::ToneCurveField(QWidget *parent,
FxHistogramRender *fxHistogramRender)
: QWidget(parent), m_toneCurveStackedWidget(0) {
setFixedWidth(368);
int currentChannelIndex = 0;
QVBoxLayout *mainLayout = new QVBoxLayout(this);
mainLayout->setMargin(0);
mainLayout->setSpacing(0);
QStringList channels;
channels << "RGBA"
<< "RGB"
<< "Red"
<< "Green"
<< "Blue"
<< "Alpha";
int channelCount = channels.size();
// lista canali: label+comboBox
QWidget *channelListWidget = new QWidget(this);
QHBoxLayout *channelListLayout = new QHBoxLayout(channelListWidget);
channelListLayout->setMargin(0);
channelListLayout->setSpacing(0);
QLabel *channelLabel = new QLabel(tr("Channel:"), channelListWidget);
channelListLayout->addWidget(channelLabel);
m_channelListChooser = new QComboBox(channelListWidget);
m_channelListChooser->setFixedSize(100, 20);
m_channelListChooser->addItems(channels);
m_channelListChooser->setCurrentIndex(currentChannelIndex);
channelListLayout->addWidget(m_channelListChooser);
channelListWidget->setLayout(channelListLayout);
mainLayout->addWidget(channelListWidget, 0, Qt::AlignCenter);
// stack widget dei grafi
m_toneCurveStackedWidget = new QStackedWidget(this);
Histograms *histograms = new Histograms(0, true);
fxHistogramRender->setHistograms(histograms);
int i;
for (i = 0; i < channelCount; i++) {
ChennelCurveEditor *c =
new ChennelCurveEditor(this, histograms->getHistogramView(i));
m_toneCurveStackedWidget->addWidget(c);
connect(c, SIGNAL(firstLastXPostionChanged(int, int)), this,
SLOT(onFirstLastXPostionChanged(int, int)));
}
QWidget *w = new QWidget(this);
QHBoxLayout *layout = new QHBoxLayout(w);
layout->setMargin(0);
layout->setSpacing(0);
layout->addWidget(m_toneCurveStackedWidget);
w->setLayout(layout);
mainLayout->addWidget(w, 0, Qt::AlignHCenter);
m_toneCurveStackedWidget->setCurrentIndex(currentChannelIndex);
// stack widget degli slider
m_sliderStackedWidget = new QStackedWidget(this);
for (i = 0; i < channelCount; i++) {
IntPairField *intPairSlider = new IntPairField(this);
intPairSlider->setFixedHeight(20);
intPairSlider->setLabelsEnabled(false);
intPairSlider->setRange(0, 255);
intPairSlider->setValues(std::make_pair(0, 255));
m_sliderStackedWidget->addWidget(intPairSlider);
connect(intPairSlider, SIGNAL(valuesChanged(bool)), this,
SLOT(sliderValueChanged(bool)));
}
mainLayout->addWidget(m_sliderStackedWidget);
m_sliderStackedWidget->setCurrentIndex(currentChannelIndex);
mainLayout->addSpacing(10);
m_isLinearCheckBox = new CheckBox(QString("Linear"), this);
mainLayout->addWidget(m_isLinearCheckBox, 0, Qt::AlignHCenter);
connect(m_isLinearCheckBox, SIGNAL(clicked(bool)),
SLOT(setLinearManually(bool)));
connect(m_isLinearCheckBox, SIGNAL(toggled(bool)), SLOT(setLinear(bool)));
connect(m_channelListChooser, SIGNAL(currentIndexChanged(int)),
m_toneCurveStackedWidget, SLOT(setCurrentIndex(int)));
connect(m_channelListChooser, SIGNAL(currentIndexChanged(int)),
m_sliderStackedWidget, SLOT(setCurrentIndex(int)));
connect(m_channelListChooser, SIGNAL(currentIndexChanged(int)), this,
SIGNAL(currentChannelIndexChanged(int)));
setLayout(mainLayout);
}
//-----------------------------------------------------------------------------
void ToneCurveField::setCurrentChannel(int currentChannel) {
m_channelListChooser->setCurrentIndex(currentChannel);
}
//-----------------------------------------------------------------------------
ChennelCurveEditor *ToneCurveField::getChannelEditor(int channel) const {
ChennelCurveEditor *c = dynamic_cast<ChennelCurveEditor *>(
m_toneCurveStackedWidget->widget(channel));
assert(c);
return c;
}
//-----------------------------------------------------------------------------
ChennelCurveEditor *ToneCurveField::getCurrentChannelEditor() const {
return getChannelEditor(m_toneCurveStackedWidget->currentIndex());
}
//-----------------------------------------------------------------------------
IntPairField *ToneCurveField::getCurrentSlider() const {
return dynamic_cast<IntPairField *>(m_sliderStackedWidget->currentWidget());
}
//-----------------------------------------------------------------------------
void ToneCurveField::sliderValueChanged(bool isDragging) {
std::pair<int, int> values = getCurrentSlider()->getValues();
getCurrentChannelEditor()->setFirstLastXPosition(values, isDragging);
}
//-----------------------------------------------------------------------------
void ToneCurveField::onFirstLastXPostionChanged(int x0, int x1) {
std::pair<int, int> values = getCurrentSlider()->getValues();
if (values.first != x0 || values.second != x1)
getCurrentSlider()->setValues(std::make_pair(x0, x1));
}
//-----------------------------------------------------------------------------
void ToneCurveField::setIsLinearCheckBox(bool isChecked) {
if (m_isLinearCheckBox->isChecked() == isChecked) return;
m_isLinearCheckBox->setChecked(isChecked);
}
//-----------------------------------------------------------------------------
void ToneCurveField::setLinear(bool isLinear) {
int i;
for (i = 0; i < m_sliderStackedWidget->count(); i++)
getChannelEditor(i)->setLinear(isLinear);
}
//-----------------------------------------------------------------------------
void ToneCurveField::setLinearManually(bool isLinear) {
emit isLinearChanged(isLinear);
}