From 580a4e15d13d8eb6574c2a1eb3355af5acc11849 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Stefan=20Tr=C3=B6ger?= Date: Mon, 12 Oct 2015 20:56:14 +0200 Subject: [PATCH] Expressions: port int spinbox for property editor --- src/Gui/SpinBox.cpp | 176 ++++++++++++++++++++++++ src/Gui/SpinBox.h | 27 +++- src/Gui/propertyeditor/PropertyItem.cpp | 41 +++++- src/Gui/propertyeditor/PropertyItem.h | 2 + 4 files changed, 240 insertions(+), 6 deletions(-) diff --git a/src/Gui/SpinBox.cpp b/src/Gui/SpinBox.cpp index d100ce9e6..da53f1535 100644 --- a/src/Gui/SpinBox.cpp +++ b/src/Gui/SpinBox.cpp @@ -406,6 +406,182 @@ void UIntSpinBox::keyPressEvent(QKeyEvent *event) } } + +IntSpinBox::IntSpinBox(QWidget* parent) : QSpinBox(parent) { + + 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())); +} + +IntSpinBox::~IntSpinBox() { + +} + + +bool IntSpinBox::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; +} + +void IntSpinBox::bind(const 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 IntSpinBox::setExpression(boost::shared_ptr expr) +{ + Q_ASSERT(isBound()); + + try { + ExpressionBinding::setExpression(expr); + } + 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 IntSpinBox::onChange() { + + 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()); +} + +void IntSpinBox::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 IntSpinBox::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 IntSpinBox::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 IntSpinBox::keyPressEvent(QKeyEvent *event) +{ + if (event->text() == QString::fromUtf8("=") && isBound()) + openFormulaDialog(); + else { + if (!hasExpression()) + QAbstractSpinBox::keyPressEvent(event); + } +} + + DoubleSpinBox::DoubleSpinBox(QWidget* parent): QDoubleSpinBox(parent) { defaultPalette = lineEdit()->palette(); diff --git a/src/Gui/SpinBox.h b/src/Gui/SpinBox.h index 9f2ab474a..14b0dffab 100644 --- a/src/Gui/SpinBox.h +++ b/src/Gui/SpinBox.h @@ -112,7 +112,32 @@ private: UIntSpinBoxPrivate * d; }; -class DoubleSpinBoxPrivate; + +/** + * The IntSpinBox class does exactly the same as Qt's QSpinBox but has expression support + * @author Stefan Tröger + */ +class GuiExport IntSpinBox : public QSpinBox, public ExpressionBinding +{ + Q_OBJECT + +public: + IntSpinBox ( QWidget* parent=0 ); + virtual ~IntSpinBox(); + + void setExpression(boost::shared_ptr expr); + void bind(const App::ObjectIdentifier &_path); + bool apply(const std::string &propName); + + void keyPressEvent(QKeyEvent *event); + void resizeEvent(QResizeEvent *event); + +private Q_SLOTS: + void finishFormulaDialog(); + void openFormulaDialog(); + virtual void onChange(); +}; + /** * The DoubleSpinBox class does exactly the same as Qt's QDoubleSpinBox but has expression * support diff --git a/src/Gui/propertyeditor/PropertyItem.cpp b/src/Gui/propertyeditor/PropertyItem.cpp index ac86658cf..19c83851b 100644 --- a/src/Gui/propertyeditor/PropertyItem.cpp +++ b/src/Gui/propertyeditor/PropertyItem.cpp @@ -30,7 +30,6 @@ # include # include # include -# include # include # include #endif @@ -555,10 +554,16 @@ void PropertyIntegerItem::setValue(const QVariant& value) QWidget* PropertyIntegerItem::createEditor(QWidget* parent, const QObject* receiver, const char* method) const { - QSpinBox *sb = new QSpinBox(parent); + Gui::IntSpinBox *sb = new Gui::IntSpinBox(parent); sb->setFrame(false); sb->setReadOnly(isReadOnly()); QObject::connect(sb, SIGNAL(valueChanged(int)), receiver, method); + + if(isBound()) { + sb->bind(getPath()); + sb->setAutoApply(true); + } + return sb; } @@ -575,6 +580,16 @@ QVariant PropertyIntegerItem::editorData(QWidget *editor) const return QVariant(sb->value()); } +QVariant PropertyIntegerItem::toString(const QVariant& v) const { + QString string(PropertyItem::toString(v).toString()); + + if(hasExpression()) + string += QString::fromAscii(" ( %1 )").arg(QString::fromStdString(getExpressionString())); + + return QVariant(string); +} + + // -------------------------------------------------------------------- TYPESYSTEM_SOURCE(Gui::PropertyEditor::PropertyIntegerConstraintItem, Gui::PropertyEditor::PropertyItem); @@ -602,10 +617,16 @@ void PropertyIntegerConstraintItem::setValue(const QVariant& value) QWidget* PropertyIntegerConstraintItem::createEditor(QWidget* parent, const QObject* receiver, const char* method) const { - QSpinBox *sb = new QSpinBox(parent); + Gui::IntSpinBox *sb = new Gui::IntSpinBox(parent); sb->setFrame(false); sb->setReadOnly(isReadOnly()); QObject::connect(sb, SIGNAL(valueChanged(int)), receiver, method); + + if(isBound()) { + sb->bind(getPath()); + sb->setAutoApply(true); + } + return sb; } @@ -634,6 +655,17 @@ QVariant PropertyIntegerConstraintItem::editorData(QWidget *editor) const return QVariant(sb->value()); } +QVariant PropertyIntegerConstraintItem::toString(const QVariant& v) const { + + QString string(PropertyItem::toString(v).toString()); + + if(hasExpression()) + string += QString::fromAscii(" ( %1 )").arg(QString::fromStdString(getExpressionString())); + + return QVariant(string); +} + + // -------------------------------------------------------------------- TYPESYSTEM_SOURCE(Gui::PropertyEditor::PropertyFloatItem, Gui::PropertyEditor::PropertyItem); @@ -682,8 +714,7 @@ QWidget* PropertyFloatItem::createEditor(QWidget* parent, const QObject* receive sb->bind(getPath()); sb->setAutoApply(true); } - - + return sb; } diff --git a/src/Gui/propertyeditor/PropertyItem.h b/src/Gui/propertyeditor/PropertyItem.h index 82d664fc7..8ce031980 100644 --- a/src/Gui/propertyeditor/PropertyItem.h +++ b/src/Gui/propertyeditor/PropertyItem.h @@ -189,6 +189,7 @@ class GuiExport PropertyIntegerItem: public PropertyItem virtual QVariant editorData(QWidget *editor) const; protected: + virtual QVariant toString(const QVariant&) const; virtual QVariant value(const App::Property*) const; virtual void setValue(const QVariant&); @@ -209,6 +210,7 @@ class GuiExport PropertyIntegerConstraintItem: public PropertyItem virtual QVariant editorData(QWidget *editor) const; protected: + virtual QVariant toString(const QVariant&) const; virtual QVariant value(const App::Property*) const; virtual void setValue(const QVariant&);