1
/***************************************************************************
2
* Copyright (c) 2006 Werner Mayer <werner.wm.mayer@gmx.de> *
4
* This file is part of the FreeCAD CAx development system. *
6
* This library is free software; you can redistribute it and/or *
7
* modify it under the terms of the GNU Library General Public *
8
* License as published by the Free Software Foundation; either *
9
* version 2 of the License, or (at your option) any later version. *
11
* This library is distributed in the hope that it will be useful, *
12
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
13
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
14
* GNU Library General Public License for more details. *
16
* You should have received a copy of the GNU Library General Public *
17
* License along with this library; see the file COPYING.LIB. If not, *
18
* write to the Free Software Foundation, Inc., 59 Temple Place, *
19
* Suite 330, Boston, MA 02111-1307, USA *
21
***************************************************************************/
24
#include <QApplication>
25
#include <QColorDialog>
30
#include <QRegularExpression>
31
#include <QRegularExpressionMatch>
32
#include <QStyleOptionButton>
33
#include <QStylePainter>
38
#include "customwidgets.h"
43
UrlLabel::UrlLabel(QWidget* parent, Qt::WindowFlags f)
44
: QLabel("TextLabel", parent, f)
46
_url = "http://localhost";
47
setToolTip(this->_url);
48
setCursor(Qt::PointingHandCursor);
54
void UrlLabel::mouseReleaseEvent(QMouseEvent*)
56
QMessageBox::information(this,
58
QString("This starts your browser with url %1").arg(_url));
61
QString UrlLabel::url() const
66
void UrlLabel::setUrl(const QString& u)
69
setToolTip(this->_url);
72
LocationWidget::LocationWidget(QWidget* parent)
75
box = new QGridLayout();
77
xValue = new QDoubleSpinBox(this);
78
xValue->setMinimum(-2.14748e+09);
79
xValue->setMaximum(2.14748e+09);
80
xLabel = new QLabel(this);
81
box->addWidget(xLabel, 0, 0, 1, 1);
82
box->addWidget(xValue, 0, 1, 1, 1);
84
yValue = new QDoubleSpinBox(this);
85
yValue->setMinimum(-2.14748e+09);
86
yValue->setMaximum(2.14748e+09);
87
yLabel = new QLabel(this);
88
box->addWidget(yLabel, 1, 0, 1, 1);
89
box->addWidget(yValue, 1, 1, 1, 1);
91
zValue = new QDoubleSpinBox(this);
92
zValue->setMinimum(-2.14748e+09);
93
zValue->setMaximum(2.14748e+09);
94
zLabel = new QLabel(this);
95
box->addWidget(zLabel, 2, 0, 1, 1);
96
box->addWidget(zValue, 2, 1, 1, 1);
98
dLabel = new QLabel(this);
99
dValue = new QComboBox(this);
100
dValue->setCurrentIndex(-1);
101
box->addWidget(dLabel, 3, 0, 1, 1);
102
box->addWidget(dValue, 3, 1, 1, 1);
104
QGridLayout* gridLayout = new QGridLayout(this);
105
gridLayout->addLayout(box, 0, 0, 1, 2);
110
LocationWidget::~LocationWidget()
113
QSize LocationWidget::sizeHint() const
115
return QSize(150, 100);
118
void LocationWidget::changeEvent(QEvent* e)
120
if (e->type() == QEvent::LanguageChange) {
121
this->retranslateUi();
123
QWidget::changeEvent(e);
126
void LocationWidget::retranslateUi()
128
xLabel->setText(QApplication::translate("Gui::LocationWidget", "X:"));
129
yLabel->setText(QApplication::translate("Gui::LocationWidget", "Y:"));
130
zLabel->setText(QApplication::translate("Gui::LocationWidget", "Z:"));
131
dLabel->setText(QApplication::translate("Gui::LocationWidget", "Direction:"));
134
FileChooser::FileChooser(QWidget* parent)
139
QHBoxLayout* layout = new QHBoxLayout(this);
140
layout->setContentsMargins(0, 0, 0, 0);
141
layout->setSpacing(6);
143
lineEdit = new QLineEdit(this);
144
layout->addWidget(lineEdit);
146
connect(lineEdit, &QLineEdit::textChanged, this, &FileChooser::fileNameChanged);
148
button = new QPushButton("...", this);
149
#if QT_VERSION >= QT_VERSION_CHECK(5, 11, 0)
150
button->setFixedWidth(2 * button->fontMetrics().horizontalAdvance(" ... "));
152
button->setFixedWidth(2 * button->fontMetrics().width(" ... "));
154
layout->addWidget(button);
156
connect(button, &QPushButton::clicked, this, &FileChooser::chooseFile);
158
setFocusProxy(lineEdit);
161
FileChooser::~FileChooser()
164
QString FileChooser::fileName() const
166
return lineEdit->text();
169
void FileChooser::setFileName(const QString& fn)
171
lineEdit->setText(fn);
174
void FileChooser::chooseFile()
176
QFileDialog::Options dlgOpt = QFileDialog::DontUseNativeDialog;
178
if (mode() == File) {
179
fn = QFileDialog::getOpenFileName(this,
187
QFileDialog::Options option = QFileDialog::ShowDirsOnly | dlgOpt;
188
fn = QFileDialog::getExistingDirectory(this,
189
tr("Select a directory"),
195
lineEdit->setText(fn);
196
Q_EMIT fileNameSelected(fn);
200
FileChooser::Mode FileChooser::mode() const
205
void FileChooser::setMode(Mode m)
210
QString FileChooser::filter() const
215
void FileChooser::setFilter(const QString& filter)
220
void FileChooser::setButtonText(const QString& txt)
222
button->setText(txt);
223
#if QT_VERSION >= QT_VERSION_CHECK(5, 11, 0)
224
int w1 = 2 * button->fontMetrics().horizontalAdvance(txt);
225
int w2 = 2 * button->fontMetrics().horizontalAdvance(" ... ");
227
int w1 = 2 * button->fontMetrics().width(txt);
228
int w2 = 2 * button->fontMetrics().width(" ... ");
230
button->setFixedWidth((w1 > w2 ? w1 : w2));
233
QString FileChooser::buttonText() const
235
return button->text();
238
// ------------------------------------------------------------------------------
240
PrefFileChooser::PrefFileChooser(QWidget* parent)
241
: FileChooser(parent)
244
PrefFileChooser::~PrefFileChooser()
247
QByteArray PrefFileChooser::entryName() const
252
QByteArray PrefFileChooser::paramGrpPath() const
257
void PrefFileChooser::setEntryName(const QByteArray& name)
262
void PrefFileChooser::setParamGrpPath(const QByteArray& name)
267
// --------------------------------------------------------------------
269
AccelLineEdit::AccelLineEdit(QWidget* parent)
272
setPlaceholderText(tr("Press a keyboard shortcut"));
273
setClearButtonEnabled(true);
277
bool AccelLineEdit::isNone() const
279
return text().isEmpty();
282
void AccelLineEdit::keyPressEvent(QKeyEvent* e)
285
QLineEdit::keyPressEvent(e);
289
QString txtLine = text();
292
Qt::KeyboardModifiers state = e->modifiers();
294
// Backspace clears the shortcut if text is present, else sets Backspace as shortcut.
295
// If a modifier is pressed without any other key, return.
296
// AltGr is not a modifier but doesn't have a QString representation.
298
case Qt::Key_Backspace:
300
if (state == Qt::NoModifier) {
303
QKeySequence ks(key);
304
setText(ks.toString(QKeySequence::NativeText));
310
case Qt::Key_Control:
320
if (txtLine.isEmpty()) {
321
// Text maybe cleared by QLineEdit's built in clear button
325
// 4 keys are allowed for QShortcut
326
switch (keyPressedCount) {
335
txtLine += QString::fromLatin1(",");
340
// Handles modifiers applying a mask.
341
if ((state & Qt::ControlModifier) == Qt::ControlModifier) {
342
QKeySequence ks(Qt::CTRL);
343
txtLine += ks.toString(QKeySequence::NativeText);
345
if ((state & Qt::AltModifier) == Qt::AltModifier) {
346
QKeySequence ks(Qt::ALT);
347
txtLine += ks.toString(QKeySequence::NativeText);
349
if ((state & Qt::ShiftModifier) == Qt::ShiftModifier) {
350
QKeySequence ks(Qt::SHIFT);
351
txtLine += ks.toString(QKeySequence::NativeText);
353
if ((state & Qt::MetaModifier) == Qt::MetaModifier) {
354
QKeySequence ks(Qt::META);
355
txtLine += ks.toString(QKeySequence::NativeText);
358
// Handles normal keys
359
QKeySequence ks(key);
360
txtLine += ks.toString(QKeySequence::NativeText);
366
// ------------------------------------------------------------------------------
368
ActionSelector::ActionSelector(QWidget* parent)
371
addButton = new QPushButton(this);
372
addButton->setMinimumSize(QSize(30, 30));
374
icon.addFile(QString::fromUtf8(":/icons/button_right.xpm"), QSize(), QIcon::Normal, QIcon::Off);
375
addButton->setIcon(icon);
376
gridLayout = new QGridLayout(this);
377
gridLayout->addWidget(addButton, 1, 1, 1, 1);
379
spacerItem = new QSpacerItem(33, 57, QSizePolicy::Minimum, QSizePolicy::Expanding);
380
gridLayout->addItem(spacerItem, 5, 1, 1, 1);
381
spacerItem1 = new QSpacerItem(33, 58, QSizePolicy::Minimum, QSizePolicy::Expanding);
382
gridLayout->addItem(spacerItem1, 0, 1, 1, 1);
384
removeButton = new QPushButton(this);
385
removeButton->setMinimumSize(QSize(30, 30));
387
icon1.addFile(QString::fromUtf8(":/icons/button_left.xpm"), QSize(), QIcon::Normal, QIcon::Off);
388
removeButton->setIcon(icon1);
389
removeButton->setAutoDefault(true);
390
removeButton->setDefault(false);
392
gridLayout->addWidget(removeButton, 2, 1, 1, 1);
394
upButton = new QPushButton(this);
395
upButton->setMinimumSize(QSize(30, 30));
397
icon3.addFile(QString::fromUtf8(":/icons/button_up.xpm"), QSize(), QIcon::Normal, QIcon::Off);
398
upButton->setIcon(icon3);
400
gridLayout->addWidget(upButton, 3, 1, 1, 1);
402
downButton = new QPushButton(this);
403
downButton->setMinimumSize(QSize(30, 30));
405
icon2.addFile(QString::fromUtf8(":/icons/button_down.xpm"), QSize(), QIcon::Normal, QIcon::Off);
406
downButton->setIcon(icon2);
407
downButton->setAutoDefault(true);
409
gridLayout->addWidget(downButton, 4, 1, 1, 1);
411
vboxLayout = new QVBoxLayout();
412
vboxLayout->setContentsMargins(0, 0, 0, 0);
413
labelAvailable = new QLabel(this);
414
vboxLayout->addWidget(labelAvailable);
416
availableWidget = new QTreeWidget(this);
417
availableWidget->setRootIsDecorated(false);
418
availableWidget->setHeaderLabels(QStringList() << QString());
419
availableWidget->header()->hide();
420
vboxLayout->addWidget(availableWidget);
422
gridLayout->addLayout(vboxLayout, 0, 0, 6, 1);
424
vboxLayout1 = new QVBoxLayout();
425
vboxLayout1->setContentsMargins(0, 0, 0, 0);
426
labelSelected = new QLabel(this);
427
vboxLayout1->addWidget(labelSelected);
429
selectedWidget = new QTreeWidget(this);
430
selectedWidget->setRootIsDecorated(false);
431
selectedWidget->setHeaderLabels(QStringList() << QString());
432
selectedWidget->header()->hide();
433
vboxLayout1->addWidget(selectedWidget);
435
gridLayout->addLayout(vboxLayout1, 0, 2, 6, 1);
437
addButton->setText(QString());
438
removeButton->setText(QString());
439
upButton->setText(QString());
440
downButton->setText(QString());
442
labelAvailable->setText(QApplication::translate("Gui::ActionSelector", "Available:"));
443
labelSelected->setText(QApplication::translate("Gui::ActionSelector", "Selected:"));
444
addButton->setToolTip(QApplication::translate("Gui::ActionSelector", "Add"));
445
removeButton->setToolTip(QApplication::translate("Gui::ActionSelector", "Remove"));
446
upButton->setToolTip(QApplication::translate("Gui::ActionSelector", "Move up"));
447
downButton->setToolTip(QApplication::translate("Gui::ActionSelector", "Move down"));
450
ActionSelector::~ActionSelector()
453
// --------------------------------------------------------------------
455
InputField::InputField(QWidget* parent)
464
InputField::~InputField()
467
/** Sets the preference path to \a path. */
468
void InputField::setParamGrpPath(const QByteArray& path)
473
/** Returns the widget's preferences path. */
474
QByteArray InputField::paramGrpPath() const
479
/// sets the field with a quantity
480
void InputField::setValue(double quant)
483
setText(QString("%1 %2").arg(Value).arg(UnitStr));
486
/// sets the field with a quantity
487
double InputField::getQuantity() const
492
/// get the value of the singleStep property
493
double InputField::singleStep(void) const
498
/// set the value of the singleStep property
499
void InputField::setSingleStep(double s)
504
/// get the value of the maximum property
505
double InputField::maximum(void) const
510
/// set the value of the maximum property
511
void InputField::setMaximum(double m)
516
/// get the value of the minimum property
517
double InputField::minimum(void) const
522
/// set the value of the minimum property
523
void InputField::setMinimum(double m)
528
void InputField::setUnitText(QString str)
531
setText(QString("%1 %2").arg(Value).arg(UnitStr));
534
QString InputField::getUnitText(void)
539
// get the value of the minimum property
540
int InputField::historySize(void) const
545
// set the value of the minimum property
546
void InputField::setHistorySize(int i)
551
// --------------------------------------------------------------------
559
Unit::Unit(const QString& u)
563
bool Unit::isEmpty() const
565
return unit.isEmpty();
568
bool Unit::operator==(const Unit& that)
570
return this->unit == that.unit;
573
bool Unit::operator!=(const Unit& that)
575
return this->unit != that.unit;
578
const QString& Unit::getString() const
583
int QuantityFormat::defaultDenominator = 8; // for 1/8"
586
QuantityFormat::QuantityFormat()
587
: option(OmitGroupSeparator | RejectGroupSeparator)
590
, denominator(defaultDenominator)
598
Quantity::Quantity(double v, const Unit& u)
603
Quantity Quantity::parse(const QString& str)
608
while (!txt.isEmpty() && txt[txt.length() - 1].isLetter()) {
609
unit.prepend(txt[txt.length() - 1]);
613
double v = QLocale::system().toDouble(txt, &ok);
614
// if (!ok && !txt.isEmpty())
615
// throw Base::Exception();
616
return Quantity(v, Unit(unit));
619
void Quantity::setValue(double v)
624
double Quantity::getValue() const
629
void Quantity::setUnit(const Unit& u)
634
Unit Quantity::getUnit() const
639
QString Quantity::getUserString() const
642
const QuantityFormat& format = getFormat();
643
if (format.option != QuantityFormat::None) {
644
uint opt = static_cast<uint>(format.option);
645
Lc.setNumberOptions(static_cast<QLocale::NumberOptions>(opt));
648
QString Ln = Lc.toString(value, format.toFormat(), format.precision);
649
return QString::fromUtf8("%1 %2").arg(Ln, unit.getString());
652
QString Quantity::getUserString(double& factor, QString& unitString) const
655
unitString = unit.getString();
658
const QuantityFormat& format = getFormat();
659
if (format.option != QuantityFormat::None) {
660
uint opt = static_cast<uint>(format.option);
661
Lc.setNumberOptions(static_cast<QLocale::NumberOptions>(opt));
664
QString Ln = Lc.toString(value, format.toFormat(), format.precision);
665
return QString::fromUtf8("%1 %2").arg(Ln, unit.getString());
673
class QuantitySpinBoxPrivate
676
QuantitySpinBoxPrivate()
684
~QuantitySpinBoxPrivate()
687
QString stripped(const QString& t, int* pos) const
690
const int s = text.size();
691
text = text.trimmed();
693
(*pos) -= (s - text.size());
698
bool validate(QString& input, Base::Quantity& result) const
700
bool success = false;
703
QValidator::State state;
704
Base::Quantity res = validateAndInterpret(tmp, pos, state);
705
res.setFormat(quantity.getFormat());
706
if (state == QValidator::Acceptable) {
711
else if (state == QValidator::Intermediate) {
713
tmp += QLatin1Char(' ');
715
Base::Quantity res2 = validateAndInterpret(tmp, pos, state);
716
res2.setFormat(quantity.getFormat());
717
if (state == QValidator::Acceptable) {
726
Base::Quantity validateAndInterpret(QString& input, int& pos, QValidator::State& state) const
729
const double max = this->maximum;
730
const double min = this->minimum;
732
QString copy = input;
734
int len = copy.size();
736
const bool plus = max >= 0;
737
const bool minus = min <= 0;
741
state = max != min ? QValidator::Intermediate : QValidator::Invalid;
744
if (copy.at(0) == locale.decimalPoint()) {
745
state = QValidator::Intermediate;
746
copy.prepend(QLatin1Char('0'));
751
else if (copy.at(0) == QLatin1Char('+')) {
752
// the quantity parser doesn't allow numbers of the form '+1.0'
753
state = QValidator::Invalid;
756
else if (copy.at(0) == QLatin1Char('-')) {
758
state = QValidator::Intermediate;
761
state = QValidator::Invalid;
767
if (copy.at(1) == locale.decimalPoint()
768
&& (plus && copy.at(0) == QLatin1Char('+'))) {
769
state = QValidator::Intermediate;
772
if (copy.at(1) == locale.decimalPoint()
773
&& (minus && copy.at(0) == QLatin1Char('-'))) {
774
state = QValidator::Intermediate;
775
copy.insert(1, QLatin1Char('0'));
786
if (copy.at(0) == locale.groupSeparator()) {
787
state = QValidator::Invalid;
791
bool decOccurred = false;
792
for (int i = 0; i < copy.size(); i++) {
793
if (copy.at(i) == locale.decimalPoint()) {
794
// Disallow multiple decimal points within the same numeric substring
796
state = QValidator::Invalid;
801
// Reset decOcurred if non-numeric character found
802
else if (!(copy.at(i) == locale.groupSeparator() || copy.at(i).isDigit())) {
811
QChar plus = QLatin1Char('+'), minus = QLatin1Char('-');
813
if (locale.negativeSign() != minus) {
814
copy.replace(locale.negativeSign(), minus);
816
if (locale.positiveSign() != plus) {
817
copy.replace(locale.positiveSign(), plus);
821
QString copy2 = copy;
822
copy2.remove(locale.groupSeparator());
824
res = Base::Quantity::parse(copy2);
825
value = res.getValue();
828
catch (Base::Exception&) {
832
// input may not be finished
833
state = QValidator::Intermediate;
835
else if (value >= min && value <= max) {
836
if (copy.endsWith(locale.decimalPoint())) {
837
// input shouldn't end with a decimal point
838
state = QValidator::Intermediate;
840
else if (res.getUnit().isEmpty() && !this->unit.isEmpty()) {
841
// if not dimensionless the input should have a dimension
842
state = QValidator::Intermediate;
844
else if (res.getUnit() != this->unit) {
845
state = QValidator::Invalid;
848
state = QValidator::Acceptable;
851
else if (max == min) { // when max and min is the same the only non-Invalid input is
853
state = QValidator::Invalid;
856
if ((value >= 0 && value > max) || (value < 0 && value < min)) {
857
state = QValidator::Invalid;
860
state = QValidator::Intermediate;
865
if (state != QValidator::Acceptable) {
866
res.setValue(max > 0 ? min : max);
877
Base::Quantity quantity;
878
Base::Quantity cached;
888
QuantitySpinBox::QuantitySpinBox(QWidget* parent)
889
: QAbstractSpinBox(parent)
890
, d_ptr(new QuantitySpinBoxPrivate())
892
d_ptr->locale = locale();
893
this->setContextMenuPolicy(Qt::DefaultContextMenu);
894
connect(lineEdit(), &QLineEdit::textChanged, this, &QuantitySpinBox::userInput);
895
connect(this, &QuantitySpinBox::editingFinished, this, &QuantitySpinBox::handlePendingEmit);
898
QuantitySpinBox::~QuantitySpinBox()
901
void QuantitySpinBox::resizeEvent(QResizeEvent* event)
903
QAbstractSpinBox::resizeEvent(event);
906
void Gui::QuantitySpinBox::keyPressEvent(QKeyEvent* event)
908
QAbstractSpinBox::keyPressEvent(event);
912
void QuantitySpinBox::updateText(const Base::Quantity& quant)
914
Q_D(QuantitySpinBox);
917
QString txt = getUserString(quant, dFactor, d->unitStr);
918
d->unitValue = quant.getValue() / dFactor;
919
lineEdit()->setText(txt);
923
Base::Quantity QuantitySpinBox::value() const
925
Q_D(const QuantitySpinBox);
929
double QuantitySpinBox::rawValue() const
931
Q_D(const QuantitySpinBox);
932
return d->quantity.getValue();
935
void QuantitySpinBox::setValue(const Base::Quantity& value)
937
Q_D(QuantitySpinBox);
940
if (d->quantity.getValue() > d->maximum) {
941
d->quantity.setValue(d->maximum);
943
if (d->quantity.getValue() < d->minimum) {
944
d->quantity.setValue(d->minimum);
947
d->unit = value.getUnit();
952
void QuantitySpinBox::setValue(double value)
954
Q_D(QuantitySpinBox);
955
setValue(Base::Quantity(value, d->unit));
958
bool QuantitySpinBox::hasValidInput() const
960
Q_D(const QuantitySpinBox);
961
return d->validInput;
964
// Gets called after call of 'validateAndInterpret'
965
void QuantitySpinBox::userInput(const QString& text)
967
Q_D(QuantitySpinBox);
969
d->pendingEmit = true;
973
if (d->validate(tmp, res)) {
975
d->validInput = true;
978
d->validInput = false;
982
if (keyboardTracking()) {
991
void QuantitySpinBox::handlePendingEmit()
993
updateFromCache(true);
996
void QuantitySpinBox::updateFromCache(bool notify)
998
Q_D(QuantitySpinBox);
999
if (d->pendingEmit) {
1001
const Base::Quantity& res = d->cached;
1002
QString text = getUserString(res, factor, d->unitStr);
1003
d->unitValue = res.getValue() / factor;
1008
d->pendingEmit = false;
1010
valueChanged(res.getValue());
1016
Base::Unit QuantitySpinBox::unit() const
1018
Q_D(const QuantitySpinBox);
1022
void QuantitySpinBox::setUnit(const Base::Unit& unit)
1024
Q_D(QuantitySpinBox);
1027
d->quantity.setUnit(unit);
1028
updateText(d->quantity);
1031
void QuantitySpinBox::setUnitText(const QString& str)
1034
Base::Quantity quant = Base::Quantity::parse(str);
1035
setUnit(quant.getUnit());
1037
catch (const Base::Exception&) {
1041
QString QuantitySpinBox::unitText(void)
1043
Q_D(QuantitySpinBox);
1047
double QuantitySpinBox::singleStep() const
1049
Q_D(const QuantitySpinBox);
1050
return d->singleStep;
1053
void QuantitySpinBox::setSingleStep(double value)
1055
Q_D(QuantitySpinBox);
1058
d->singleStep = value;
1062
double QuantitySpinBox::minimum() const
1064
Q_D(const QuantitySpinBox);
1068
void QuantitySpinBox::setMinimum(double minimum)
1070
Q_D(QuantitySpinBox);
1071
d->minimum = minimum;
1074
double QuantitySpinBox::maximum() const
1076
Q_D(const QuantitySpinBox);
1080
void QuantitySpinBox::setMaximum(double maximum)
1082
Q_D(QuantitySpinBox);
1083
d->maximum = maximum;
1086
void QuantitySpinBox::setRange(double minimum, double maximum)
1088
Q_D(QuantitySpinBox);
1089
d->minimum = minimum;
1090
d->maximum = maximum;
1093
int QuantitySpinBox::decimals() const
1095
Q_D(const QuantitySpinBox);
1096
return d->quantity.getFormat().precision;
1099
void QuantitySpinBox::setDecimals(int v)
1101
Q_D(QuantitySpinBox);
1102
Base::QuantityFormat f = d->quantity.getFormat();
1104
d->quantity.setFormat(f);
1105
updateText(d->quantity);
1108
void QuantitySpinBox::clearSchema()
1110
Q_D(QuantitySpinBox);
1111
updateText(d->quantity);
1115
QuantitySpinBox::getUserString(const Base::Quantity& val, double& factor, QString& unitString) const
1117
return val.getUserString(factor, unitString);
1120
QString QuantitySpinBox::getUserString(const Base::Quantity& val) const
1122
return val.getUserString();
1125
QAbstractSpinBox::StepEnabled QuantitySpinBox::stepEnabled() const
1127
Q_D(const QuantitySpinBox);
1128
if (isReadOnly() /* || !d->validInput*/) {
1132
return StepEnabled(StepUpEnabled | StepDownEnabled);
1134
StepEnabled ret = StepNone;
1135
if (d->quantity.getValue() < d->maximum) {
1136
ret |= StepUpEnabled;
1138
if (d->quantity.getValue() > d->minimum) {
1139
ret |= StepDownEnabled;
1144
void QuantitySpinBox::stepBy(int steps)
1146
Q_D(QuantitySpinBox);
1147
updateFromCache(false);
1149
double step = d->singleStep * steps;
1150
double val = d->unitValue + step;
1151
if (val > d->maximum) {
1154
else if (val < d->minimum) {
1158
lineEdit()->setText(QString::fromUtf8("%L1 %2").arg(val).arg(d->unitStr));
1159
updateFromCache(true);
1164
QSize QuantitySpinBox::sizeHint() const
1168
const QFontMetrics fm(fontMetrics());
1169
int frameWidth = lineEdit()->style()->pixelMetric(QStyle::PM_SpinBoxFrameWidth);
1170
int iconHeight = fm.height() - frameWidth;
1171
int h = lineEdit()->sizeHint().height();
1174
QString s = QLatin1String("000000000000000000");
1175
QString fixedContent = QLatin1String(" ");
1178
#if QT_VERSION >= QT_VERSION_CHECK(5, 11, 0)
1179
w = fm.horizontalAdvance(s);
1184
w += 2; // cursor blinking space
1187
QStyleOptionSpinBox opt;
1188
initStyleOption(&opt);
1190
QSize size = style()->sizeFromContents(QStyle::CT_SpinBox, &opt, hint, this);
1194
QSize QuantitySpinBox::minimumSizeHint() const
1198
const QFontMetrics fm(fontMetrics());
1199
int frameWidth = lineEdit()->style()->pixelMetric(QStyle::PM_SpinBoxFrameWidth);
1200
int iconHeight = fm.height() - frameWidth;
1201
int h = lineEdit()->minimumSizeHint().height();
1204
QString s = QLatin1String("000000000000000000");
1205
QString fixedContent = QLatin1String(" ");
1208
#if QT_VERSION >= QT_VERSION_CHECK(5, 11, 0)
1209
w = fm.horizontalAdvance(s);
1214
w += 2; // cursor blinking space
1217
QStyleOptionSpinBox opt;
1218
initStyleOption(&opt);
1220
QSize size = style()->sizeFromContents(QStyle::CT_SpinBox, &opt, hint, this);
1224
void QuantitySpinBox::showEvent(QShowEvent* event)
1226
Q_D(QuantitySpinBox);
1228
QAbstractSpinBox::showEvent(event);
1230
bool selected = lineEdit()->hasSelectedText();
1231
updateText(d->quantity);
1237
void QuantitySpinBox::hideEvent(QHideEvent* event)
1239
handlePendingEmit();
1240
QAbstractSpinBox::hideEvent(event);
1243
void QuantitySpinBox::closeEvent(QCloseEvent* event)
1245
handlePendingEmit();
1246
QAbstractSpinBox::closeEvent(event);
1249
bool QuantitySpinBox::event(QEvent* event)
1251
// issue #0004059: Tooltips for Gui::QuantitySpinBox not showing
1252
// Here we must not try to show the tooltip of the icon label
1253
// because it would override a custom tooltip set to this widget.
1255
// We could also check if the text of this tooltip is empty but
1256
// it will fail in cases where the widget is embedded into the
1257
// property editor and the corresponding item has set a tooltip.
1258
// Instead of showing the item's tooltip it will again show the
1259
// tooltip of the icon label.
1261
if (event->type() == QEvent::ToolTip) {
1262
if (isBound() && getExpression() && lineEdit()->isReadOnly()) {
1263
QHelpEvent * helpEvent = static_cast<QHelpEvent*>(event);
1265
QToolTip::showText( helpEvent->globalPos(), Base::Tools::fromStdString(getExpression()->toString()), this);
1272
return QAbstractSpinBox::event(event);
1275
void QuantitySpinBox::focusInEvent(QFocusEvent* event)
1277
bool hasSel = lineEdit()->hasSelectedText();
1278
QAbstractSpinBox::focusInEvent(event);
1280
if (event->reason() == Qt::TabFocusReason || event->reason() == Qt::BacktabFocusReason
1281
|| event->reason() == Qt::ShortcutFocusReason) {
1289
void QuantitySpinBox::focusOutEvent(QFocusEvent* event)
1291
Q_D(QuantitySpinBox);
1294
QString text = lineEdit()->text();
1295
QValidator::State state;
1296
d->validateAndInterpret(text, pos, state);
1297
if (state != QValidator::Acceptable) {
1298
lineEdit()->setText(d->validStr);
1301
handlePendingEmit();
1303
QToolTip::hideText();
1304
QAbstractSpinBox::focusOutEvent(event);
1307
void QuantitySpinBox::clear()
1309
QAbstractSpinBox::clear();
1312
void QuantitySpinBox::selectNumber()
1314
QString expr = QString::fromLatin1("^([%1%2]?[0-9\\%3]*)\\%4?([0-9]+(%5[%1%2]?[0-9]+)?)")
1315
.arg(locale().negativeSign())
1316
.arg(locale().positiveSign())
1317
.arg(locale().groupSeparator())
1318
.arg(locale().decimalPoint())
1319
.arg(locale().exponential());
1320
auto rmatch = QRegularExpression(expr).match(lineEdit()->text());
1321
if (rmatch.hasMatch()) {
1322
lineEdit()->setSelection(0, rmatch.capturedLength());
1326
QString QuantitySpinBox::textFromValue(const Base::Quantity& value) const
1330
QString str = getUserString(value, factor, unitStr);
1331
if (qAbs(value.getValue()) >= 1000.0) {
1332
str.remove(locale().groupSeparator());
1337
Base::Quantity QuantitySpinBox::valueFromText(const QString& text) const
1339
Q_D(const QuantitySpinBox);
1341
QString copy = text;
1342
int pos = lineEdit()->cursorPosition();
1343
QValidator::State state = QValidator::Acceptable;
1344
Base::Quantity quant = d->validateAndInterpret(copy, pos, state);
1345
if (state != QValidator::Acceptable) {
1347
quant = d->validateAndInterpret(copy, pos, state);
1353
QValidator::State QuantitySpinBox::validate(QString& text, int& pos) const
1355
Q_D(const QuantitySpinBox);
1357
QValidator::State state;
1358
d->validateAndInterpret(text, pos, state);
1362
void QuantitySpinBox::fixup(QString& input) const
1364
input.remove(locale().groupSeparator());
1367
// ------------------------------------------------------------------------------
1369
PrefUnitSpinBox::PrefUnitSpinBox(QWidget* parent)
1370
: QuantitySpinBox(parent)
1373
PrefUnitSpinBox::~PrefUnitSpinBox()
1376
QByteArray PrefUnitSpinBox::entryName() const
1381
QByteArray PrefUnitSpinBox::paramGrpPath() const
1386
void PrefUnitSpinBox::setEntryName(const QByteArray& name)
1391
void PrefUnitSpinBox::setParamGrpPath(const QByteArray& name)
1396
// --------------------------------------------------------------------
1398
PrefQuantitySpinBox::PrefQuantitySpinBox(QWidget* parent)
1399
: QuantitySpinBox(parent)
1402
PrefQuantitySpinBox::~PrefQuantitySpinBox()
1405
QByteArray PrefQuantitySpinBox::entryName() const
1410
QByteArray PrefQuantitySpinBox::paramGrpPath() const
1415
void PrefQuantitySpinBox::setEntryName(const QByteArray& name)
1420
void PrefQuantitySpinBox::setParamGrpPath(const QByteArray& name)
1425
// --------------------------------------------------------------------
1427
CommandIconView::CommandIconView(QWidget* parent)
1428
: QListWidget(parent)
1430
connect(this, &QListWidget::currentItemChanged, this, &CommandIconView::onSelectionChanged);
1433
CommandIconView::~CommandIconView()
1436
void CommandIconView::startDrag(Qt::DropActions /*supportedActions*/)
1438
QList<QListWidgetItem*> items = selectedItems();
1439
QByteArray itemData;
1440
QDataStream dataStream(&itemData, QIODevice::WriteOnly);
1443
dataStream << items.count();
1444
for (QList<QListWidgetItem*>::ConstIterator it = items.begin(); it != items.end(); ++it) {
1445
if (it == items.begin()) {
1446
pixmap = ((*it)->data(Qt::UserRole)).value<QPixmap>();
1448
dataStream << (*it)->text();
1451
QMimeData* mimeData = new QMimeData;
1452
mimeData->setData("text/x-action-items", itemData);
1454
QDrag* drag = new QDrag(this);
1455
drag->setMimeData(mimeData);
1456
drag->setHotSpot(QPoint(pixmap.width() / 2, pixmap.height() / 2));
1457
drag->setPixmap(pixmap);
1458
drag->exec(Qt::MoveAction);
1461
void CommandIconView::onSelectionChanged(QListWidgetItem* item, QListWidgetItem*)
1464
emitSelectionChanged(item->toolTip());
1468
// ------------------------------------------------------------------------------
1473
class UnsignedValidator: public QValidator
1476
UnsignedValidator(QObject* parent);
1477
UnsignedValidator(uint minimum, uint maximum, QObject* parent);
1478
~UnsignedValidator();
1480
QValidator::State validate(QString&, int&) const;
1482
void setBottom(uint);
1484
virtual void setRange(uint bottom, uint top);
1499
UnsignedValidator::UnsignedValidator(QObject* parent)
1500
: QValidator(parent)
1506
UnsignedValidator::UnsignedValidator(uint minimum, uint maximum, QObject* parent)
1507
: QValidator(parent)
1513
UnsignedValidator::~UnsignedValidator()
1516
QValidator::State UnsignedValidator::validate(QString& input, int&) const
1518
QString stripped; // = input.stripWhiteSpace();
1519
if (stripped.isEmpty()) {
1520
return Intermediate;
1523
uint entered = input.toUInt(&ok);
1527
else if (entered < b) {
1528
return Intermediate;
1530
else if (entered > t) {
1533
// else if ( entered < b || entered > t )
1540
void UnsignedValidator::setRange(uint minimum, uint maximum)
1546
void UnsignedValidator::setBottom(uint bottom)
1548
setRange(bottom, top());
1551
void UnsignedValidator::setTop(uint top)
1553
setRange(bottom(), top);
1556
class UIntSpinBoxPrivate
1559
UnsignedValidator* mValidator;
1561
UIntSpinBoxPrivate()
1564
uint mapToUInt(int v) const
1570
else if (v == INT_MAX) {
1583
int mapToInt(uint v) const
1586
if (v == UINT_MAX) {
1592
else if (v > INT_MAX) {
1606
// -------------------------------------------------------------
1608
UIntSpinBox::UIntSpinBox(QWidget* parent)
1611
d = new UIntSpinBoxPrivate;
1612
d->mValidator = new UnsignedValidator(this->minimum(), this->maximum(), this);
1613
connect(this, qOverload<int>(&QSpinBox::valueChanged), this, &UIntSpinBox::valueChange);
1619
UIntSpinBox::~UIntSpinBox()
1621
delete d->mValidator;
1626
void UIntSpinBox::setRange(uint minVal, uint maxVal)
1628
int iminVal = d->mapToInt(minVal);
1629
int imaxVal = d->mapToInt(maxVal);
1630
QSpinBox::setRange(iminVal, imaxVal);
1634
QValidator::State UIntSpinBox::validate(QString& input, int& pos) const
1636
return d->mValidator->validate(input, pos);
1639
uint UIntSpinBox::value() const
1641
return d->mapToUInt(QSpinBox::value());
1644
void UIntSpinBox::setValue(uint value)
1646
QSpinBox::setValue(d->mapToInt(value));
1649
void UIntSpinBox::valueChange(int value)
1651
unsignedChanged(d->mapToUInt(value));
1654
uint UIntSpinBox::minimum() const
1656
return d->mapToUInt(QSpinBox::minimum());
1659
void UIntSpinBox::setMinimum(uint minVal)
1661
uint maxVal = maximum();
1662
if (maxVal < minVal) {
1665
setRange(minVal, maxVal);
1668
uint UIntSpinBox::maximum() const
1670
return d->mapToUInt(QSpinBox::maximum());
1673
void UIntSpinBox::setMaximum(uint maxVal)
1675
uint minVal = minimum();
1676
if (minVal > maxVal) {
1679
setRange(minVal, maxVal);
1682
QString UIntSpinBox::textFromValue(int v) const
1684
uint val = d->mapToUInt(v);
1690
int UIntSpinBox::valueFromText(const QString& text) const
1694
uint newVal = s.toUInt(&ok);
1695
if (!ok && !(prefix().isEmpty() && suffix().isEmpty())) {
1697
newVal = s.toUInt(&ok);
1700
return d->mapToInt(newVal);
1703
void UIntSpinBox::updateValidator()
1705
d->mValidator->setRange(this->minimum(), this->maximum());
1708
// --------------------------------------------------------------------
1710
IntSpinBox::IntSpinBox(QWidget* parent)
1714
IntSpinBox::~IntSpinBox()
1717
// --------------------------------------------------------------------
1719
PrefSpinBox::PrefSpinBox(QWidget* parent)
1723
PrefSpinBox::~PrefSpinBox()
1726
QByteArray PrefSpinBox::entryName() const
1731
QByteArray PrefSpinBox::paramGrpPath() const
1736
void PrefSpinBox::setEntryName(const QByteArray& name)
1741
void PrefSpinBox::setParamGrpPath(const QByteArray& name)
1746
// --------------------------------------------------------------------
1748
DoubleSpinBox::DoubleSpinBox(QWidget* parent)
1749
: QDoubleSpinBox(parent)
1752
DoubleSpinBox::~DoubleSpinBox()
1755
// --------------------------------------------------------------------
1757
PrefDoubleSpinBox::PrefDoubleSpinBox(QWidget* parent)
1758
: QDoubleSpinBox(parent)
1761
PrefDoubleSpinBox::~PrefDoubleSpinBox()
1764
QByteArray PrefDoubleSpinBox::entryName() const
1769
QByteArray PrefDoubleSpinBox::paramGrpPath() const
1774
void PrefDoubleSpinBox::setEntryName(const QByteArray& name)
1779
void PrefDoubleSpinBox::setParamGrpPath(const QByteArray& name)
1784
// -------------------------------------------------------------
1786
ColorButton::ColorButton(QWidget* parent)
1787
: QPushButton(parent)
1788
, _allowChange(true)
1789
, _allowTransparency(false)
1792
_col = palette().color(QPalette::Active, QPalette::Midlight);
1793
connect(this, &ColorButton::clicked, this, &ColorButton::onChooseColor);
1796
ColorButton::~ColorButton()
1799
void ColorButton::setColor(const QColor& c)
1805
QColor ColorButton::color() const
1810
void ColorButton::setAllowChangeColor(bool ok)
1815
bool ColorButton::allowChangeColor() const
1817
return _allowChange;
1820
void ColorButton::setAllowTransparency(bool ok)
1822
_allowTransparency = ok;
1825
bool ColorButton::allowTransparency() const
1827
return _allowTransparency;
1830
void ColorButton::setDrawFrame(bool ok)
1835
bool ColorButton::drawFrame() const
1840
void ColorButton::paintEvent(QPaintEvent* e)
1842
// first paint the complete button
1843
QPushButton::paintEvent(e);
1845
// repaint the rectangle area
1846
QPalette::ColorGroup group =
1847
isEnabled() ? hasFocus() ? QPalette::Active : QPalette::Inactive : QPalette::Disabled;
1848
QColor pen = palette().color(group, QPalette::ButtonText);
1850
QPainter paint(this);
1854
paint.setBrush(QBrush(_col));
1855
paint.drawRect(5, 5, width() - 10, height() - 10);
1858
paint.fillRect(5, 5, width() - 10, height() - 10, QBrush(_col));
1862
// overpaint the rectangle to paint icon and text
1863
QStyleOptionButton opt;
1867
opt.iconSize = iconSize();
1869
QStylePainter p(this);
1870
p.drawControl(QStyle::CE_PushButtonLabel, opt);
1873
void ColorButton::onChooseColor()
1875
if (!_allowChange) {
1878
QColor c = QColorDialog::getColor(_col, this);
1885
// ------------------------------------------------------------------------------
1887
PrefColorButton::PrefColorButton(QWidget* parent)
1888
: ColorButton(parent)
1891
PrefColorButton::~PrefColorButton()
1894
QByteArray PrefColorButton::entryName() const
1899
QByteArray PrefColorButton::paramGrpPath() const
1904
void PrefColorButton::setEntryName(const QByteArray& name)
1909
void PrefColorButton::setParamGrpPath(const QByteArray& name)
1914
// --------------------------------------------------------------------
1916
PrefLineEdit::PrefLineEdit(QWidget* parent)
1920
PrefLineEdit::~PrefLineEdit()
1923
QByteArray PrefLineEdit::entryName() const
1928
QByteArray PrefLineEdit::paramGrpPath() const
1933
void PrefLineEdit::setEntryName(const QByteArray& name)
1938
void PrefLineEdit::setParamGrpPath(const QByteArray& name)
1943
// --------------------------------------------------------------------
1945
PrefComboBox::PrefComboBox(QWidget* parent)
1951
PrefComboBox::~PrefComboBox()
1954
QByteArray PrefComboBox::entryName() const
1959
QByteArray PrefComboBox::paramGrpPath() const
1964
void PrefComboBox::setEntryName(const QByteArray& name)
1969
void PrefComboBox::setParamGrpPath(const QByteArray& name)
1974
// --------------------------------------------------------------------
1976
PrefCheckBox::PrefCheckBox(QWidget* parent)
1979
setText("CheckBox");
1982
PrefCheckBox::~PrefCheckBox()
1985
QByteArray PrefCheckBox::entryName() const
1990
QByteArray PrefCheckBox::paramGrpPath() const
1995
void PrefCheckBox::setEntryName(const QByteArray& name)
2000
void PrefCheckBox::setParamGrpPath(const QByteArray& name)
2005
// --------------------------------------------------------------------
2007
PrefRadioButton::PrefRadioButton(QWidget* parent)
2008
: QRadioButton(parent)
2010
setText("RadioButton");
2013
PrefRadioButton::~PrefRadioButton()
2016
QByteArray PrefRadioButton::entryName() const
2021
QByteArray PrefRadioButton::paramGrpPath() const
2026
void PrefRadioButton::setEntryName(const QByteArray& name)
2031
void PrefRadioButton::setParamGrpPath(const QByteArray& name)
2036
// --------------------------------------------------------------------
2038
PrefSlider::PrefSlider(QWidget* parent)
2042
PrefSlider::~PrefSlider()
2045
QByteArray PrefSlider::entryName() const
2050
QByteArray PrefSlider::paramGrpPath() const
2055
void PrefSlider::setEntryName(const QByteArray& name)
2060
void PrefSlider::setParamGrpPath(const QByteArray& name)
2065
// --------------------------------------------------------------------
2067
PrefFontBox::PrefFontBox(QWidget* parent)
2068
: QFontComboBox(parent)
2071
PrefFontBox::~PrefFontBox()
2074
QByteArray PrefFontBox::entryName() const
2079
QByteArray PrefFontBox::paramGrpPath() const
2084
void PrefFontBox::setEntryName(const QByteArray& name)
2089
void PrefFontBox::setParamGrpPath(const QByteArray& name)