From cbb4c52310cc94820c4e0445593772c0f63e1809 Mon Sep 17 00:00:00 2001 From: Eivind Kvedalen Date: Mon, 28 Sep 2015 22:03:22 +0200 Subject: [PATCH] SpinBox: Added expression binding functionality. --- src/Gui/SpinBox.cpp | 181 +++++++++++++++++++++++++++++++++++++++++++- src/Gui/SpinBox.h | 12 ++- 2 files changed, 191 insertions(+), 2 deletions(-) diff --git a/src/Gui/SpinBox.cpp b/src/Gui/SpinBox.cpp index 21edf56f8..7ca51f945 100644 --- a/src/Gui/SpinBox.cpp +++ b/src/Gui/SpinBox.cpp @@ -24,13 +24,24 @@ #include "PreCompiled.h" #ifndef _PreComp_ +# include # include +# include +# include +# include #endif #include "SpinBox.h" +#include "DlgExpressionInput.h" +#include "Command.h" +#include +#include +#include +#include "QuantitySpinBox_p.h" using namespace Gui; - +using namespace App; +using namespace Base; UnsignedValidator::UnsignedValidator( QObject * parent ) : QValidator( parent ) @@ -135,6 +146,22 @@ UIntSpinBox::UIntSpinBox (QWidget* parent) setRange(0, 99); setValue(0); updateValidator(); + + defaultPalette = lineEdit()->palette(); + + /* Icon for f(x) */ + QFontMetrics fm(lineEdit()->font()); + int frameWidth = style()->pixelMetric(QStyle::PM_SpinBoxFrameWidth); + iconHeight = fm.height() - frameWidth; + iconLabel = new ExpressionLabel(lineEdit()); + iconLabel->setCursor(Qt::ArrowCursor); + QPixmap pixmap = getIcon(":/icons/bound-expression-unset.svg", QSize(iconHeight, iconHeight)); + iconLabel->setPixmap(pixmap); + iconLabel->setStyleSheet(QString::fromAscii("QLabel { border: none; padding: 0px; padding-top: %2px; width: %1px; height: %1px }").arg(iconHeight).arg(frameWidth/2)); + iconLabel->hide(); + lineEdit()->setStyleSheet(QString::fromAscii("QLineEdit { padding-right: %1px } ").arg(iconHeight+frameWidth)); + + QObject::connect(iconLabel, SIGNAL(clicked()), this, SLOT(openFormulaDialog())); } UIntSpinBox::~UIntSpinBox() @@ -223,4 +250,156 @@ void UIntSpinBox::updateValidator() d->mValidator->setRange(this->minimum(), this->maximum()); } +void UIntSpinBox::bind(const App::ObjectIdentifier &_path) +{ + ExpressionBinding::bind(_path); + + int frameWidth = style()->pixelMetric(QStyle::PM_SpinBoxFrameWidth); + lineEdit()->setStyleSheet(QString::fromAscii("QLineEdit { padding-right: %1px } ").arg(iconLabel->sizeHint().width() + frameWidth + 1)); + + iconLabel->show(); +} + +void UIntSpinBox::setExpression(boost::shared_ptr expr) +{ + Q_ASSERT(isBound()); + + try { + ExpressionBinding::setExpression(expr); + + if (getExpression()) { + std::auto_ptr result(getExpression()->eval()); + NumberExpression * value = freecad_dynamic_cast(result.get()); + + if (value) { + setValue(boost::math::round(value->getValue())); + setReadOnly(true); + iconLabel->setPixmap(getIcon(":/icons/bound-expression.svg", QSize(iconHeight, iconHeight))); + + QPalette p(lineEdit()->palette()); + p.setColor(QPalette::Text, Qt::lightGray); + lineEdit()->setPalette(p); + } + setToolTip(Base::Tools::fromStdString(getExpression()->toString())); + } + else { + setReadOnly(false); + iconLabel->setPixmap(getIcon(":/icons/bound-expression-unset.svg", QSize(iconHeight, iconHeight))); + QPalette p(lineEdit()->palette()); + p.setColor(QPalette::Active, QPalette::Text, defaultPalette.color(QPalette::Text)); + lineEdit()->setPalette(p); + + } + iconLabel->setToolTip(QString()); + } + catch (const Base::Exception & e) { + setReadOnly(true); + QPalette p(lineEdit()->palette()); + p.setColor(QPalette::Active, QPalette::Text, Qt::red); + lineEdit()->setPalette(p); + iconLabel->setToolTip(QString::fromAscii(e.what())); + } +} + +bool UIntSpinBox::apply(const std::string & propName) +{ + if (!ExpressionBinding::apply(propName)) { + Gui::Command::doCommand(Gui::Command::Doc, "%s = %u", propName.c_str(), value()); + return true; + } + else + return false; +} + +bool UIntSpinBox::apply() +{ + return ExpressionBinding::apply(); +} + +void UIntSpinBox::resizeEvent(QResizeEvent * event) +{ + QAbstractSpinBox::resizeEvent(event); + + int frameWidth = style()->pixelMetric(QStyle::PM_SpinBoxFrameWidth); + + QSize sz = iconLabel->sizeHint(); + iconLabel->move(lineEdit()->rect().right() - frameWidth - sz.width(), 0); + + try { + if (isBound() && getExpression()) { + std::auto_ptr result(getExpression()->eval()); + NumberExpression * value = freecad_dynamic_cast(result.get()); + + if (value) { + setReadOnly(true); + QPixmap pixmap = getIcon(":/icons/bound-expression.svg", QSize(iconHeight, iconHeight)); + iconLabel->setPixmap(pixmap); + + QPalette p(lineEdit()->palette()); + p.setColor(QPalette::Text, Qt::lightGray); + lineEdit()->setPalette(p); + } + setToolTip(Base::Tools::fromStdString(getExpression()->toString())); + } + else { + setReadOnly(false); + QPixmap pixmap = getIcon(":/icons/bound-expression-unset.svg", QSize(iconHeight, iconHeight)); + iconLabel->setPixmap(pixmap); + + QPalette p(lineEdit()->palette()); + p.setColor(QPalette::Active, QPalette::Text, defaultPalette.color(QPalette::Text)); + lineEdit()->setPalette(p); + + } + iconLabel->setToolTip(QString()); + } + catch (const Base::Exception & e) { + setReadOnly(true); + QPalette p(lineEdit()->palette()); + p.setColor(QPalette::Active, QPalette::Text, Qt::red); + lineEdit()->setPalette(p); + iconLabel->setToolTip(QString::fromAscii(e.what())); + } + +} + +void UIntSpinBox::openFormulaDialog() +{ + Q_ASSERT(isBound()); + + Gui::Dialog::DlgExpressionInput* box = new Gui::Dialog::DlgExpressionInput(getPath(), getExpression(), Unit(), this); + connect(box, SIGNAL(finished(int)), this, SLOT(finishFormulaDialog())); + box->show(); + + QPoint pos = mapToGlobal(QPoint(0,0)); + box->move(pos-box->expressionPosition()); + box->setExpressionInputSize(width(), height()); +} + +void UIntSpinBox::finishFormulaDialog() +{ + Gui::Dialog::DlgExpressionInput* box = qobject_cast(sender()); + if (!box) { + qWarning() << "Sender is not a Gui::Dialog::DlgExpressionInput"; + return; + } + + if (box->result() == QDialog::Accepted) + setExpression(box->getExpression()); + else if (box->discardedFormula()) + setExpression(boost::shared_ptr()); + + box->deleteLater(); +} + +void UIntSpinBox::keyPressEvent(QKeyEvent *event) +{ + if (event->text() == QString::fromUtf8("=") && isBound()) + openFormulaDialog(); + else { + if (!hasExpression()) + QAbstractSpinBox::keyPressEvent(event); + } +} + #include "moc_SpinBox.cpp" diff --git a/src/Gui/SpinBox.h b/src/Gui/SpinBox.h index 72f61528d..7f7d6442f 100644 --- a/src/Gui/SpinBox.h +++ b/src/Gui/SpinBox.h @@ -26,6 +26,7 @@ #include #include +#include "ExpressionBinding.h" namespace Gui { @@ -64,7 +65,7 @@ class UIntSpinBoxPrivate; * This allows to use numbers in the range of [0, UINT_MAX] * @author Werner Mayer */ -class GuiExport UIntSpinBox : public QSpinBox +class GuiExport UIntSpinBox : public QSpinBox, public ExpressionBinding { Q_OBJECT Q_OVERRIDE( uint maximum READ maximum WRITE setMaximum ) @@ -83,6 +84,13 @@ public: uint maximum() const; void setMaximum( uint value ); + void setExpression(boost::shared_ptr expr); + void bind(const App::ObjectIdentifier &_path); + bool apply(const std::string &propName); + bool apply(); + + void keyPressEvent(QKeyEvent *event); + void resizeEvent(QResizeEvent *event); Q_SIGNALS: void valueChanged( uint value ); @@ -91,6 +99,8 @@ public Q_SLOTS: private Q_SLOTS: void valueChange( int value ); + void finishFormulaDialog(); + void openFormulaDialog(); protected: virtual QString textFromValue ( int v ) const;