| |
| |
| #include "toonzqt/intfield.h" |
| #include "toonzqt/dvdialog.h" |
| #include "toonzqt/gutil.h" |
| |
| #include <QIntValidator> |
| #include <QSlider> |
| #include <QHBoxLayout> |
| #include <QAction> |
| #include <QFocusEvent> |
| #include <QPainter> |
| |
| namespace { |
| const int NonLinearSliderPrecision = 2; |
| } |
| |
| using namespace DVGui; |
| |
| |
| |
| |
| |
| 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(QWidget *parent, int value, int minValue, int maxValue, |
| int showedDigits) |
| : LineEdit(parent), m_showedDigits(showedDigits) { |
| setFixedWidth(40); |
| |
| 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); |
| |
| |
| |
| |
| |
| 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); |
| m_isTyping = false; |
| } |
| |
| |
| |
| |
| void IntLineEdit::setLineEditBackgroundColor(QColor color) { |
| |
| int value = 0; |
| double luminescence = ((0.299 * color.red()) + (0.587 * color.green()) + |
| (0.114 * color.blue())) / |
| 255; |
| if (luminescence > 0.5) |
| value = 0; |
| else |
| value = 255; |
| |
| QString sheet = |
| QString("background-color: rgba(") + QString::number(color.red()) + |
| QString(",") + QString::number(color.green()) + QString(",") + |
| QString::number(color.blue()) + QString(",") + |
| QString::number(color.alpha()) + |
| QString(");" + |
| QString("color: rgb(" + QString::number(value) + QString(",") + |
| QString::number(value) + QString(",") + |
| QString::number(value) + QString(");"))); |
| setStyleSheet(sheet); |
| } |
| |
| |
| |
| void IntLineEdit::mousePressEvent(QMouseEvent *e) { |
| if (e->buttons() == Qt::MiddleButton) { |
| m_xMouse = e->x(); |
| m_mouseDragEditing = true; |
| } else { |
| QLineEdit::mousePressEvent(e); |
| if (!m_isTyping) { |
| selectAll(); |
| m_isTyping = true; |
| } |
| } |
| } |
| |
| |
| |
| void IntLineEdit::mouseMoveEvent(QMouseEvent *e) { |
| if (e->buttons() == Qt::MiddleButton) { |
| setValue(getValue() + ((e->x() - m_xMouse) / 2)); |
| m_xMouse = e->x(); |
| } else |
| QLineEdit::mouseMoveEvent(e); |
| } |
| |
| |
| |
| void IntLineEdit::mouseReleaseEvent(QMouseEvent *e) { |
| if ((e->buttons() == Qt::NoButton && m_mouseDragEditing)) { |
| m_mouseDragEditing = false; |
| clearFocus(); |
| } else |
| QLineEdit::mouseReleaseEvent(e); |
| } |
| |
| |
| |
| |
| |
| IntField::IntField(QWidget *parent, bool isMaxRangeLimited, bool isRollerHide) |
| : QWidget(parent) |
| , m_lineEdit(0) |
| , m_slider(0) |
| , m_roller(0) |
| , m_isMaxRangeLimited(isMaxRangeLimited) |
| , m_isLinearSlider(true) { |
| 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)()); |
| if (m_isLinearSlider) |
| m_slider->setRange(minValue, maxValue); |
| else |
| m_slider->setRange(minValue * pow(10., NonLinearSliderPrecision), |
| maxValue * pow(10., NonLinearSliderPrecision)); |
| m_roller->setRange(minValue, maxValue); |
| } |
| |
| |
| |
| void IntField::setValue(int value) { |
| if (m_lineEdit->getValue() == value) return; |
| m_lineEdit->setValue(value); |
| m_slider->setSliderPosition(value2pos(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); |
| } |
| |
| |
| |
| int IntField::pos2value(int x) const { |
| if (m_isLinearSlider) return x; |
| |
| |
| double rangeSize = (double)(m_slider->maximum() - m_slider->minimum()); |
| double posRatio = (double)(x - m_slider->minimum()) / rangeSize; |
| double t; |
| if (posRatio <= 0.5) |
| t = 0.04 * posRatio; |
| else if (posRatio <= 0.75) |
| t = -0.02 + 0.08 * posRatio; |
| else if (posRatio <= 0.9) |
| t = -0.26 + 0.4 * posRatio; |
| else |
| t = -8.0 + 9.0 * posRatio; |
| double sliderVal = (double)m_slider->minimum() + rangeSize * t; |
| return (int)round(sliderVal * pow(0.1, NonLinearSliderPrecision)); |
| } |
| |
| |
| |
| int IntField::value2pos(int v) const { |
| if (m_isLinearSlider) return v; |
| |
| |
| double sliderVal = (double)v * pow(10., NonLinearSliderPrecision); |
| double rangeSize = (double)(m_slider->maximum() - m_slider->minimum()); |
| double valueRatio = (double)(sliderVal - m_slider->minimum()) / rangeSize; |
| double t; |
| if (valueRatio <= 0.02) |
| t = valueRatio / 0.04; |
| else if (valueRatio <= 0.04) |
| t = (valueRatio + 0.02) / 0.08; |
| else if (valueRatio <= 0.1) |
| t = (valueRatio + 0.26) / 0.4; |
| else |
| t = (valueRatio + 8.0) / 9.0; |
| return m_slider->minimum() + (int)(t * rangeSize); |
| } |
| |
| |
| |
| void IntField::onSliderChanged(int sliderPos) { |
| int value = pos2value(sliderPos); |
| |
| |
| if (m_lineEdit->getValue() == value || |
| ((int)m_roller->getValue() == value && m_roller->isVisible())) |
| return; |
| m_lineEdit->setValue(value); |
| m_roller->setValue((double)value); |
| |
| |
| |
| m_lineEdit->setCursorPosition(0); |
| emit valueChanged(true); |
| } |
| |
| |
| |
| void IntField::onEditingFinished() { |
| double value = m_lineEdit->getValue(); |
| |
| |
| if ((pos2value(m_slider->value()) == value && m_slider->isVisible()) || |
| ((int)m_roller->getValue() == value && m_roller->isVisible())) |
| return; |
| m_slider->setValue(value2pos(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(pos2value(m_slider->value()) == value || !m_slider->isVisible()); |
| |
| |
| if (!isDragging) emit valueChanged(isDragging); |
| return; |
| } |
| m_slider->setValue(value2pos(value)); |
| m_lineEdit->setValue(value); |
| |
| |
| |
| |
| m_lineEdit->setCursorPosition(0); |
| |
| emit valueChanged(isDragging); |
| } |
| |