Blob Blame Raw


#include "toonzqt/intfield.h"
#include "toonzqt/dvdialog.h"
#include "toonzqt/gutil.h"

#include <QIntValidator>
#include <QSlider>
#include <QHBoxLayout>
#include <QAction>
#include <QFocusEvent>
#include <QPainter>

using namespace DVGui;

//=============================================================================
// RollerField
//-----------------------------------------------------------------------------

RollerField::RollerField(QWidget *parent)
	: QWidget(parent), m_value(0), m_minValue(-100000.0), m_maxValue(100000.0), m_xPos(0), m_step(1.0)
{
	setMinimumSize(43, 7);
}

//-----------------------------------------------------------------------------

void RollerField::setValue(double value)
{
	if (m_value == value)
		return;
	if (value < m_minValue)
		m_value = m_minValue;
	if (value > m_maxValue)
		m_value = m_maxValue;

	m_value = value;
}

//-----------------------------------------------------------------------------

double RollerField::getValue() const
{
	return m_value;
}

//-----------------------------------------------------------------------------

void RollerField::setRange(double minValue, double maxValue)
{
	m_minValue = minValue;
	m_maxValue = maxValue;
}

//-----------------------------------------------------------------------------

void RollerField::getRange(double &minValue, double &maxValue)
{
	minValue = m_minValue;
	maxValue = m_maxValue;
}

//-----------------------------------------------------------------------------

void RollerField::paintEvent(QPaintEvent *e)
{
	QPainter p(this);

	int w = width();

	drawArrow(p, QPointF(3, 3), QPointF(5, 5), QPointF(5, 1), true, Qt::black, Qt::black);
	drawArrow(p, QPointF(w - 4, 3), QPointF(w - 6, 5), QPointF(w - 6, 1), true, Qt::black, Qt::black);

	p.drawLine(QPoint(3, 3), QPoint(w - 4, 3));
}

//-----------------------------------------------------------------------------

void RollerField::mousePressEvent(QMouseEvent *e)
{
	if (e->buttons() == Qt::LeftButton) {
		m_xPos = e->pos().x();
		e->accept();
	}
}

//-----------------------------------------------------------------------------

void RollerField::mouseMoveEvent(QMouseEvent *e)
{
	if (e->buttons() == Qt::LeftButton) {
		if (m_xPos < e->pos().x())
			addValue(true);
		else if (m_xPos > e->pos().x())
			removeValue(true);
		m_xPos = e->pos().x();
		e->accept();
	}
}

//-----------------------------------------------------------------------------

void RollerField::mouseReleaseEvent(QMouseEvent *e)
{
	e->accept();
	emit valueChanged(false);
}

//-----------------------------------------------------------------------------

void RollerField::addValue(bool isDragging)
{
	double newValue = tcrop(m_value + m_step, m_minValue, m_maxValue);
	if (newValue == m_value)
		return;
	m_value = newValue;
	emit valueChanged(isDragging);
}

//-----------------------------------------------------------------------------

void RollerField::removeValue(bool isDragging)
{
	double newValue = tcrop(m_value - m_step, m_minValue, m_maxValue);
	if (newValue == m_value)
		return;
	m_value = newValue;
	emit valueChanged(isDragging);
}

//=============================================================================
// IntLineEdit
//-----------------------------------------------------------------------------

IntLineEdit::IntLineEdit(QWidget *parent,
						 int value,
						 int minValue, int maxValue,
						 int showedDigits)
	: LineEdit(parent), m_showedDigits(showedDigits)
{
	setFixedWidth(54);

	m_validator = new QIntValidator(this);
	setValue(value);
	setRange(minValue, maxValue);
	setValidator(m_validator);
}

//-----------------------------------------------------------------------------

void IntLineEdit::setValue(int value)
{
	int minValue, maxValue;
	getRange(minValue, maxValue);
	if (value < minValue)
		value = minValue;
	if (value > maxValue)
		value = maxValue;
	QString str;
	str.setNum(value);
	if (m_showedDigits > 0) {
		while (str.length() < m_showedDigits)
			str.push_front("0");
		while (str.length() > m_showedDigits)
			str.remove(0, 1);
	}
	setText(str);

	//Faccio in modo che il cursore sia sulla prima cifra, cosi' se la stringa da visualizzare
	//e' piu' lunga del campo le cifre che vengono troncate sono le ultime e non le prime.
	setCursorPosition(0);
}

//-----------------------------------------------------------------------------

int IntLineEdit::getValue()
{
	return text().toInt();
}

//-----------------------------------------------------------------------------

void IntLineEdit::setRange(int minValue, int maxValue)
{
	m_validator->setRange(minValue, maxValue);
}

//-----------------------------------------------------------------------------

void IntLineEdit::getRange(int &minValue, int &maxValue)
{
	minValue = m_validator->bottom();
	maxValue = m_validator->top();
}

//-----------------------------------------------------------------------------

void IntLineEdit::setBottomRange(int minValue)
{
	m_validator->setBottom(minValue);
}

//-----------------------------------------------------------------------------

void IntLineEdit::setTopRange(int maxValue)
{
	m_validator->setTop(maxValue);
}

//-----------------------------------------------------------------------------

void IntLineEdit::focusOutEvent(QFocusEvent *e)
{
	int value = getValue();
	int minValue, maxValue;
	getRange(minValue, maxValue);

	if (e->lostFocus())
		setValue(value);

	QLineEdit::focusOutEvent(e);
}

//-----------------------------------------------------------------------------

// for fps edit in flip console
void IntLineEdit::setLineEditBackgroundColor(QColor color)
{
	QString sheet = QString("background-color: rgb(") + QString::number(color.red()) + QString(",") + QString::number(color.green()) + QString(",") + QString::number(color.blue()) + QString(",") + QString::number(color.alpha()) + QString(");");
	setStyleSheet(sheet);
}

//=============================================================================
// IntField
//-----------------------------------------------------------------------------

IntField::IntField(QWidget *parent, bool isMaxRangeLimited, bool isRollerHide)
	: QWidget(parent), m_lineEdit(0), m_slider(0), m_roller(0), m_isMaxRangeLimited(isMaxRangeLimited)
{
	setObjectName("IntField");
	QHBoxLayout *layout = new QHBoxLayout(this);
	layout->setMargin(0);
	layout->setSpacing(5);

	QWidget *field = new QWidget(this);
	field->setMaximumWidth(43);
	QVBoxLayout *vLayout = new QVBoxLayout(field);
	vLayout->setMargin(0);
	vLayout->setSpacing(0);

	m_lineEdit = new DVGui::IntLineEdit(field);
	bool ret = connect(m_lineEdit, SIGNAL(editingFinished()), this, SLOT(onEditingFinished()));
	vLayout->addWidget(m_lineEdit);

	m_roller = new RollerField(field);
	ret = ret && connect(m_roller, SIGNAL(valueChanged(bool)), this, SLOT(onRollerValueChanged(bool)));
	vLayout->addWidget(m_roller);

	if (isRollerHide)
		enableRoller(false);

	layout->addWidget(field);

	m_slider = new QSlider(Qt::Horizontal, this);
	ret = ret && connect(m_slider, SIGNAL(valueChanged(int)), this, SLOT(onSliderChanged(int)));
	ret = ret && connect(m_slider, SIGNAL(sliderReleased()), this, SLOT(onSliderReleased()));

	ret = ret && connect(m_lineEdit, SIGNAL(editingFinished()), this, SIGNAL(valueEditedByHand()));
	ret = ret && connect(m_slider, SIGNAL(sliderReleased()), this, SIGNAL(valueEditedByHand()));
	layout->addWidget(m_slider);

	setValues(0, 0, 100);

	setLayout(layout);
	assert(ret);
}

//-----------------------------------------------------------------------------

void IntField::getRange(int &minValue, int &maxValue)
{
	double min, max;
	m_roller->getRange(min, max);
	minValue = tround(min);
	maxValue = tround(max);
}

//-----------------------------------------------------------------------------

void IntField::setRange(int minValue, int maxValue)
{
	m_lineEdit->setRange(minValue, m_isMaxRangeLimited ? maxValue : (std::numeric_limits<int>::max)());
	m_slider->setRange(minValue, maxValue);
	m_roller->setRange(minValue, maxValue);
}

//-----------------------------------------------------------------------------

void IntField::setValue(int value)
{
	if (m_lineEdit->getValue() == value)
		return;
	m_lineEdit->setValue(value);
	m_slider->setSliderPosition(value);
	m_roller->setValue((double)value);
}

//-----------------------------------------------------------------------------

int IntField::getValue()
{
	return (m_lineEdit->getValue());
}

//-----------------------------------------------------------------------------

void IntField::setValues(int value, int minValue, int maxValue)
{
	setRange(minValue, maxValue);
	setValue(value);
}

//-----------------------------------------------------------------------------

void IntField::enableSlider(bool enable)
{
	m_slider->setEnabled(enable);
	if (enable)
		m_slider->show();
	else
		m_slider->hide();
}

//-----------------------------------------------------------------------------

bool IntField::sliderIsEnabled()
{
	return m_slider->isEnabled();
}

//-----------------------------------------------------------------------------

void IntField::enableRoller(bool enable)
{
	m_roller->setEnabled(enable);
	if (enable)
		m_roller->show();
	else
		m_roller->hide();
}

//-----------------------------------------------------------------------------

bool IntField::rollerIsEnabled()
{
	return m_roller->isEnabled();
}

//-----------------------------------------------------------------------------

void IntField::setLineEditBackgroundColor(QColor color)
{
	m_lineEdit->setLineEditBackgroundColor(color);
}

//-----------------------------------------------------------------------------

void IntField::onSliderChanged(int value)
{
	//Controllo necessario per evitare che il segnale di cambiamento venga emesso piu' volte.
	if (m_lineEdit->getValue() == value ||
		((int)m_roller->getValue() == value && m_roller->isVisible()))
		return;
	m_lineEdit->setValue(value);
	m_roller->setValue((double)value);
	//Faccio in modo che il cursore sia sulla prima cifra, cosi' se la stringa
	//da visualizzare e' piu' lunga del campo le cifre che vengono troncate sono
	//le ultime e non le prime (dovrebbero essere quelle dopo la virgola).
	m_lineEdit->setCursorPosition(0);
	emit valueChanged(true);
}

//-----------------------------------------------------------------------------

void IntField::onEditingFinished()
{
	double value = m_lineEdit->getValue();
	//Controllo necessario per evitare che il segnale di cambiamento venga emesso piu' volte.
	if ((m_slider->value() == value && m_slider->isVisible()) ||
		(int)m_roller->getValue() == value && m_roller->isVisible())
		return;
	m_slider->setValue(value);
	m_roller->setValue((double)value);
	emit valueChanged(false);
}

//-----------------------------------------------------------------------------

void IntField::onRollerValueChanged(bool isDragging)
{
	int value = m_roller->getValue();
	if (value == m_lineEdit->getValue()) {
		assert(m_slider->value() == value || !m_slider->isVisible());
		// Se isDragging e' falso e' giusto che venga emessa la notifica di cambiamento.
		if (!isDragging)
			emit valueChanged(isDragging);
		return;
	}
	m_slider->setValue(value);
	m_lineEdit->setValue(value);

	//Faccio in modo che il cursore sia sulla prima cifra, cosi' se la stringa
	//da visualizzare e' piu' lunga del campo le cifre che vengono troncate sono
	//le ultime e non le prime (dovrebbero essere quelle dopo la virgola).
	m_lineEdit->setCursorPosition(0);

	emit valueChanged(isDragging);
}