Blob Blame Raw


#include "toonzqt/intpairfield.h"

#include "toonzqt/dvdialog.h"

#include "tcommon.h"

#include <QLabel>
#include <QPainter>
#include <QMouseEvent>
#include <QSlider>
#include <QHBoxLayout>

using namespace DVGui;

#ifdef MACOSX
#define MARGIN_OFFSET 7
#else
#define MARGIN_OFFSET 2
#endif

//=============================================================================
// IntPairField
//-----------------------------------------------------------------------------

IntPairField::IntPairField(QWidget *parent, bool isMaxRangeLimited)
	: QWidget(parent), m_values(0, 0), m_minValue(0), m_maxValue(100), m_grabOffset(0), m_grabIndex(-1), m_leftMargin(52), m_rightMargin(52), m_isMaxRangeLimited(isMaxRangeLimited)
{
	setObjectName("IntPairField");
	setFixedHeight(WidgetHeight);

	m_leftLabel = new QLabel("", this);
	m_leftLineEdit = new IntLineEdit(this);

	m_rightLabel = new QLabel("", this);
	m_rightLineEdit = new IntLineEdit(this);

	m_leftLineEdit->setFixedWidth(40);
	m_rightLineEdit->setFixedWidth(40);

	//----layout
	QHBoxLayout *m_mainLayout = new QHBoxLayout;
	m_mainLayout->setMargin(0);
	m_mainLayout->setSpacing(5);
	{
		m_mainLayout->addWidget(m_leftLabel, 1);
		m_mainLayout->addWidget(m_leftLineEdit, 1, Qt::AlignLeft);
		m_mainLayout->addSpacing(35);
		m_mainLayout->addStretch(100);
		m_mainLayout->addWidget(m_rightLabel, 1);
		m_mainLayout->addWidget(m_rightLineEdit, 1, Qt::AlignRight);
	}
	setLayout(m_mainLayout);

	//---signal-slot connections
	bool ret = connect(m_leftLineEdit, SIGNAL(editingFinished()), SLOT(onLeftEditingFinished()));
	ret = ret && connect(m_rightLineEdit, SIGNAL(editingFinished()), SLOT(onRightEditingFinished()));

	assert(ret);
}

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

double IntPairField::pos2value(int x) const
{
	int xMin = m_leftMargin, xMax = width() - m_rightMargin - 1;
	return m_minValue + (m_maxValue - m_minValue) * (x - xMin) / (xMax - xMin);
}

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

int IntPairField::value2pos(double v) const
{
	int xMin = m_leftMargin, xMax = width() - m_rightMargin - 1;
	return xMin + (int)(((xMax - xMin) * (v - m_minValue)) / (m_maxValue - m_minValue));
}

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

void IntPairField::paintEvent(QPaintEvent *)
{
	QPainter p(this);
	p.setBrush(Qt::NoBrush);

	int x0 = value2pos(m_minValue);
	int x1 = value2pos(m_maxValue);
	int y = height() / 2;

	p.setPen(getLightLineColor());
	p.drawLine(x0 - 1, y, x1 + 1, y);
	p.drawPoint(x1 + 1, y - 1);
	p.drawPoint(x1 + 1, y - 2);
	p.drawPoint(x1 + 1, y - 3);
	p.setPen(QColor(0, 0, 0));
	p.drawLine(x0, y - 2, x1 - 1, y - 2);
	p.setPen(getDarkLineColor());
	p.drawLine(x0 - 1, y - 3, x1, y - 3);
	p.drawPoint(x0 - 1, y - 1);
	p.drawPoint(x0 - 1, y - 2);

	p.setPen(Qt::black);

	int y1 = height() - 1;
	int x;
	x = value2pos(m_values.first);
	QRect sliderRect = QRect(x0, -5, x1 - x0 + 1, 10);

	if (sliderRect.contains(QPoint(x, 0)))
		p.drawPixmap(x - m_handleLeftPixmap.width() + 1, 2, m_handleLeftPixmap);
	else
		p.drawPixmap(sliderRect.right() - m_handleLeftPixmap.width() + 1, 2, m_handleLeftGrayPixmap);

	x = value2pos(m_values.second);

	if (sliderRect.contains(QPoint(x, 0)))
		p.drawPixmap(x, 2, m_handleRightPixmap);
	else
		p.drawPixmap(sliderRect.right(), 2, m_handleRightGrayPixmap);
}

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

void IntPairField::setLeftText(const QString &text)
{
	QPoint pos = m_leftLabel->pos();
	QString oldText = m_leftLabel->text();
	int oldLabelSize = fontMetrics().width(oldText);
	int newLabelSize = fontMetrics().width(text);
	int labelSize = newLabelSize - oldLabelSize;
	m_leftMargin += labelSize + MARGIN_OFFSET;
	m_leftLabel->setText(text);
	update();
}

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

void IntPairField::setRightText(const QString &text)
{
	QString oldText = m_rightLabel->text();
	int oldLabelSize = fontMetrics().width(oldText);
	int newLabelSize = fontMetrics().width(text);
	int labelSize = newLabelSize - oldLabelSize;
	m_rightMargin += labelSize + MARGIN_OFFSET;
	m_rightLabel->setText(text);
	update();
}

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

void IntPairField::setLabelsEnabled(bool enable)
{
	if (!enable) {
		m_rightLabel->hide();
		m_leftLabel->hide();
	} else {
		m_rightLabel->show();
		m_leftLabel->show();
	}
}

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

void IntPairField::setValue(int value)
{

	value = tcrop(value, m_minValue, m_maxValue);
	value = tround(value * 100) * 0.01;
	if (m_grabIndex == 0) //Left grab
	{
		m_values.first = value;
		m_leftLineEdit->setValue(m_values.first);

		if (value > m_values.second) {
			m_values.second = value;
			m_rightLineEdit->setValue(m_values.second);
		}
	} else //Right grab
	{
		m_values.second = value;
		m_rightLineEdit->setValue(m_values.second);

		if (value < m_values.first) {
			m_values.first = value;
			m_leftLineEdit->setValue(m_values.first);
		}
	}
}

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

void IntPairField::setValues(const std::pair<int, int> &values)
{
	assert(values.first <= values.second);
	m_values.first = tcrop(values.first, m_minValue, m_maxValue);
	m_leftLineEdit->setValue(m_values.first);

	m_values.second = values.second;
	if (m_isMaxRangeLimited)
		m_values.second = tcrop(values.second, m_values.first, m_maxValue);
	m_rightLineEdit->setValue(m_values.second);

	update();
}

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

void IntPairField::setRange(int minValue, int maxValue)
{
	m_minValue = minValue;
	m_maxValue = maxValue;

	if (!m_isMaxRangeLimited)
		maxValue = (std::numeric_limits<int>::max)();
	m_leftLineEdit->setRange(minValue, maxValue);
	m_rightLineEdit->setRange(minValue, maxValue);

	update();
}

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

void IntPairField::getRange(int &minValue, int &maxValue)
{
	minValue = m_minValue;
	maxValue = m_maxValue;
}

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

void IntPairField::mousePressEvent(QMouseEvent *event)
{
	if (event->button() == Qt::LeftButton) {
		int x = event->pos().x();
		int cur0, cur1;
		if (m_values.first > m_maxValue)
			cur0 = value2pos(m_maxValue) - 5;
		else
			cur0 = value2pos(m_values.first);
		if (m_values.second > m_maxValue)
			cur1 = value2pos(m_maxValue);
		else
			cur1 = value2pos(m_values.second);
		int d0 = abs(cur0 - x);
		int d1 = abs(cur1 - x);
		int d, cur;
		if (d0 < d1 || (d0 == d1 && x < cur0)) {
			d = d0;
			cur = cur0;
			m_grabIndex = 0;
		} else {
			d = d1;
			cur = cur1;
			m_grabIndex = 1;
		}
		if (d < 6)
			m_grabOffset = cur - x;
		else {
			m_grabOffset = 0;
			setValue(pos2value(x));
			emit valuesChanged(true);
			update();
		}
	}
}

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

void IntPairField::mouseMoveEvent(QMouseEvent *event)
{
	if (event->buttons()) {
		std::pair<int, int> oldValues = m_values;
		int x = event->pos().x() + m_grabOffset;
		setValue(pos2value(x));
		if (oldValues == m_values)
			return;

		emit valuesChanged(true);
		update();
	}
}

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

void IntPairField::mouseReleaseEvent(QMouseEvent *event)
{
	m_grabOffset = 0;
	m_grabIndex = 0;
	emit valuesChanged(false);
}

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

void IntPairField::onLeftEditingFinished()
{
	int value = m_leftLineEdit->getValue();
	if (value == m_values.first)
		return;
	if (!m_isMaxRangeLimited && value < m_minValue)
		value = m_minValue;
	else if (m_isMaxRangeLimited)
		value = tcrop(value, m_minValue, m_maxValue);
	m_values.first = value;
	if (m_values.first > m_values.second) {
		m_values.second = m_values.first;
		m_rightLineEdit->setValue(m_values.second);
	}
	emit valuesChanged(false);
	update();
}

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

void IntPairField::onRightEditingFinished()
{
	int value = m_rightLineEdit->getValue();
	if (value == m_values.second)
		return;
	if (m_isMaxRangeLimited)
		value = tcrop(value, m_minValue, m_maxValue);
	m_values.second = value;
	if (m_values.second < m_values.first) {
		m_values.first = m_values.second;
		m_leftLineEdit->setValue(m_values.first);
	}
	emit valuesChanged(false);
	update();
}