338 lines
9.6 KiB
C++
338 lines
9.6 KiB
C++
#include "evalspinbox.h"
|
|
#include <QLineEdit>
|
|
#include <QLabel>
|
|
#include <QDebug>
|
|
#include <QRegExp>
|
|
#include <QPainter>
|
|
#include <QTimer>
|
|
#include <QStyle>
|
|
#include <QStyleOptionSpinBox>
|
|
#include "qad_types.h"
|
|
|
|
|
|
EvalSpinBox::EvalSpinBox(QWidget * parent): QAbstractSpinBox(parent) {
|
|
status = new QWidget(lineEdit());
|
|
cw = new QWidget(lineEdit());
|
|
label = new QLabel(lineEdit());
|
|
// label->hide();
|
|
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_visible = false;
|
|
//lineEdit()->setStyleSheet("color: darkgreen;");
|
|
//lineEdit()->setText(eval.expression() + " -> " + QString::number(value(), 'G', 10));
|
|
cw->installEventFilter(this);
|
|
status->installEventFilter(this);
|
|
connect(lineEdit(), SIGNAL(textChanged(QString)), this, SLOT(textChanged_(QString)));
|
|
connect(this, SIGNAL(editingFinished()), this, SLOT(setExpression_()));
|
|
label->setText("0");
|
|
//connect(cw, SIGNAL(mouseReleaseEvent(QMouseEvent * )), this, SLOT(clearMouseRelease(QMouseEvent * )));
|
|
}
|
|
|
|
|
|
EvalSpinBox::~EvalSpinBox() {
|
|
delete cw;
|
|
delete status;
|
|
delete label;
|
|
}
|
|
|
|
|
|
bool EvalSpinBox::eventFilter(QObject * o, QEvent * e) {
|
|
switch (e->type()) {
|
|
case QEvent::MouseButtonRelease:
|
|
if (o == cw) clearMouseRelease((QMouseEvent * )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();
|
|
int tm = (lineEdit()->height() - is + 1) / 2;
|
|
QStyleOptionFrame so;
|
|
so.initFrom(lineEdit());
|
|
QRect r = style()->subElementRect(QStyle::SE_LineEditContents, &so, lineEdit());
|
|
int m0, m1, m2, m3;
|
|
lineEdit()->getTextMargins(&m0, &m1, &m2, &m3);
|
|
//label->setGeometry(m0 + r.x() + 2, m1 + r.y() + (r.height() - fontMetrics().height() + 1) / 2, lineEdit()->width() - 2*tm - (is * 1.2) * ((status->isVisible() ? 1 : 0) + (cw->isVisible() ? 1 : 0)), lineEdit()->height() - 2*tm);
|
|
int lwh = label->sizeHint().width();
|
|
label->setGeometry(lineEdit()->width() - m0 - lwh + r.x() - 2,
|
|
m1 + 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);
|
|
lineEdit()->setTextMargins(m0, m1, (is * 1.2) * ((status->isVisible() ? 1 : 0) + (cw->isVisible() ? 1 : 0)), m3);
|
|
}
|
|
|
|
|
|
void EvalSpinBox::resizeEvent(QResizeEvent * e) {
|
|
QAbstractSpinBox::resizeEvent(e);
|
|
resizeIcons();
|
|
}
|
|
|
|
|
|
void EvalSpinBox::changeEvent(QEvent * e) {
|
|
if (e->type() == QEvent::LanguageChange) {
|
|
cw->setToolTip(tr("Clear"));
|
|
return;
|
|
}
|
|
QAbstractSpinBox::changeEvent(e);
|
|
}
|
|
|
|
|
|
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));
|
|
}
|
|
// qDebug() << "value =" << value();
|
|
if (pv != value()) emit valueChanged(value());
|
|
} else {
|
|
icon = icon_fail;
|
|
status->setToolTip(eval.error());
|
|
}
|
|
resizeIcons();
|
|
}
|
|
|
|
|
|
void EvalSpinBox::setExpression_() {
|
|
bool td = false;
|
|
double pv = value();
|
|
QString t = text();
|
|
if (t.endsWith('=')) {
|
|
td = true;
|
|
t.chop(1);
|
|
}
|
|
if (eval.check(t)) {
|
|
/*if (eval.expression() == "0") lineEdit()->clear();
|
|
else*/ lineEdit()->setText(eval.expression());
|
|
eval.evaluate();
|
|
if (td) lineEdit()->setText(QString::number(value(), 'G', 10));
|
|
status->setToolTip("OK -> " + QString::number(value(), 'G', 10));
|
|
icon = icon_ok;
|
|
} else {
|
|
icon = icon_fail;
|
|
status->setToolTip(eval.error());
|
|
// qDebug() << eval.expression();
|
|
}
|
|
if (!label->isHidden()) {
|
|
// if (eval.expression() != QString::number(value(), 'G', 10) && eval.expression() != QString::number(value(), 'G', 11) && eval.isCorrect())
|
|
// label->setText("<html><head/><body><p>" + eval.expression() + " <span style=\"color:#005500;\">-> " + QString::number(value(), 'G', 10) + "</span></p></body></html>");
|
|
// else
|
|
// label->setText(eval.expression());
|
|
if (eval.expression() != QString::number(value(), 'G', 10) && eval.expression() != QString::number(value(), 'G', 11) && eval.isCorrect())
|
|
label->setText("<html><head/><body><p><span style=\"color:#005500;\">-> " + QString::number(value(), 'G', 10) + "</span></p></body></html>");
|
|
else
|
|
label->setText("");
|
|
lineEdit()->blockSignals(true);
|
|
if (!eval.isCorrect()) {
|
|
lineEdit()->setStyleSheet("color: darkred;");
|
|
status->show();
|
|
} else {
|
|
lineEdit()->setStyleSheet("");
|
|
status->hide();
|
|
}
|
|
// lineEdit()->setText(eval.expression() + " -> " + QString::number(value(), 'G', 10));
|
|
//lineEdit()->setText("");
|
|
lineEdit()->blockSignals(false);
|
|
}
|
|
|
|
// qDebug() << "value =" << value();
|
|
if (pv != value()) emit valueChanged(value());
|
|
}
|
|
|
|
|
|
void EvalSpinBox::setExpression(const QString & expr) {
|
|
lineEdit()->setText(expr);
|
|
//if (eval.expression() == "0") lineEdit()->clear();
|
|
cw->setVisible(text() != dt && cw_visible);
|
|
setExpression_();
|
|
}
|
|
|
|
|
|
void EvalSpinBox::setValue(double val) {
|
|
lineEdit()->setText(QString::number(val, 'G', 16));
|
|
//if (val == 0) lineEdit()->clear();
|
|
cw->setVisible(text() != dt && cw_visible);
|
|
setExpression_();
|
|
}
|
|
|
|
|
|
void EvalSpinBox::stepBy(int steps) {
|
|
stepByDouble(steps);
|
|
}
|
|
|
|
|
|
void EvalSpinBox::clear() {
|
|
lineEdit()->setText(dt);
|
|
setExpression_();
|
|
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) {
|
|
// qDebug() << "focus_in";
|
|
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);
|
|
// qDebug() << eval.expression() << QString::number(value(), 'G', 10);
|
|
// if (eval.expression() != QString::number(value(), 'G', 10) && eval.expression() != QString::number(value(), 'G', 11) && eval.isCorrect())
|
|
// label->setText("<html><head/><body><p>" + eval.expression() + " <span style=\"color:#005500;\">-> " + QString::number(value(), 'G', 10) + "</span></p></body></html>");
|
|
// else
|
|
// label->setText(eval.expression());
|
|
if (eval.expression() != QString::number(value(), 'G', 10) && eval.expression() != QString::number(value(), 'G', 11) && eval.isCorrect())
|
|
label->setText("<html><head/><body><p><span style=\"color:#005500;\">-> " + QString::number(value(), 'G', 10) + "</span></p></body></html>");
|
|
else
|
|
label->setText("");
|
|
label->show();
|
|
lineEdit()->blockSignals(true);
|
|
if (!eval.isCorrect()) lineEdit()->setStyleSheet("color: darkred;");
|
|
else status->hide();
|
|
// lineEdit()->setText(eval.expression() + " -> " + QString::number(value(), 'G', 10));
|
|
//lineEdit()->clear();
|
|
lineEdit()->blockSignals(false);
|
|
resizeIcons();
|
|
}
|
|
|
|
|
|
void EvalSpinBox::wheelEvent(QWheelEvent * event) {
|
|
if (event->modifiers().testFlag(Qt::ShiftModifier))
|
|
stepByDouble(event->delta() > 0 ? 0.1 : -0.1);
|
|
else
|
|
QAbstractSpinBox::wheelEvent(event);
|
|
}
|
|
|
|
|
|
void EvalSpinBox::stepByDouble(double steps) {
|
|
//qDebug() << "step" << steps;
|
|
if (isReadOnly()) return;
|
|
QString t = text();
|
|
if (eval.check(t)) {
|
|
t = eval.expression();
|
|
//QRegExp re("(\\-?\\d+)");
|
|
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;
|
|
}
|
|
eval.check(t);
|
|
lineEdit()->setText(eval.expression());
|
|
}
|
|
}
|
|
|
|
|
|
void EvalSpinBox::setDefaultText(const QString & t) {
|
|
// bool def = (!cw->isHidden());
|
|
dt = t;
|
|
// if (def) {
|
|
// lineEdit()->setText(dt);
|
|
// setExpression_();
|
|
// }
|
|
//if (t == eval.expression() || (value() == 0 && t.isEmpty())) clear();
|
|
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();
|
|
}
|