421 lines
12 KiB
C++
421 lines
12 KiB
C++
|
|
||
|
|
||
|
#include "toonzqt/spectrumfield.h"
|
||
|
#include "toonzqt/styleeditor.h"
|
||
|
#include "tconvert.h"
|
||
|
#include "toonzqt/dvdialog.h"
|
||
|
#include "toonzqt/gutil.h"
|
||
|
|
||
|
#include "tcolorstyles.h"
|
||
|
|
||
|
#include <QHBoxLayout>
|
||
|
#include <QLabel>
|
||
|
#include <QSlider>
|
||
|
#include <QPainter>
|
||
|
#include <QLinearGradient>
|
||
|
#include <QMouseEvent>
|
||
|
#include <QImage>
|
||
|
|
||
|
using namespace DVGui;
|
||
|
|
||
|
//=============================================================================
|
||
|
/*! \class DVGui::SpectrumBar
|
||
|
\brief The SpectrumBar class provides a bar to display a spectrum
|
||
|
|
||
|
Inherits \b QWidget.
|
||
|
|
||
|
The object allows to manage a spectrum, permit you to insert, move and
|
||
|
remove key.
|
||
|
|
||
|
You can set spectrum default color in constructor, or set color of current
|
||
|
key, \b getCurrentColor(), using \b setCurrentColor(). It's possible to change
|
||
|
current key, \b getCurrentKeyIndex(), through its index, \b setCurrentKeyIndex().
|
||
|
You can also set current key position, \b getCurrentPos(), using \b setCurrentPos()
|
||
|
or add a new key in a specific position, addKeyAt().
|
||
|
*/
|
||
|
/*! \fn void DVGui::SpectrumBar::currentPosChanged()
|
||
|
The signal is emitted when current key position change.
|
||
|
*/
|
||
|
/*! \fn void DVGui::SpectrumBar::currentKeyChanged()
|
||
|
The signal is emitted when current key index change.
|
||
|
*/
|
||
|
SpectrumBar::SpectrumBar(QWidget *parent,
|
||
|
TPixel32 color)
|
||
|
: QWidget(parent), m_x0(10), m_currentKeyIndex(0), m_spectrum(color, color), m_chessBg(":Resources/backg.png")
|
||
|
{
|
||
|
setMinimumWidth(200);
|
||
|
setFixedHeight(WidgetHeight);
|
||
|
}
|
||
|
|
||
|
//-----------------------------------------------------------------------------
|
||
|
|
||
|
SpectrumBar::~SpectrumBar()
|
||
|
{
|
||
|
}
|
||
|
|
||
|
//-----------------------------------------------------------------------------
|
||
|
/*! Return current key position.
|
||
|
*/
|
||
|
int SpectrumBar::getCurrentPos()
|
||
|
{
|
||
|
if (m_currentKeyIndex == -1)
|
||
|
return -1;
|
||
|
return spectrumValueToPos(m_spectrum.getKey(m_currentKeyIndex).first);
|
||
|
}
|
||
|
|
||
|
//-----------------------------------------------------------------------------
|
||
|
/*! Return current key color.
|
||
|
*/
|
||
|
TPixel32 SpectrumBar::getCurrentColor()
|
||
|
{
|
||
|
if (m_currentKeyIndex == -1) //C'e' sicuramente una key perche' lo spectrum e' strutturato in modo da non avere mai size nulla.
|
||
|
return m_spectrum.getKey(getMaxPosKeyIndex()).second;
|
||
|
return m_spectrum.getKey(m_currentKeyIndex).second;
|
||
|
}
|
||
|
|
||
|
//-----------------------------------------------------------------------------
|
||
|
/*! Set current key index to \b index. Update spectrum bar and emit a signal to
|
||
|
notify current key changed \b currentKeyChanged().
|
||
|
*/
|
||
|
void SpectrumBar::setCurrentKeyIndex(int index)
|
||
|
{
|
||
|
if (m_currentKeyIndex == index)
|
||
|
return;
|
||
|
m_currentKeyIndex = index;
|
||
|
update();
|
||
|
emit currentKeyChanged();
|
||
|
}
|
||
|
|
||
|
//-----------------------------------------------------------------------------
|
||
|
/*! Add a new key to spectrum. Key position is computed \b x using
|
||
|
\b posToSpectrumValue() and color come from position.
|
||
|
*/
|
||
|
void SpectrumBar::addKeyAt(int x)
|
||
|
{
|
||
|
TPixel32 color = m_spectrum.getValue(posToSpectrumValue(x));
|
||
|
TSpectrum::ColorKey key(posToSpectrumValue(x), color);
|
||
|
m_spectrum.addKey(key);
|
||
|
int newIndex = m_spectrum.getKeyCount() - 1;
|
||
|
setCurrentKeyIndex(newIndex);
|
||
|
emit currentKeyAdded(newIndex);
|
||
|
}
|
||
|
|
||
|
//-----------------------------------------------------------------------------
|
||
|
/*! Set current key position to \b pos. Update spectrum bar and emit a signal to
|
||
|
notify current key changed \b currentKeyChanged().
|
||
|
*/
|
||
|
void SpectrumBar::setCurrentPos(int pos, bool isDragging)
|
||
|
{
|
||
|
TSpectrum::ColorKey key = m_spectrum.getKey(m_currentKeyIndex);
|
||
|
key.first = posToSpectrumValue(pos);
|
||
|
m_spectrum.setKey(m_currentKeyIndex, key);
|
||
|
update();
|
||
|
emit currentPosChanged(isDragging);
|
||
|
}
|
||
|
|
||
|
//-----------------------------------------------------------------------------
|
||
|
/*! Set current key color to \b color. Update spectrum bar.
|
||
|
*/
|
||
|
void SpectrumBar::setCurrentColor(const TPixel32 &color)
|
||
|
{
|
||
|
if (m_currentKeyIndex == -1)
|
||
|
return;
|
||
|
TSpectrum::ColorKey key = m_spectrum.getKey(m_currentKeyIndex);
|
||
|
TPixel32 oldColor = key.second;
|
||
|
if (oldColor == color)
|
||
|
return;
|
||
|
key.second = color;
|
||
|
m_spectrum.setKey(m_currentKeyIndex, key);
|
||
|
update();
|
||
|
}
|
||
|
|
||
|
//-----------------------------------------------------------------------------
|
||
|
/*! Return spectrum value from widget position \b pos.
|
||
|
*/
|
||
|
double SpectrumBar::posToSpectrumValue(int pos)
|
||
|
{
|
||
|
return (double)(pos - m_x0) / (double)(width() - 2 * m_x0 - 1);
|
||
|
}
|
||
|
|
||
|
//-----------------------------------------------------------------------------
|
||
|
/*! Return widget position from spectrum value \b spectrumValue.
|
||
|
*/
|
||
|
int SpectrumBar::spectrumValueToPos(double spectrumValue)
|
||
|
{
|
||
|
return m_x0 + int(0.5 + spectrumValue * (width() - 2 * m_x0));
|
||
|
}
|
||
|
|
||
|
//-----------------------------------------------------------------------------
|
||
|
/*! Paint widget object:
|
||
|
\li a linear gradient computed with spectrum value;
|
||
|
\li arrows for each spectrum key.
|
||
|
*/
|
||
|
void SpectrumBar::paintEvent(QPaintEvent *e)
|
||
|
{
|
||
|
QPainter p(this);
|
||
|
|
||
|
int h = height() - 1;
|
||
|
int y1 = height() / 2;
|
||
|
int x1 = width() - m_x0;
|
||
|
QRectF rectBar = QRectF(m_x0, 0, x1 - m_x0 + 1, y1);
|
||
|
|
||
|
//Build the linear gradient
|
||
|
QLinearGradient linearGrad(QPointF(m_x0, h), QPointF(x1, h));
|
||
|
int spectrumSize = m_spectrum.getKeyCount();
|
||
|
int i;
|
||
|
for (i = 0; i < spectrumSize; i++) {
|
||
|
TSpectrum::ColorKey key = m_spectrum.getKey(i);
|
||
|
//Linear Gradient
|
||
|
TPixel32 pix = key.second;
|
||
|
double spectrumValue = key.first;
|
||
|
linearGrad.setColorAt(spectrumValue, QColor(pix.r, pix.g, pix.b, pix.m));
|
||
|
//Frecce delle key
|
||
|
int pos = spectrumValueToPos(spectrumValue);
|
||
|
int f = 4;
|
||
|
drawArrow(p, QPointF(pos - f, y1 + f), QPointF(pos, y1), QPointF(pos + f, y1 + f),
|
||
|
true, (m_currentKeyIndex == i) ? Qt::black : Qt::white);
|
||
|
}
|
||
|
|
||
|
p.setPen(Qt::NoPen);
|
||
|
|
||
|
//Draw chess bg
|
||
|
QBrush bg;
|
||
|
bg.setTexture(m_chessBg);
|
||
|
p.setBrush(bg);
|
||
|
p.drawRect(rectBar);
|
||
|
|
||
|
//Draw the gradient
|
||
|
p.setBrush(linearGrad);
|
||
|
p.drawRect(rectBar);
|
||
|
}
|
||
|
|
||
|
//-----------------------------------------------------------------------------
|
||
|
/*! Manage mouse press event. Search exsisting key near click position, if
|
||
|
there is set it as current key; otherwise add a new key in click position.
|
||
|
*/
|
||
|
void SpectrumBar::mousePressEvent(QMouseEvent *e)
|
||
|
{
|
||
|
QPoint pos = e->pos();
|
||
|
int x = pos.x();
|
||
|
|
||
|
// Verifico se esiste una key vicino alla posizione in cui ho cliccato
|
||
|
int index = -1;
|
||
|
int spectrumSize = m_spectrum.getKeyCount();
|
||
|
if (x < m_x0)
|
||
|
index = getMinPosKeyIndex();
|
||
|
else if (x > width() - m_x0)
|
||
|
index = getMaxPosKeyIndex();
|
||
|
else
|
||
|
index = getNearPosKeyIndex(x);
|
||
|
|
||
|
// Se x e' vicino a una key esistente setto questa come corrente
|
||
|
if (index != -1)
|
||
|
setCurrentKeyIndex(index);
|
||
|
else //Altrimenti aggiungo una nuova key
|
||
|
addKeyAt(x);
|
||
|
}
|
||
|
|
||
|
//-----------------------------------------------------------------------------
|
||
|
/*! Manage mouse move event. If y position value greater than widget height
|
||
|
erase current key; otherwise move current key position.
|
||
|
*/
|
||
|
void SpectrumBar::mouseMoveEvent(QMouseEvent *e)
|
||
|
{
|
||
|
QPoint pos = e->pos();
|
||
|
int x = pos.x();
|
||
|
int y = pos.y();
|
||
|
if (x < m_x0 || x > width() - m_x0 - 1)
|
||
|
return;
|
||
|
|
||
|
// Se il valore della y e' maggiore dell'altezza widget, cioe' va fuori dal widget
|
||
|
// elimino la key corrente
|
||
|
if (y > height()) {
|
||
|
if (m_currentKeyIndex == -1 || m_spectrum.getKeyCount() == 1)
|
||
|
return;
|
||
|
|
||
|
m_spectrum.removeKey(m_currentKeyIndex);
|
||
|
int keyIndex = m_currentKeyIndex;
|
||
|
setCurrentKeyIndex(-1);
|
||
|
emit currentKeyRemoved(keyIndex);
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
// Se il valore della y e' interno al widget
|
||
|
// Se l'indice della key corrente e' -1 avevo eliminato un key; ora devo riaggiungerla.
|
||
|
if (m_currentKeyIndex == -1)
|
||
|
addKeyAt(x);
|
||
|
|
||
|
// Setto la nuova posizione x alla chiave corrente
|
||
|
setCurrentPos(x, true);
|
||
|
}
|
||
|
//-----------------------------------------------------------------------------
|
||
|
|
||
|
void SpectrumBar::mouseReleaseEvent(QMouseEvent *e)
|
||
|
{
|
||
|
if (m_currentKeyIndex == -1)
|
||
|
return;
|
||
|
QPoint pos = e->pos();
|
||
|
int x = pos.x();
|
||
|
int y = pos.y();
|
||
|
if (x < m_x0 || x > width() - m_x0 - 1)
|
||
|
return;
|
||
|
if (y > height())
|
||
|
return;
|
||
|
|
||
|
setCurrentPos(x, false);
|
||
|
}
|
||
|
|
||
|
//-----------------------------------------------------------------------------
|
||
|
/*! Return index of key with maximum position.
|
||
|
*/
|
||
|
int SpectrumBar::getMaxPosKeyIndex()
|
||
|
{
|
||
|
int spectrumSize = m_spectrum.getKeyCount();
|
||
|
if (!spectrumSize)
|
||
|
return -1;
|
||
|
int maxPosIndex = 0;
|
||
|
int maxPos = spectrumValueToPos(m_spectrum.getKey(0).first);
|
||
|
int i;
|
||
|
for (i = 0; i < spectrumSize; i++) {
|
||
|
int newPos = spectrumValueToPos(m_spectrum.getKey(i).first);
|
||
|
if (maxPos < newPos) {
|
||
|
maxPos = newPos;
|
||
|
maxPosIndex = i;
|
||
|
}
|
||
|
}
|
||
|
return maxPosIndex;
|
||
|
}
|
||
|
|
||
|
//-----------------------------------------------------------------------------
|
||
|
/*! Return index of key with minimum position.
|
||
|
*/
|
||
|
int SpectrumBar::getMinPosKeyIndex()
|
||
|
{
|
||
|
int spectrumSize = m_spectrum.getKeyCount();
|
||
|
if (!spectrumSize)
|
||
|
return -1;
|
||
|
int minPosIndex = 0;
|
||
|
int minPos = spectrumValueToPos(m_spectrum.getKey(0).first);
|
||
|
int i;
|
||
|
for (i = 0; i < spectrumSize; i++) {
|
||
|
int newPos = spectrumValueToPos(m_spectrum.getKey(i).first);
|
||
|
if (minPos > newPos) {
|
||
|
minPos = newPos;
|
||
|
minPosIndex = i;
|
||
|
}
|
||
|
}
|
||
|
return minPosIndex;
|
||
|
}
|
||
|
|
||
|
//-----------------------------------------------------------------------------
|
||
|
/*! Return index of key "near" \b pos. "near" mean with a dinstace less than
|
||
|
a constant size. If there aren't key near pos return \b -1.
|
||
|
*/
|
||
|
int SpectrumBar::getNearPosKeyIndex(int pos)
|
||
|
{
|
||
|
int i;
|
||
|
int gap = 20;
|
||
|
for (i = 0; i < m_spectrum.getKeyCount(); i++)
|
||
|
if (areAlmostEqual(double(pos),
|
||
|
double(spectrumValueToPos(m_spectrum.getKey(i).first)),
|
||
|
gap))
|
||
|
return i;
|
||
|
return -1;
|
||
|
}
|
||
|
|
||
|
//=============================================================================
|
||
|
/*! \class DVGui::SpectrumField
|
||
|
\brief The SpectrumField class provides an object to display and manage a spectrum.
|
||
|
|
||
|
Inherits \b QWidget.
|
||
|
|
||
|
The object is composed of a vertical layout \b QVBoxLayout which contains a
|
||
|
spectrum bar \b SpectrumBar and a color field \b ColorField. Using color field
|
||
|
it's possible to set spectrum current key color.
|
||
|
|
||
|
\b Example: Spectrum Field.
|
||
|
\image html SpectrumField.jpg
|
||
|
*/
|
||
|
SpectrumField::SpectrumField(QWidget *parent,
|
||
|
TPixel32 color)
|
||
|
: QWidget(parent), m_margin(0), m_spacing(4)
|
||
|
{
|
||
|
setFixedHeight(60);
|
||
|
|
||
|
QVBoxLayout *layout = new QVBoxLayout();
|
||
|
layout->setMargin(m_margin);
|
||
|
layout->setSpacing(m_spacing);
|
||
|
|
||
|
m_spectrumbar = new SpectrumBar(this, color);
|
||
|
connect(m_spectrumbar, SIGNAL(currentPosChanged(bool)), SLOT(onCurrentPosChanged(bool)));
|
||
|
connect(m_spectrumbar, SIGNAL(currentKeyChanged()), SLOT(onCurrentKeyChanged()));
|
||
|
connect(m_spectrumbar, SIGNAL(currentKeyAdded(int)), SIGNAL(keyAdded(int)));
|
||
|
connect(m_spectrumbar, SIGNAL(currentKeyRemoved(int)), SIGNAL(keyRemoved(int)));
|
||
|
|
||
|
layout->addWidget(m_spectrumbar);
|
||
|
|
||
|
m_colorField = new ColorField(this, true, color, 36);
|
||
|
connect(m_colorField, SIGNAL(colorChanged(const TPixel32 &, bool)),
|
||
|
this, SLOT(onColorChanged(const TPixel32 &, bool)));
|
||
|
layout->addWidget(m_colorField, 0, Qt::AlignLeft);
|
||
|
|
||
|
setLayout(layout);
|
||
|
}
|
||
|
|
||
|
//-----------------------------------------------------------------------------
|
||
|
/*! Update all widget and emit keyPositionChanged() signal.
|
||
|
*/
|
||
|
void SpectrumField::onCurrentPosChanged(bool isDragging)
|
||
|
{
|
||
|
if (m_spectrumbar->getCurrentKeyIndex() == -1)
|
||
|
return;
|
||
|
update();
|
||
|
emit keyPositionChanged(isDragging);
|
||
|
}
|
||
|
|
||
|
//-----------------------------------------------------------------------------
|
||
|
/*! Set color field to spectrum current key color and update.
|
||
|
*/
|
||
|
void SpectrumField::onCurrentKeyChanged()
|
||
|
{
|
||
|
if (m_spectrumbar->getCurrentKeyIndex() != -1)
|
||
|
m_colorField->setColor(m_spectrumbar->getCurrentColor());
|
||
|
update();
|
||
|
}
|
||
|
|
||
|
//-----------------------------------------------------------------------------
|
||
|
/*! Set spectrum current key color to \b color and emit keyColorChanged().
|
||
|
*/
|
||
|
void SpectrumField::onColorChanged(const TPixel32 &color, bool isDragging)
|
||
|
{
|
||
|
m_spectrumbar->setCurrentColor(color);
|
||
|
emit keyColorChanged(isDragging);
|
||
|
}
|
||
|
|
||
|
//-----------------------------------------------------------------------------
|
||
|
/*! Paint an arrow to connect current spectrum key and square color field.
|
||
|
*/
|
||
|
void SpectrumField::paintEvent(QPaintEvent *e)
|
||
|
{
|
||
|
int curPos = m_spectrumbar->getCurrentPos();
|
||
|
if (curPos == -1)
|
||
|
return;
|
||
|
QPainter p(this);
|
||
|
int x0 = 18 + m_margin;
|
||
|
int y0 = 2 * m_margin + WidgetHeight + m_spacing;
|
||
|
int y = m_margin + m_spacing + (WidgetHeight * 0.5 - 4); //4 e' l'altezza della freccia nella spectrum bar
|
||
|
int y1 = y0 - y * 0.5 + 1;
|
||
|
int y2 = y0 - y;
|
||
|
curPos += m_margin;
|
||
|
p.setPen(Qt::black);
|
||
|
p.drawLine(x0, y0, x0, y1);
|
||
|
p.drawLine(x0, y1, curPos, y1);
|
||
|
p.drawLine(curPos, y1, curPos, y2);
|
||
|
}
|
||
|
|
||
|
//-----------------------------------------------------------------------------
|
||
|
|
||
|
SpectrumField::~SpectrumField()
|
||
|
{
|
||
|
}
|