#include "evalspinbox.h" #include "qad_types.h" #include "qpievaluator_p.h" #include #include #include #include #include #include #include #include #if QT_VERSION_MAJOR <= 5 # include #else # include #endif EvalSpinBox::EvalSpinBox(QWidget * parent): QAbstractSpinBox(parent) { status = new QWidget(lineEdit()); cw = new QWidget(lineEdit()); label = new QLabel(lineEdit()); eval = new QPIEvaluator(); clear_im.load(":/icons/edit-clear-locationbar-rtl.png"); icon_ok.load(":/icons/dialog-ok-apply.png"); icon_fail.load(":/icons/dialog-warning.png"); icon_calc.load(":/icons/tools-wizard.png"); icon = icon_ok; status->setCursor(Qt::ArrowCursor); status->setToolTip("OK -> 0"); status->hide(); cw->setCursor(Qt::ArrowCursor); cw->setToolTip(tr("Clear")); cw->hide(); cw->installEventFilter(this); status->installEventFilter(this); connect(lineEdit(), SIGNAL(textChanged(QString)), this, SLOT(textChanged_(QString))); connect(this, SIGNAL(editingFinished()), this, SLOT(setExpressionSlot())); label->setText("0"); } EvalSpinBox::~EvalSpinBox() { delete eval; delete label; delete cw; delete status; } bool EvalSpinBox::eventFilter(QObject * o, QEvent * e) { switch (e->type()) { case QEvent::MouseButtonRelease: if (o == cw) { clearMouseRelease(static_cast(e)); } break; case QEvent::Paint: if (o == status) { statusPaintEvent(); } if (o == cw) { cwPaintEvent(); } break; default: break; } return QAbstractSpinBox::eventFilter(o, e); } void EvalSpinBox::resizeIcons() { int is = fontHeight(this); int tm = (lineEdit()->height() - is + 1) / 2; QStyleOptionFrame so; so.initFrom(lineEdit()); QRect r = style()->subElementRect(QStyle::SE_LineEditContents, &so, lineEdit()); QMargins m = lineEdit()->textMargins(); int lwh = label->sizeHint().width(); label->setGeometry(lineEdit()->width() - m.left() - lwh + r.x() - 2, m.top() + r.y() + (r.height() - fontMetrics().height() + 1) / 2, lwh, // - 2*tm - (is * 1.2) * ((status->isVisible() ? 1 : 0) + (cw->isVisible() ? 1 : 0)), lineEdit()->height() - 2 * tm); status->setGeometry(lineEdit()->width() - (is + tm) * (cw->isVisible() ? 2 : 1), tm, is, is); cw->setGeometry(lineEdit()->width() - (is + tm) * 1, tm, is, is); m.setRight((is * 1.2) * ((status->isVisible() ? 1 : 0) + (cw->isVisible() ? 1 : 0))); lineEdit()->setTextMargins(m); } void EvalSpinBox::resizeEvent(QResizeEvent * e) { QAbstractSpinBox::resizeEvent(e); resizeIcons(); } void EvalSpinBox::changeEvent(QEvent * e) { QAbstractSpinBox::changeEvent(e); if (e->type() == QEvent::LanguageChange) { cw->setToolTip(tr("Clear")); return; } } void EvalSpinBox::cwPaintEvent() { QPainter p(cw); p.setRenderHint(QPainter::SmoothPixmapTransform); p.drawImage(cw->rect(), clear_im); } void EvalSpinBox::statusPaintEvent() { QPainter p(status); p.setRenderHint(QPainter::SmoothPixmapTransform); p.drawImage(status->rect(), icon); } void EvalSpinBox::clearMouseRelease(QMouseEvent * e) { if (cw->rect().contains(e->pos())) clear(); } void EvalSpinBox::textChanged_(const QString & text) { double pv = value(); QString t = text; cw->setVisible(text != dt && cw_visible); bool td = false; if (t.endsWith('=')) { td = true; t.chop(1); } bool ok = eval->check(t); if (ok) { eval->evaluate(); if (td) { icon = icon_calc; status->setToolTip("Enter to calc -> " + QString::number(value(), 'G', 10)); } else { icon = icon_ok; status->setToolTip("OK -> " + QString::number(value(), 'G', 10)); } if (pv != value()) { emit valueChanged(value()); } } else { icon = icon_fail; status->setToolTip(eval->error()); } resizeIcons(); } void EvalSpinBox::setExpressionSlot() { bool td = false; double pv = value(); QString t = text(); if (t.endsWith('=')) { td = true; t.chop(1); } if (eval->check(t)) { lineEdit()->setText(eval->expression()); eval->evaluate(); if (td) lineEdit()->setText(QString::number(value(), 'G', precision_ > 0 ? precision_ : 16)); status->setToolTip("OK -> " + QString::number(value(), 'G', 10)); icon = icon_ok; } else { icon = icon_fail; status->setToolTip(eval->error()); } if (!label->isHidden()) { if (eval->expression() != QString::number(value(), 'G', 10) && eval->expression() != QString::number(value(), 'G', 11) && eval->isCorrect()) label->setText("

-> " + QString::number(value(), 'G', 10) + "

"); else label->setText(""); lineEdit()->blockSignals(true); if (!eval->isCorrect()) { lineEdit()->setStyleSheet("color: darkred;"); status->show(); } else { lineEdit()->setStyleSheet(""); status->hide(); } lineEdit()->blockSignals(false); } if (pv != value()) emit valueChanged(value()); } void EvalSpinBox::setExpression(const QString & expr) { lineEdit()->setText(expr); cw->setVisible(text() != dt && cw_visible); setExpressionSlot(); } void EvalSpinBox::setValue(double val) { lineEdit()->setText(QString::number(val, 'G', precision_ > 0 ? precision_ : 16)); cw->setVisible(text() != dt && cw_visible); setExpressionSlot(); } void EvalSpinBox::stepBy(int steps) { stepByDouble(steps * m_singleStep); } void EvalSpinBox::clear() { lineEdit()->setText(dt); setExpressionSlot(); cw->hide(); resizeIcons(); emit cleared(); } double EvalSpinBox::value() const { if (eval->isCorrect()) { return eval->lastResult().real(); } return 0.; } const QString & EvalSpinBox::expression() const { return eval->expression(); } bool EvalSpinBox::isCleared() const { return (dt == eval->expression() || (value() == 0 && dt.isEmpty())); } QSize EvalSpinBox::sizeHint() const { QSize s = QAbstractSpinBox::sizeHint(); s.setWidth(120); return s; } QAbstractSpinBox::StepEnabled EvalSpinBox::stepEnabled() const { return StepUpEnabled | StepDownEnabled; } void EvalSpinBox::focusInEvent(QFocusEvent * event) { label->hide(); status->show(); lineEdit()->blockSignals(true); lineEdit()->setStyleSheet(""); if (eval->expression() == "0") lineEdit()->clear(); lineEdit()->blockSignals(false); QAbstractSpinBox::focusInEvent(event); resizeIcons(); } void EvalSpinBox::focusOutEvent(QFocusEvent * event) { QAbstractSpinBox::focusOutEvent(event); if (eval->expression() != QString::number(value(), 'G', 10) && eval->expression() != QString::number(value(), 'G', 11) && eval->isCorrect()) { label->setText("

-> " + QString::number(value(), 'G', 10) + "

"); } else { label->setText(""); } if (calc_visible) { label->show(); } lineEdit()->blockSignals(true); if (!eval->isCorrect()) lineEdit()->setStyleSheet("color: darkred;"); else status->hide(); lineEdit()->blockSignals(false); resizeIcons(); } void EvalSpinBox::wheelEvent(QWheelEvent * event) { if (event->modifiers().testFlag(Qt::ShiftModifier)) { stepByDouble(( #if QT_VERSION < QT_VERSION_CHECK(5, 14, 0) event->delta() #else event->angleDelta().y() #endif > 0 ? 0.1 : -0.1) * m_singleStep); } else { QAbstractSpinBox::wheelEvent(event); } } void EvalSpinBox::stepByDouble(double steps) { if (isReadOnly()) return; QString t = text(); if (eval->check(t)) { t = eval->expression(); #if QT_VERSION_MAJOR <= 5 QRegExp re("[+-]?([0-9]+([.][0-9]*)?|[.][0-9]+)"); int pos = 0; if ((pos = re.indexIn(t)) != -1) { double v = t.mid(pos, re.matchedLength()).toDouble(); v += steps; t.remove(pos, re.matchedLength()); t.insert(pos, QString::number(v)); } else { double v = steps; t = QString::number(v) + t; } #else QRegularExpression re("[+-]?([0-9]+([.][0-9]*)?|[.][0-9]+)"); QRegularExpressionMatchIterator i = re.globalMatch(t); if (i.hasNext()) { QRegularExpressionMatch match = i.next(); double v = t.mid(match.capturedStart(), match.capturedLength()).toDouble(); v += steps; t.remove(match.capturedStart(), match.capturedLength()); t.insert(match.capturedStart(), QString::number(v)); } else { double v = steps; t = QString::number(v) + t; } #endif eval->check(t); lineEdit()->setText(eval->expression()); } } void EvalSpinBox::setDefaultText(const QString & t) { dt = t; cw->setVisible((eval->expression() != dt || (dt.isEmpty() && eval->expression() == "0")) && cw_visible); resizeIcons(); } void EvalSpinBox::setClearButtonVisible(bool visible) { cw_visible = visible; cw->setVisible((eval->expression() != dt || (dt.isEmpty() && eval->expression() == "0")) && cw_visible); resizeIcons(); } void EvalSpinBox::setCalculationVisible(bool visible) { calc_visible = visible; setExpressionSlot(); if (!calc_visible) { label->hide(); } }