Skip to content

Commit

Permalink
SpinBox: Added expression binding functionality.
Browse files Browse the repository at this point in the history
  • Loading branch information
eivindkv authored and wwmayer committed Sep 30, 2015
1 parent 014bb5b commit cbb4c52
Show file tree
Hide file tree
Showing 2 changed files with 191 additions and 2 deletions.
181 changes: 180 additions & 1 deletion src/Gui/SpinBox.cpp
Expand Up @@ -24,13 +24,24 @@
#include "PreCompiled.h"

#ifndef _PreComp_
# include <QDebug>
# include <climits>
# include <QStyle>
# include <QLineEdit>
# include <QKeyEvent>
#endif

#include "SpinBox.h"
#include "DlgExpressionInput.h"
#include "Command.h"
#include <Base/Tools.h>
#include <App/Expression.h>
#include <boost/math/special_functions/round.hpp>
#include "QuantitySpinBox_p.h"

using namespace Gui;

using namespace App;
using namespace Base;

UnsignedValidator::UnsignedValidator( QObject * parent )
: QValidator( parent )
Expand Down Expand Up @@ -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()
Expand Down Expand Up @@ -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<Expression> expr)
{
Q_ASSERT(isBound());

try {
ExpressionBinding::setExpression(expr);

if (getExpression()) {
std::auto_ptr<Expression> result(getExpression()->eval());
NumberExpression * value = freecad_dynamic_cast<NumberExpression>(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<Expression> result(getExpression()->eval());
NumberExpression * value = freecad_dynamic_cast<NumberExpression>(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<Gui::Dialog::DlgExpressionInput*>(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<Expression>());

box->deleteLater();
}

void UIntSpinBox::keyPressEvent(QKeyEvent *event)
{
if (event->text() == QString::fromUtf8("=") && isBound())
openFormulaDialog();
else {
if (!hasExpression())
QAbstractSpinBox::keyPressEvent(event);
}
}

#include "moc_SpinBox.cpp"
12 changes: 11 additions & 1 deletion src/Gui/SpinBox.h
Expand Up @@ -26,6 +26,7 @@

#include <QValidator>
#include <QSpinBox>
#include "ExpressionBinding.h"

namespace Gui {

Expand Down Expand Up @@ -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 )
Expand All @@ -83,6 +84,13 @@ class GuiExport UIntSpinBox : public QSpinBox
uint maximum() const;
void setMaximum( uint value );

void setExpression(boost::shared_ptr<App::Expression> 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 );

Expand All @@ -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;
Expand Down

0 comments on commit cbb4c52

Please sign in to comment.