FreeCAD

Форк
0
/
customwidgets.cpp 
2092 строки · 51.0 Кб
1
/***************************************************************************
2
 *   Copyright (c) 2006 Werner Mayer <werner.wm.mayer@gmx.de>              *
3
 *                                                                         *
4
 *   This file is part of the FreeCAD CAx development system.              *
5
 *                                                                         *
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.      *
10
 *                                                                         *
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.                  *
15
 *                                                                         *
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                                *
20
 *                                                                         *
21
 ***************************************************************************/
22

23

24
#include <QApplication>
25
#include <QColorDialog>
26
#include <QCursor>
27
#include <QFileDialog>
28
#include <QHeaderView>
29
#include <QMessageBox>
30
#include <QRegularExpression>
31
#include <QRegularExpressionMatch>
32
#include <QStyleOptionButton>
33
#include <QStylePainter>
34
#include <QToolTip>
35
#include <QtGui>
36
#include <cfloat>
37

38
#include "customwidgets.h"
39

40
using namespace Gui;
41

42

43
UrlLabel::UrlLabel(QWidget* parent, Qt::WindowFlags f)
44
    : QLabel("TextLabel", parent, f)
45
{
46
    _url = "http://localhost";
47
    setToolTip(this->_url);
48
    setCursor(Qt::PointingHandCursor);
49
}
50

51
UrlLabel::~UrlLabel()
52
{}
53

54
void UrlLabel::mouseReleaseEvent(QMouseEvent*)
55
{
56
    QMessageBox::information(this,
57
                             "Browser",
58
                             QString("This starts your browser with url %1").arg(_url));
59
}
60

61
QString UrlLabel::url() const
62
{
63
    return this->_url;
64
}
65

66
void UrlLabel::setUrl(const QString& u)
67
{
68
    this->_url = u;
69
    setToolTip(this->_url);
70
}
71

72
LocationWidget::LocationWidget(QWidget* parent)
73
    : QWidget(parent)
74
{
75
    box = new QGridLayout();
76

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);
83

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);
90

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);
97

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);
103

104
    QGridLayout* gridLayout = new QGridLayout(this);
105
    gridLayout->addLayout(box, 0, 0, 1, 2);
106

107
    retranslateUi();
108
}
109

110
LocationWidget::~LocationWidget()
111
{}
112

113
QSize LocationWidget::sizeHint() const
114
{
115
    return QSize(150, 100);
116
}
117

118
void LocationWidget::changeEvent(QEvent* e)
119
{
120
    if (e->type() == QEvent::LanguageChange) {
121
        this->retranslateUi();
122
    }
123
    QWidget::changeEvent(e);
124
}
125

126
void LocationWidget::retranslateUi()
127
{
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:"));
132
}
133

134
FileChooser::FileChooser(QWidget* parent)
135
    : QWidget(parent)
136
    , md(File)
137
    , _filter(QString())
138
{
139
    QHBoxLayout* layout = new QHBoxLayout(this);
140
    layout->setContentsMargins(0, 0, 0, 0);
141
    layout->setSpacing(6);
142

143
    lineEdit = new QLineEdit(this);
144
    layout->addWidget(lineEdit);
145

146
    connect(lineEdit, &QLineEdit::textChanged, this, &FileChooser::fileNameChanged);
147

148
    button = new QPushButton("...", this);
149
#if QT_VERSION >= QT_VERSION_CHECK(5, 11, 0)
150
    button->setFixedWidth(2 * button->fontMetrics().horizontalAdvance(" ... "));
151
#else
152
    button->setFixedWidth(2 * button->fontMetrics().width(" ... "));
153
#endif
154
    layout->addWidget(button);
155

156
    connect(button, &QPushButton::clicked, this, &FileChooser::chooseFile);
157

158
    setFocusProxy(lineEdit);
159
}
160

161
FileChooser::~FileChooser()
162
{}
163

164
QString FileChooser::fileName() const
165
{
166
    return lineEdit->text();
167
}
168

169
void FileChooser::setFileName(const QString& fn)
170
{
171
    lineEdit->setText(fn);
172
}
173

174
void FileChooser::chooseFile()
175
{
176
    QFileDialog::Options dlgOpt = QFileDialog::DontUseNativeDialog;
177
    QString fn;
178
    if (mode() == File) {
179
        fn = QFileDialog::getOpenFileName(this,
180
                                          tr("Select a file"),
181
                                          lineEdit->text(),
182
                                          _filter,
183
                                          0,
184
                                          dlgOpt);
185
    }
186
    else {
187
        QFileDialog::Options option = QFileDialog::ShowDirsOnly | dlgOpt;
188
        fn = QFileDialog::getExistingDirectory(this,
189
                                               tr("Select a directory"),
190
                                               lineEdit->text(),
191
                                               option);
192
    }
193

194
    if (!fn.isEmpty()) {
195
        lineEdit->setText(fn);
196
        Q_EMIT fileNameSelected(fn);
197
    }
198
}
199

200
FileChooser::Mode FileChooser::mode() const
201
{
202
    return md;
203
}
204

205
void FileChooser::setMode(Mode m)
206
{
207
    md = m;
208
}
209

210
QString FileChooser::filter() const
211
{
212
    return _filter;
213
}
214

215
void FileChooser::setFilter(const QString& filter)
216
{
217
    _filter = filter;
218
}
219

220
void FileChooser::setButtonText(const QString& txt)
221
{
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(" ... ");
226
#else
227
    int w1 = 2 * button->fontMetrics().width(txt);
228
    int w2 = 2 * button->fontMetrics().width(" ... ");
229
#endif
230
    button->setFixedWidth((w1 > w2 ? w1 : w2));
231
}
232

233
QString FileChooser::buttonText() const
234
{
235
    return button->text();
236
}
237

238
// ------------------------------------------------------------------------------
239

240
PrefFileChooser::PrefFileChooser(QWidget* parent)
241
    : FileChooser(parent)
242
{}
243

244
PrefFileChooser::~PrefFileChooser()
245
{}
246

247
QByteArray PrefFileChooser::entryName() const
248
{
249
    return m_sPrefName;
250
}
251

252
QByteArray PrefFileChooser::paramGrpPath() const
253
{
254
    return m_sPrefGrp;
255
}
256

257
void PrefFileChooser::setEntryName(const QByteArray& name)
258
{
259
    m_sPrefName = name;
260
}
261

262
void PrefFileChooser::setParamGrpPath(const QByteArray& name)
263
{
264
    m_sPrefGrp = name;
265
}
266

267
// --------------------------------------------------------------------
268

269
AccelLineEdit::AccelLineEdit(QWidget* parent)
270
    : QLineEdit(parent)
271
{
272
    setPlaceholderText(tr("Press a keyboard shortcut"));
273
    setClearButtonEnabled(true);
274
    keyPressedCount = 0;
275
}
276

277
bool AccelLineEdit::isNone() const
278
{
279
    return text().isEmpty();
280
}
281

282
void AccelLineEdit::keyPressEvent(QKeyEvent* e)
283
{
284
    if (isReadOnly()) {
285
        QLineEdit::keyPressEvent(e);
286
        return;
287
    }
288

289
    QString txtLine = text();
290

291
    int key = e->key();
292
    Qt::KeyboardModifiers state = e->modifiers();
293

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.
297
    switch (key) {
298
        case Qt::Key_Backspace:
299
        case Qt::Key_Delete:
300
            if (state == Qt::NoModifier) {
301
                keyPressedCount = 0;
302
                if (isNone()) {
303
                    QKeySequence ks(key);
304
                    setText(ks.toString(QKeySequence::NativeText));
305
                }
306
                else {
307
                    clear();
308
                }
309
            }
310
        case Qt::Key_Control:
311
        case Qt::Key_Shift:
312
        case Qt::Key_Alt:
313
        case Qt::Key_Meta:
314
        case Qt::Key_AltGr:
315
            return;
316
        default:
317
            break;
318
    }
319

320
    if (txtLine.isEmpty()) {
321
        // Text maybe cleared by QLineEdit's built in clear button
322
        keyPressedCount = 0;
323
    }
324
    else {
325
        // 4 keys are allowed for QShortcut
326
        switch (keyPressedCount) {
327
            case 4:
328
                keyPressedCount = 0;
329
                txtLine.clear();
330
                break;
331
            case 0:
332
                txtLine.clear();
333
                break;
334
            default:
335
                txtLine += QString::fromLatin1(",");
336
                break;
337
        }
338
    }
339

340
    // Handles modifiers applying a mask.
341
    if ((state & Qt::ControlModifier) == Qt::ControlModifier) {
342
        QKeySequence ks(Qt::CTRL);
343
        txtLine += ks.toString(QKeySequence::NativeText);
344
    }
345
    if ((state & Qt::AltModifier) == Qt::AltModifier) {
346
        QKeySequence ks(Qt::ALT);
347
        txtLine += ks.toString(QKeySequence::NativeText);
348
    }
349
    if ((state & Qt::ShiftModifier) == Qt::ShiftModifier) {
350
        QKeySequence ks(Qt::SHIFT);
351
        txtLine += ks.toString(QKeySequence::NativeText);
352
    }
353
    if ((state & Qt::MetaModifier) == Qt::MetaModifier) {
354
        QKeySequence ks(Qt::META);
355
        txtLine += ks.toString(QKeySequence::NativeText);
356
    }
357

358
    // Handles normal keys
359
    QKeySequence ks(key);
360
    txtLine += ks.toString(QKeySequence::NativeText);
361

362
    setText(txtLine);
363
    keyPressedCount++;
364
}
365

366
// ------------------------------------------------------------------------------
367

368
ActionSelector::ActionSelector(QWidget* parent)
369
    : QWidget(parent)
370
{
371
    addButton = new QPushButton(this);
372
    addButton->setMinimumSize(QSize(30, 30));
373
    QIcon icon;
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);
378

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);
383

384
    removeButton = new QPushButton(this);
385
    removeButton->setMinimumSize(QSize(30, 30));
386
    QIcon icon1;
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);
391

392
    gridLayout->addWidget(removeButton, 2, 1, 1, 1);
393

394
    upButton = new QPushButton(this);
395
    upButton->setMinimumSize(QSize(30, 30));
396
    QIcon icon3;
397
    icon3.addFile(QString::fromUtf8(":/icons/button_up.xpm"), QSize(), QIcon::Normal, QIcon::Off);
398
    upButton->setIcon(icon3);
399

400
    gridLayout->addWidget(upButton, 3, 1, 1, 1);
401

402
    downButton = new QPushButton(this);
403
    downButton->setMinimumSize(QSize(30, 30));
404
    QIcon icon2;
405
    icon2.addFile(QString::fromUtf8(":/icons/button_down.xpm"), QSize(), QIcon::Normal, QIcon::Off);
406
    downButton->setIcon(icon2);
407
    downButton->setAutoDefault(true);
408

409
    gridLayout->addWidget(downButton, 4, 1, 1, 1);
410

411
    vboxLayout = new QVBoxLayout();
412
    vboxLayout->setContentsMargins(0, 0, 0, 0);
413
    labelAvailable = new QLabel(this);
414
    vboxLayout->addWidget(labelAvailable);
415

416
    availableWidget = new QTreeWidget(this);
417
    availableWidget->setRootIsDecorated(false);
418
    availableWidget->setHeaderLabels(QStringList() << QString());
419
    availableWidget->header()->hide();
420
    vboxLayout->addWidget(availableWidget);
421

422
    gridLayout->addLayout(vboxLayout, 0, 0, 6, 1);
423

424
    vboxLayout1 = new QVBoxLayout();
425
    vboxLayout1->setContentsMargins(0, 0, 0, 0);
426
    labelSelected = new QLabel(this);
427
    vboxLayout1->addWidget(labelSelected);
428

429
    selectedWidget = new QTreeWidget(this);
430
    selectedWidget->setRootIsDecorated(false);
431
    selectedWidget->setHeaderLabels(QStringList() << QString());
432
    selectedWidget->header()->hide();
433
    vboxLayout1->addWidget(selectedWidget);
434

435
    gridLayout->addLayout(vboxLayout1, 0, 2, 6, 1);
436

437
    addButton->setText(QString());
438
    removeButton->setText(QString());
439
    upButton->setText(QString());
440
    downButton->setText(QString());
441

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"));
448
}
449

450
ActionSelector::~ActionSelector()
451
{}
452

453
// --------------------------------------------------------------------
454

455
InputField::InputField(QWidget* parent)
456
    : QLineEdit(parent)
457
    , Value(0)
458
    , Maximum(INT_MAX)
459
    , Minimum(-INT_MAX)
460
    , StepSize(1.0)
461
    , HistorySize(5)
462
{}
463

464
InputField::~InputField()
465
{}
466

467
/** Sets the preference path to \a path. */
468
void InputField::setParamGrpPath(const QByteArray& path)
469
{
470
    m_sPrefGrp = path;
471
}
472

473
/** Returns the widget's preferences path. */
474
QByteArray InputField::paramGrpPath() const
475
{
476
    return m_sPrefGrp;
477
}
478

479
/// sets the field with a quantity
480
void InputField::setValue(double quant)
481
{
482
    Value = quant;
483
    setText(QString("%1 %2").arg(Value).arg(UnitStr));
484
}
485

486
/// sets the field with a quantity
487
double InputField::getQuantity() const
488
{
489
    return Value;
490
}
491

492
/// get the value of the singleStep property
493
double InputField::singleStep(void) const
494
{
495
    return StepSize;
496
}
497

498
/// set the value of the singleStep property
499
void InputField::setSingleStep(double s)
500
{
501
    StepSize = s;
502
}
503

504
/// get the value of the maximum property
505
double InputField::maximum(void) const
506
{
507
    return Maximum;
508
}
509

510
/// set the value of the maximum property
511
void InputField::setMaximum(double m)
512
{
513
    Maximum = m;
514
}
515

516
/// get the value of the minimum property
517
double InputField::minimum(void) const
518
{
519
    return Minimum;
520
}
521

522
/// set the value of the minimum property
523
void InputField::setMinimum(double m)
524
{
525
    Minimum = m;
526
}
527

528
void InputField::setUnitText(QString str)
529
{
530
    UnitStr = str;
531
    setText(QString("%1 %2").arg(Value).arg(UnitStr));
532
}
533

534
QString InputField::getUnitText(void)
535
{
536
    return UnitStr;
537
}
538

539
// get the value of the minimum property
540
int InputField::historySize(void) const
541
{
542
    return HistorySize;
543
}
544

545
// set the value of the minimum property
546
void InputField::setHistorySize(int i)
547
{
548
    HistorySize = i;
549
}
550

551
// --------------------------------------------------------------------
552

553
namespace Base
554
{
555

556
Unit::Unit()
557
{}
558

559
Unit::Unit(const QString& u)
560
    : unit(u)
561
{}
562

563
bool Unit::isEmpty() const
564
{
565
    return unit.isEmpty();
566
}
567

568
bool Unit::operator==(const Unit& that)
569
{
570
    return this->unit == that.unit;
571
}
572

573
bool Unit::operator!=(const Unit& that)
574
{
575
    return this->unit != that.unit;
576
}
577

578
const QString& Unit::getString() const
579
{
580
    return unit;
581
}
582

583
int QuantityFormat::defaultDenominator = 8;  // for 1/8"
584

585

586
QuantityFormat::QuantityFormat()
587
    : option(OmitGroupSeparator | RejectGroupSeparator)
588
    , format(Fixed)
589
    , precision(4)
590
    , denominator(defaultDenominator)
591
{}
592

593
Quantity::Quantity()
594
    : value(0)
595
    , unit()
596
{}
597

598
Quantity::Quantity(double v, const Unit& u)
599
    : value(v)
600
    , unit(u)
601
{}
602

603
Quantity Quantity::parse(const QString& str)
604
{
605
    bool ok;
606
    QString txt = str;
607
    QString unit;
608
    while (!txt.isEmpty() && txt[txt.length() - 1].isLetter()) {
609
        unit.prepend(txt[txt.length() - 1]);
610
        txt.chop(1);
611
    }
612

613
    double v = QLocale::system().toDouble(txt, &ok);
614
    // if (!ok && !txt.isEmpty())
615
    //     throw Base::Exception();
616
    return Quantity(v, Unit(unit));
617
}
618

619
void Quantity::setValue(double v)
620
{
621
    value = v;
622
}
623

624
double Quantity::getValue() const
625
{
626
    return value;
627
}
628

629
void Quantity::setUnit(const Unit& u)
630
{
631
    unit = u;
632
}
633

634
Unit Quantity::getUnit() const
635
{
636
    return unit;
637
}
638

639
QString Quantity::getUserString() const
640
{
641
    QLocale Lc;
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));
646
    }
647

648
    QString Ln = Lc.toString(value, format.toFormat(), format.precision);
649
    return QString::fromUtf8("%1 %2").arg(Ln, unit.getString());
650
}
651

652
QString Quantity::getUserString(double& factor, QString& unitString) const
653
{
654
    factor = 1;
655
    unitString = unit.getString();
656

657
    QLocale Lc;
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));
662
    }
663

664
    QString Ln = Lc.toString(value, format.toFormat(), format.precision);
665
    return QString::fromUtf8("%1 %2").arg(Ln, unit.getString());
666
}
667

668
}  // namespace Base
669

670
namespace Gui
671
{
672

673
class QuantitySpinBoxPrivate
674
{
675
public:
676
    QuantitySpinBoxPrivate()
677
        : validInput(true)
678
        , pendingEmit(false)
679
        , unitValue(0)
680
        , maximum(INT_MAX)
681
        , minimum(-INT_MAX)
682
        , singleStep(1.0)
683
    {}
684
    ~QuantitySpinBoxPrivate()
685
    {}
686

687
    QString stripped(const QString& t, int* pos) const
688
    {
689
        QString text = t;
690
        const int s = text.size();
691
        text = text.trimmed();
692
        if (pos) {
693
            (*pos) -= (s - text.size());
694
        }
695
        return text;
696
    }
697

698
    bool validate(QString& input, Base::Quantity& result) const
699
    {
700
        bool success = false;
701
        QString tmp = input;
702
        int pos = 0;
703
        QValidator::State state;
704
        Base::Quantity res = validateAndInterpret(tmp, pos, state);
705
        res.setFormat(quantity.getFormat());
706
        if (state == QValidator::Acceptable) {
707
            success = true;
708
            result = res;
709
            input = tmp;
710
        }
711
        else if (state == QValidator::Intermediate) {
712
            tmp = tmp.trimmed();
713
            tmp += QLatin1Char(' ');
714
            tmp += unitStr;
715
            Base::Quantity res2 = validateAndInterpret(tmp, pos, state);
716
            res2.setFormat(quantity.getFormat());
717
            if (state == QValidator::Acceptable) {
718
                success = true;
719
                result = res2;
720
                input = tmp;
721
            }
722
        }
723

724
        return success;
725
    }
726
    Base::Quantity validateAndInterpret(QString& input, int& pos, QValidator::State& state) const
727
    {
728
        Base::Quantity res;
729
        const double max = this->maximum;
730
        const double min = this->minimum;
731

732
        QString copy = input;
733

734
        int len = copy.size();
735

736
        const bool plus = max >= 0;
737
        const bool minus = min <= 0;
738

739
        switch (len) {
740
            case 0:
741
                state = max != min ? QValidator::Intermediate : QValidator::Invalid;
742
                goto end;
743
            case 1:
744
                if (copy.at(0) == locale.decimalPoint()) {
745
                    state = QValidator::Intermediate;
746
                    copy.prepend(QLatin1Char('0'));
747
                    pos++;
748
                    len++;
749
                    goto end;
750
                }
751
                else if (copy.at(0) == QLatin1Char('+')) {
752
                    // the quantity parser doesn't allow numbers of the form '+1.0'
753
                    state = QValidator::Invalid;
754
                    goto end;
755
                }
756
                else if (copy.at(0) == QLatin1Char('-')) {
757
                    if (minus) {
758
                        state = QValidator::Intermediate;
759
                    }
760
                    else {
761
                        state = QValidator::Invalid;
762
                    }
763
                    goto end;
764
                }
765
                break;
766
            case 2:
767
                if (copy.at(1) == locale.decimalPoint()
768
                    && (plus && copy.at(0) == QLatin1Char('+'))) {
769
                    state = QValidator::Intermediate;
770
                    goto end;
771
                }
772
                if (copy.at(1) == locale.decimalPoint()
773
                    && (minus && copy.at(0) == QLatin1Char('-'))) {
774
                    state = QValidator::Intermediate;
775
                    copy.insert(1, QLatin1Char('0'));
776
                    pos++;
777
                    len++;
778
                    goto end;
779
                }
780
                break;
781
            default:
782
                break;
783
        }
784

785
        {
786
            if (copy.at(0) == locale.groupSeparator()) {
787
                state = QValidator::Invalid;
788
                goto end;
789
            }
790
            else if (len > 1) {
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
795
                        if (decOccurred) {
796
                            state = QValidator::Invalid;
797
                            goto end;
798
                        }
799
                        decOccurred = true;
800
                    }
801
                    // Reset decOcurred if non-numeric character found
802
                    else if (!(copy.at(i) == locale.groupSeparator() || copy.at(i).isDigit())) {
803
                        decOccurred = false;
804
                    }
805
                }
806
            }
807

808
            bool ok = false;
809
            double value = min;
810

811
            QChar plus = QLatin1Char('+'), minus = QLatin1Char('-');
812

813
            if (locale.negativeSign() != minus) {
814
                copy.replace(locale.negativeSign(), minus);
815
            }
816
            if (locale.positiveSign() != plus) {
817
                copy.replace(locale.positiveSign(), plus);
818
            }
819

820
            try {
821
                QString copy2 = copy;
822
                copy2.remove(locale.groupSeparator());
823

824
                res = Base::Quantity::parse(copy2);
825
                value = res.getValue();
826
                ok = true;
827
            }
828
            catch (Base::Exception&) {
829
            }
830

831
            if (!ok) {
832
                // input may not be finished
833
                state = QValidator::Intermediate;
834
            }
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;
839
                }
840
                else if (res.getUnit().isEmpty() && !this->unit.isEmpty()) {
841
                    // if not dimensionless the input should have a dimension
842
                    state = QValidator::Intermediate;
843
                }
844
                else if (res.getUnit() != this->unit) {
845
                    state = QValidator::Invalid;
846
                }
847
                else {
848
                    state = QValidator::Acceptable;
849
                }
850
            }
851
            else if (max == min) {  // when max and min is the same the only non-Invalid input is
852
                                    // max (or min)
853
                state = QValidator::Invalid;
854
            }
855
            else {
856
                if ((value >= 0 && value > max) || (value < 0 && value < min)) {
857
                    state = QValidator::Invalid;
858
                }
859
                else {
860
                    state = QValidator::Intermediate;
861
                }
862
            }
863
        }
864
    end:
865
        if (state != QValidator::Acceptable) {
866
            res.setValue(max > 0 ? min : max);
867
        }
868

869
        input = copy;
870
        return res;
871
    }
872

873
    QLocale locale;
874
    bool validInput;
875
    bool pendingEmit;
876
    QString validStr;
877
    Base::Quantity quantity;
878
    Base::Quantity cached;
879
    Base::Unit unit;
880
    double unitValue;
881
    QString unitStr;
882
    double maximum;
883
    double minimum;
884
    double singleStep;
885
};
886
}  // namespace Gui
887

888
QuantitySpinBox::QuantitySpinBox(QWidget* parent)
889
    : QAbstractSpinBox(parent)
890
    , d_ptr(new QuantitySpinBoxPrivate())
891
{
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);
896
}
897

898
QuantitySpinBox::~QuantitySpinBox()
899
{}
900

901
void QuantitySpinBox::resizeEvent(QResizeEvent* event)
902
{
903
    QAbstractSpinBox::resizeEvent(event);
904
}
905

906
void Gui::QuantitySpinBox::keyPressEvent(QKeyEvent* event)
907
{
908
    QAbstractSpinBox::keyPressEvent(event);
909
}
910

911

912
void QuantitySpinBox::updateText(const Base::Quantity& quant)
913
{
914
    Q_D(QuantitySpinBox);
915

916
    double dFactor;
917
    QString txt = getUserString(quant, dFactor, d->unitStr);
918
    d->unitValue = quant.getValue() / dFactor;
919
    lineEdit()->setText(txt);
920
    handlePendingEmit();
921
}
922

923
Base::Quantity QuantitySpinBox::value() const
924
{
925
    Q_D(const QuantitySpinBox);
926
    return d->quantity;
927
}
928

929
double QuantitySpinBox::rawValue() const
930
{
931
    Q_D(const QuantitySpinBox);
932
    return d->quantity.getValue();
933
}
934

935
void QuantitySpinBox::setValue(const Base::Quantity& value)
936
{
937
    Q_D(QuantitySpinBox);
938
    d->quantity = value;
939
    // check limits
940
    if (d->quantity.getValue() > d->maximum) {
941
        d->quantity.setValue(d->maximum);
942
    }
943
    if (d->quantity.getValue() < d->minimum) {
944
        d->quantity.setValue(d->minimum);
945
    }
946

947
    d->unit = value.getUnit();
948

949
    updateText(value);
950
}
951

952
void QuantitySpinBox::setValue(double value)
953
{
954
    Q_D(QuantitySpinBox);
955
    setValue(Base::Quantity(value, d->unit));
956
}
957

958
bool QuantitySpinBox::hasValidInput() const
959
{
960
    Q_D(const QuantitySpinBox);
961
    return d->validInput;
962
}
963

964
// Gets called after call of 'validateAndInterpret'
965
void QuantitySpinBox::userInput(const QString& text)
966
{
967
    Q_D(QuantitySpinBox);
968

969
    d->pendingEmit = true;
970

971
    QString tmp = text;
972
    Base::Quantity res;
973
    if (d->validate(tmp, res)) {
974
        d->validStr = tmp;
975
        d->validInput = true;
976
    }
977
    else {
978
        d->validInput = false;
979
        return;
980
    }
981

982
    if (keyboardTracking()) {
983
        d->cached = res;
984
        handlePendingEmit();
985
    }
986
    else {
987
        d->cached = res;
988
    }
989
}
990

991
void QuantitySpinBox::handlePendingEmit()
992
{
993
    updateFromCache(true);
994
}
995

996
void QuantitySpinBox::updateFromCache(bool notify)
997
{
998
    Q_D(QuantitySpinBox);
999
    if (d->pendingEmit) {
1000
        double factor;
1001
        const Base::Quantity& res = d->cached;
1002
        QString text = getUserString(res, factor, d->unitStr);
1003
        d->unitValue = res.getValue() / factor;
1004
        d->quantity = res;
1005

1006
        // signaling
1007
        if (notify) {
1008
            d->pendingEmit = false;
1009
            valueChanged(res);
1010
            valueChanged(res.getValue());
1011
            textChanged(text);
1012
        }
1013
    }
1014
}
1015

1016
Base::Unit QuantitySpinBox::unit() const
1017
{
1018
    Q_D(const QuantitySpinBox);
1019
    return d->unit;
1020
}
1021

1022
void QuantitySpinBox::setUnit(const Base::Unit& unit)
1023
{
1024
    Q_D(QuantitySpinBox);
1025

1026
    d->unit = unit;
1027
    d->quantity.setUnit(unit);
1028
    updateText(d->quantity);
1029
}
1030

1031
void QuantitySpinBox::setUnitText(const QString& str)
1032
{
1033
    try {
1034
        Base::Quantity quant = Base::Quantity::parse(str);
1035
        setUnit(quant.getUnit());
1036
    }
1037
    catch (const Base::Exception&) {
1038
    }
1039
}
1040

1041
QString QuantitySpinBox::unitText(void)
1042
{
1043
    Q_D(QuantitySpinBox);
1044
    return d->unitStr;
1045
}
1046

1047
double QuantitySpinBox::singleStep() const
1048
{
1049
    Q_D(const QuantitySpinBox);
1050
    return d->singleStep;
1051
}
1052

1053
void QuantitySpinBox::setSingleStep(double value)
1054
{
1055
    Q_D(QuantitySpinBox);
1056

1057
    if (value >= 0) {
1058
        d->singleStep = value;
1059
    }
1060
}
1061

1062
double QuantitySpinBox::minimum() const
1063
{
1064
    Q_D(const QuantitySpinBox);
1065
    return d->minimum;
1066
}
1067

1068
void QuantitySpinBox::setMinimum(double minimum)
1069
{
1070
    Q_D(QuantitySpinBox);
1071
    d->minimum = minimum;
1072
}
1073

1074
double QuantitySpinBox::maximum() const
1075
{
1076
    Q_D(const QuantitySpinBox);
1077
    return d->maximum;
1078
}
1079

1080
void QuantitySpinBox::setMaximum(double maximum)
1081
{
1082
    Q_D(QuantitySpinBox);
1083
    d->maximum = maximum;
1084
}
1085

1086
void QuantitySpinBox::setRange(double minimum, double maximum)
1087
{
1088
    Q_D(QuantitySpinBox);
1089
    d->minimum = minimum;
1090
    d->maximum = maximum;
1091
}
1092

1093
int QuantitySpinBox::decimals() const
1094
{
1095
    Q_D(const QuantitySpinBox);
1096
    return d->quantity.getFormat().precision;
1097
}
1098

1099
void QuantitySpinBox::setDecimals(int v)
1100
{
1101
    Q_D(QuantitySpinBox);
1102
    Base::QuantityFormat f = d->quantity.getFormat();
1103
    f.precision = v;
1104
    d->quantity.setFormat(f);
1105
    updateText(d->quantity);
1106
}
1107

1108
void QuantitySpinBox::clearSchema()
1109
{
1110
    Q_D(QuantitySpinBox);
1111
    updateText(d->quantity);
1112
}
1113

1114
QString
1115
QuantitySpinBox::getUserString(const Base::Quantity& val, double& factor, QString& unitString) const
1116
{
1117
    return val.getUserString(factor, unitString);
1118
}
1119

1120
QString QuantitySpinBox::getUserString(const Base::Quantity& val) const
1121
{
1122
    return val.getUserString();
1123
}
1124

1125
QAbstractSpinBox::StepEnabled QuantitySpinBox::stepEnabled() const
1126
{
1127
    Q_D(const QuantitySpinBox);
1128
    if (isReadOnly() /* || !d->validInput*/) {
1129
        return StepNone;
1130
    }
1131
    if (wrapping()) {
1132
        return StepEnabled(StepUpEnabled | StepDownEnabled);
1133
    }
1134
    StepEnabled ret = StepNone;
1135
    if (d->quantity.getValue() < d->maximum) {
1136
        ret |= StepUpEnabled;
1137
    }
1138
    if (d->quantity.getValue() > d->minimum) {
1139
        ret |= StepDownEnabled;
1140
    }
1141
    return ret;
1142
}
1143

1144
void QuantitySpinBox::stepBy(int steps)
1145
{
1146
    Q_D(QuantitySpinBox);
1147
    updateFromCache(false);
1148

1149
    double step = d->singleStep * steps;
1150
    double val = d->unitValue + step;
1151
    if (val > d->maximum) {
1152
        val = d->maximum;
1153
    }
1154
    else if (val < d->minimum) {
1155
        val = d->minimum;
1156
    }
1157

1158
    lineEdit()->setText(QString::fromUtf8("%L1 %2").arg(val).arg(d->unitStr));
1159
    updateFromCache(true);
1160
    update();
1161
    selectNumber();
1162
}
1163

1164
QSize QuantitySpinBox::sizeHint() const
1165
{
1166
    ensurePolished();
1167

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();
1172
    int w = 0;
1173

1174
    QString s = QLatin1String("000000000000000000");
1175
    QString fixedContent = QLatin1String(" ");
1176
    s += fixedContent;
1177

1178
#if QT_VERSION >= QT_VERSION_CHECK(5, 11, 0)
1179
    w = fm.horizontalAdvance(s);
1180
#else
1181
    w = fm.width(s);
1182
#endif
1183

1184
    w += 2;  // cursor blinking space
1185
    w += iconHeight;
1186

1187
    QStyleOptionSpinBox opt;
1188
    initStyleOption(&opt);
1189
    QSize hint(w, h);
1190
    QSize size = style()->sizeFromContents(QStyle::CT_SpinBox, &opt, hint, this);
1191
    return size;
1192
}
1193

1194
QSize QuantitySpinBox::minimumSizeHint() const
1195
{
1196
    ensurePolished();
1197

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();
1202
    int w = 0;
1203

1204
    QString s = QLatin1String("000000000000000000");
1205
    QString fixedContent = QLatin1String(" ");
1206
    s += fixedContent;
1207

1208
#if QT_VERSION >= QT_VERSION_CHECK(5, 11, 0)
1209
    w = fm.horizontalAdvance(s);
1210
#else
1211
    w = fm.width(s);
1212
#endif
1213

1214
    w += 2;  // cursor blinking space
1215
    w += iconHeight;
1216

1217
    QStyleOptionSpinBox opt;
1218
    initStyleOption(&opt);
1219
    QSize hint(w, h);
1220
    QSize size = style()->sizeFromContents(QStyle::CT_SpinBox, &opt, hint, this);
1221
    return size;
1222
}
1223

1224
void QuantitySpinBox::showEvent(QShowEvent* event)
1225
{
1226
    Q_D(QuantitySpinBox);
1227

1228
    QAbstractSpinBox::showEvent(event);
1229

1230
    bool selected = lineEdit()->hasSelectedText();
1231
    updateText(d->quantity);
1232
    if (selected) {
1233
        selectNumber();
1234
    }
1235
}
1236

1237
void QuantitySpinBox::hideEvent(QHideEvent* event)
1238
{
1239
    handlePendingEmit();
1240
    QAbstractSpinBox::hideEvent(event);
1241
}
1242

1243
void QuantitySpinBox::closeEvent(QCloseEvent* event)
1244
{
1245
    handlePendingEmit();
1246
    QAbstractSpinBox::closeEvent(event);
1247
}
1248

1249
bool QuantitySpinBox::event(QEvent* event)
1250
{
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.
1254
    //
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.
1260
#if 0
1261
    if (event->type() == QEvent::ToolTip) {
1262
        if (isBound() && getExpression() && lineEdit()->isReadOnly()) {
1263
            QHelpEvent * helpEvent = static_cast<QHelpEvent*>(event);
1264

1265
            QToolTip::showText( helpEvent->globalPos(), Base::Tools::fromStdString(getExpression()->toString()), this);
1266
            event->accept();
1267
            return true;
1268
        }
1269
    }
1270
#endif
1271

1272
    return QAbstractSpinBox::event(event);
1273
}
1274

1275
void QuantitySpinBox::focusInEvent(QFocusEvent* event)
1276
{
1277
    bool hasSel = lineEdit()->hasSelectedText();
1278
    QAbstractSpinBox::focusInEvent(event);
1279

1280
    if (event->reason() == Qt::TabFocusReason || event->reason() == Qt::BacktabFocusReason
1281
        || event->reason() == Qt::ShortcutFocusReason) {
1282

1283
        if (!hasSel) {
1284
            selectNumber();
1285
        }
1286
    }
1287
}
1288

1289
void QuantitySpinBox::focusOutEvent(QFocusEvent* event)
1290
{
1291
    Q_D(QuantitySpinBox);
1292

1293
    int pos = 0;
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);
1299
    }
1300

1301
    handlePendingEmit();
1302

1303
    QToolTip::hideText();
1304
    QAbstractSpinBox::focusOutEvent(event);
1305
}
1306

1307
void QuantitySpinBox::clear()
1308
{
1309
    QAbstractSpinBox::clear();
1310
}
1311

1312
void QuantitySpinBox::selectNumber()
1313
{
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());
1323
    }
1324
}
1325

1326
QString QuantitySpinBox::textFromValue(const Base::Quantity& value) const
1327
{
1328
    double factor;
1329
    QString unitStr;
1330
    QString str = getUserString(value, factor, unitStr);
1331
    if (qAbs(value.getValue()) >= 1000.0) {
1332
        str.remove(locale().groupSeparator());
1333
    }
1334
    return str;
1335
}
1336

1337
Base::Quantity QuantitySpinBox::valueFromText(const QString& text) const
1338
{
1339
    Q_D(const QuantitySpinBox);
1340

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) {
1346
        fixup(copy);
1347
        quant = d->validateAndInterpret(copy, pos, state);
1348
    }
1349

1350
    return quant;
1351
}
1352

1353
QValidator::State QuantitySpinBox::validate(QString& text, int& pos) const
1354
{
1355
    Q_D(const QuantitySpinBox);
1356

1357
    QValidator::State state;
1358
    d->validateAndInterpret(text, pos, state);
1359
    return state;
1360
}
1361

1362
void QuantitySpinBox::fixup(QString& input) const
1363
{
1364
    input.remove(locale().groupSeparator());
1365
}
1366

1367
// ------------------------------------------------------------------------------
1368

1369
PrefUnitSpinBox::PrefUnitSpinBox(QWidget* parent)
1370
    : QuantitySpinBox(parent)
1371
{}
1372

1373
PrefUnitSpinBox::~PrefUnitSpinBox()
1374
{}
1375

1376
QByteArray PrefUnitSpinBox::entryName() const
1377
{
1378
    return m_sPrefName;
1379
}
1380

1381
QByteArray PrefUnitSpinBox::paramGrpPath() const
1382
{
1383
    return m_sPrefGrp;
1384
}
1385

1386
void PrefUnitSpinBox::setEntryName(const QByteArray& name)
1387
{
1388
    m_sPrefName = name;
1389
}
1390

1391
void PrefUnitSpinBox::setParamGrpPath(const QByteArray& name)
1392
{
1393
    m_sPrefGrp = name;
1394
}
1395

1396
// --------------------------------------------------------------------
1397

1398
PrefQuantitySpinBox::PrefQuantitySpinBox(QWidget* parent)
1399
    : QuantitySpinBox(parent)
1400
{}
1401

1402
PrefQuantitySpinBox::~PrefQuantitySpinBox()
1403
{}
1404

1405
QByteArray PrefQuantitySpinBox::entryName() const
1406
{
1407
    return m_sPrefName;
1408
}
1409

1410
QByteArray PrefQuantitySpinBox::paramGrpPath() const
1411
{
1412
    return m_sPrefGrp;
1413
}
1414

1415
void PrefQuantitySpinBox::setEntryName(const QByteArray& name)
1416
{
1417
    m_sPrefName = name;
1418
}
1419

1420
void PrefQuantitySpinBox::setParamGrpPath(const QByteArray& name)
1421
{
1422
    m_sPrefGrp = name;
1423
}
1424

1425
// --------------------------------------------------------------------
1426

1427
CommandIconView::CommandIconView(QWidget* parent)
1428
    : QListWidget(parent)
1429
{
1430
    connect(this, &QListWidget::currentItemChanged, this, &CommandIconView::onSelectionChanged);
1431
}
1432

1433
CommandIconView::~CommandIconView()
1434
{}
1435

1436
void CommandIconView::startDrag(Qt::DropActions /*supportedActions*/)
1437
{
1438
    QList<QListWidgetItem*> items = selectedItems();
1439
    QByteArray itemData;
1440
    QDataStream dataStream(&itemData, QIODevice::WriteOnly);
1441

1442
    QPixmap pixmap;
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>();
1447
        }
1448
        dataStream << (*it)->text();
1449
    }
1450

1451
    QMimeData* mimeData = new QMimeData;
1452
    mimeData->setData("text/x-action-items", itemData);
1453

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);
1459
}
1460

1461
void CommandIconView::onSelectionChanged(QListWidgetItem* item, QListWidgetItem*)
1462
{
1463
    if (item) {
1464
        emitSelectionChanged(item->toolTip());
1465
    }
1466
}
1467

1468
// ------------------------------------------------------------------------------
1469

1470
namespace Gui
1471
{
1472

1473
class UnsignedValidator: public QValidator
1474
{
1475
public:
1476
    UnsignedValidator(QObject* parent);
1477
    UnsignedValidator(uint minimum, uint maximum, QObject* parent);
1478
    ~UnsignedValidator();
1479

1480
    QValidator::State validate(QString&, int&) const;
1481

1482
    void setBottom(uint);
1483
    void setTop(uint);
1484
    virtual void setRange(uint bottom, uint top);
1485

1486
    uint bottom() const
1487
    {
1488
        return b;
1489
    }
1490
    uint top() const
1491
    {
1492
        return t;
1493
    }
1494

1495
private:
1496
    uint b, t;
1497
};
1498

1499
UnsignedValidator::UnsignedValidator(QObject* parent)
1500
    : QValidator(parent)
1501
{
1502
    b = 0;
1503
    t = UINT_MAX;
1504
}
1505

1506
UnsignedValidator::UnsignedValidator(uint minimum, uint maximum, QObject* parent)
1507
    : QValidator(parent)
1508
{
1509
    b = minimum;
1510
    t = maximum;
1511
}
1512

1513
UnsignedValidator::~UnsignedValidator()
1514
{}
1515

1516
QValidator::State UnsignedValidator::validate(QString& input, int&) const
1517
{
1518
    QString stripped;  // = input.stripWhiteSpace();
1519
    if (stripped.isEmpty()) {
1520
        return Intermediate;
1521
    }
1522
    bool ok;
1523
    uint entered = input.toUInt(&ok);
1524
    if (!ok) {
1525
        return Invalid;
1526
    }
1527
    else if (entered < b) {
1528
        return Intermediate;
1529
    }
1530
    else if (entered > t) {
1531
        return Invalid;
1532
    }
1533
    //  else if ( entered < b || entered > t )
1534
    //	  return Invalid;
1535
    else {
1536
        return Acceptable;
1537
    }
1538
}
1539

1540
void UnsignedValidator::setRange(uint minimum, uint maximum)
1541
{
1542
    b = minimum;
1543
    t = maximum;
1544
}
1545

1546
void UnsignedValidator::setBottom(uint bottom)
1547
{
1548
    setRange(bottom, top());
1549
}
1550

1551
void UnsignedValidator::setTop(uint top)
1552
{
1553
    setRange(bottom(), top);
1554
}
1555

1556
class UIntSpinBoxPrivate
1557
{
1558
public:
1559
    UnsignedValidator* mValidator;
1560

1561
    UIntSpinBoxPrivate()
1562
        : mValidator(0)
1563
    {}
1564
    uint mapToUInt(int v) const
1565
    {
1566
        uint ui;
1567
        if (v == INT_MIN) {
1568
            ui = 0;
1569
        }
1570
        else if (v == INT_MAX) {
1571
            ui = UINT_MAX;
1572
        }
1573
        else if (v < 0) {
1574
            v -= INT_MIN;
1575
            ui = (uint)v;
1576
        }
1577
        else {
1578
            ui = (uint)v;
1579
            ui -= INT_MIN;
1580
        }
1581
        return ui;
1582
    }
1583
    int mapToInt(uint v) const
1584
    {
1585
        int in;
1586
        if (v == UINT_MAX) {
1587
            in = INT_MAX;
1588
        }
1589
        else if (v == 0) {
1590
            in = INT_MIN;
1591
        }
1592
        else if (v > INT_MAX) {
1593
            v += INT_MIN;
1594
            in = (int)v;
1595
        }
1596
        else {
1597
            in = v;
1598
            in += INT_MIN;
1599
        }
1600
        return in;
1601
    }
1602
};
1603

1604
}  // namespace Gui
1605

1606
// -------------------------------------------------------------
1607

1608
UIntSpinBox::UIntSpinBox(QWidget* parent)
1609
    : QSpinBox(parent)
1610
{
1611
    d = new UIntSpinBoxPrivate;
1612
    d->mValidator = new UnsignedValidator(this->minimum(), this->maximum(), this);
1613
    connect(this, qOverload<int>(&QSpinBox::valueChanged), this, &UIntSpinBox::valueChange);
1614
    setRange(0, 99);
1615
    setValue(0);
1616
    updateValidator();
1617
}
1618

1619
UIntSpinBox::~UIntSpinBox()
1620
{
1621
    delete d->mValidator;
1622
    delete d;
1623
    d = 0;
1624
}
1625

1626
void UIntSpinBox::setRange(uint minVal, uint maxVal)
1627
{
1628
    int iminVal = d->mapToInt(minVal);
1629
    int imaxVal = d->mapToInt(maxVal);
1630
    QSpinBox::setRange(iminVal, imaxVal);
1631
    updateValidator();
1632
}
1633

1634
QValidator::State UIntSpinBox::validate(QString& input, int& pos) const
1635
{
1636
    return d->mValidator->validate(input, pos);
1637
}
1638

1639
uint UIntSpinBox::value() const
1640
{
1641
    return d->mapToUInt(QSpinBox::value());
1642
}
1643

1644
void UIntSpinBox::setValue(uint value)
1645
{
1646
    QSpinBox::setValue(d->mapToInt(value));
1647
}
1648

1649
void UIntSpinBox::valueChange(int value)
1650
{
1651
    unsignedChanged(d->mapToUInt(value));
1652
}
1653

1654
uint UIntSpinBox::minimum() const
1655
{
1656
    return d->mapToUInt(QSpinBox::minimum());
1657
}
1658

1659
void UIntSpinBox::setMinimum(uint minVal)
1660
{
1661
    uint maxVal = maximum();
1662
    if (maxVal < minVal) {
1663
        maxVal = minVal;
1664
    }
1665
    setRange(minVal, maxVal);
1666
}
1667

1668
uint UIntSpinBox::maximum() const
1669
{
1670
    return d->mapToUInt(QSpinBox::maximum());
1671
}
1672

1673
void UIntSpinBox::setMaximum(uint maxVal)
1674
{
1675
    uint minVal = minimum();
1676
    if (minVal > maxVal) {
1677
        minVal = maxVal;
1678
    }
1679
    setRange(minVal, maxVal);
1680
}
1681

1682
QString UIntSpinBox::textFromValue(int v) const
1683
{
1684
    uint val = d->mapToUInt(v);
1685
    QString s;
1686
    s.setNum(val);
1687
    return s;
1688
}
1689

1690
int UIntSpinBox::valueFromText(const QString& text) const
1691
{
1692
    bool ok;
1693
    QString s = text;
1694
    uint newVal = s.toUInt(&ok);
1695
    if (!ok && !(prefix().isEmpty() && suffix().isEmpty())) {
1696
        s = cleanText();
1697
        newVal = s.toUInt(&ok);
1698
    }
1699

1700
    return d->mapToInt(newVal);
1701
}
1702

1703
void UIntSpinBox::updateValidator()
1704
{
1705
    d->mValidator->setRange(this->minimum(), this->maximum());
1706
}
1707

1708
// --------------------------------------------------------------------
1709

1710
IntSpinBox::IntSpinBox(QWidget* parent)
1711
    : QSpinBox(parent)
1712
{}
1713

1714
IntSpinBox::~IntSpinBox()
1715
{}
1716

1717
// --------------------------------------------------------------------
1718

1719
PrefSpinBox::PrefSpinBox(QWidget* parent)
1720
    : QSpinBox(parent)
1721
{}
1722

1723
PrefSpinBox::~PrefSpinBox()
1724
{}
1725

1726
QByteArray PrefSpinBox::entryName() const
1727
{
1728
    return m_sPrefName;
1729
}
1730

1731
QByteArray PrefSpinBox::paramGrpPath() const
1732
{
1733
    return m_sPrefGrp;
1734
}
1735

1736
void PrefSpinBox::setEntryName(const QByteArray& name)
1737
{
1738
    m_sPrefName = name;
1739
}
1740

1741
void PrefSpinBox::setParamGrpPath(const QByteArray& name)
1742
{
1743
    m_sPrefGrp = name;
1744
}
1745

1746
// --------------------------------------------------------------------
1747

1748
DoubleSpinBox::DoubleSpinBox(QWidget* parent)
1749
    : QDoubleSpinBox(parent)
1750
{}
1751

1752
DoubleSpinBox::~DoubleSpinBox()
1753
{}
1754

1755
// --------------------------------------------------------------------
1756

1757
PrefDoubleSpinBox::PrefDoubleSpinBox(QWidget* parent)
1758
    : QDoubleSpinBox(parent)
1759
{}
1760

1761
PrefDoubleSpinBox::~PrefDoubleSpinBox()
1762
{}
1763

1764
QByteArray PrefDoubleSpinBox::entryName() const
1765
{
1766
    return m_sPrefName;
1767
}
1768

1769
QByteArray PrefDoubleSpinBox::paramGrpPath() const
1770
{
1771
    return m_sPrefGrp;
1772
}
1773

1774
void PrefDoubleSpinBox::setEntryName(const QByteArray& name)
1775
{
1776
    m_sPrefName = name;
1777
}
1778

1779
void PrefDoubleSpinBox::setParamGrpPath(const QByteArray& name)
1780
{
1781
    m_sPrefGrp = name;
1782
}
1783

1784
// -------------------------------------------------------------
1785

1786
ColorButton::ColorButton(QWidget* parent)
1787
    : QPushButton(parent)
1788
    , _allowChange(true)
1789
    , _allowTransparency(false)
1790
    , _drawFrame(true)
1791
{
1792
    _col = palette().color(QPalette::Active, QPalette::Midlight);
1793
    connect(this, &ColorButton::clicked, this, &ColorButton::onChooseColor);
1794
}
1795

1796
ColorButton::~ColorButton()
1797
{}
1798

1799
void ColorButton::setColor(const QColor& c)
1800
{
1801
    _col = c;
1802
    update();
1803
}
1804

1805
QColor ColorButton::color() const
1806
{
1807
    return _col;
1808
}
1809

1810
void ColorButton::setAllowChangeColor(bool ok)
1811
{
1812
    _allowChange = ok;
1813
}
1814

1815
bool ColorButton::allowChangeColor() const
1816
{
1817
    return _allowChange;
1818
}
1819

1820
void ColorButton::setAllowTransparency(bool ok)
1821
{
1822
    _allowTransparency = ok;
1823
}
1824

1825
bool ColorButton::allowTransparency() const
1826
{
1827
    return _allowTransparency;
1828
}
1829

1830
void ColorButton::setDrawFrame(bool ok)
1831
{
1832
    _drawFrame = ok;
1833
}
1834

1835
bool ColorButton::drawFrame() const
1836
{
1837
    return _drawFrame;
1838
}
1839

1840
void ColorButton::paintEvent(QPaintEvent* e)
1841
{
1842
    // first paint the complete button
1843
    QPushButton::paintEvent(e);
1844

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);
1849
    {
1850
        QPainter paint(this);
1851
        paint.setPen(pen);
1852

1853
        if (_drawFrame) {
1854
            paint.setBrush(QBrush(_col));
1855
            paint.drawRect(5, 5, width() - 10, height() - 10);
1856
        }
1857
        else {
1858
            paint.fillRect(5, 5, width() - 10, height() - 10, QBrush(_col));
1859
        }
1860
    }
1861

1862
    // overpaint the rectangle to paint icon and text
1863
    QStyleOptionButton opt;
1864
    opt.initFrom(this);
1865
    opt.text = text();
1866
    opt.icon = icon();
1867
    opt.iconSize = iconSize();
1868

1869
    QStylePainter p(this);
1870
    p.drawControl(QStyle::CE_PushButtonLabel, opt);
1871
}
1872

1873
void ColorButton::onChooseColor()
1874
{
1875
    if (!_allowChange) {
1876
        return;
1877
    }
1878
    QColor c = QColorDialog::getColor(_col, this);
1879
    if (c.isValid()) {
1880
        setColor(c);
1881
        Q_EMIT changed();
1882
    }
1883
}
1884

1885
// ------------------------------------------------------------------------------
1886

1887
PrefColorButton::PrefColorButton(QWidget* parent)
1888
    : ColorButton(parent)
1889
{}
1890

1891
PrefColorButton::~PrefColorButton()
1892
{}
1893

1894
QByteArray PrefColorButton::entryName() const
1895
{
1896
    return m_sPrefName;
1897
}
1898

1899
QByteArray PrefColorButton::paramGrpPath() const
1900
{
1901
    return m_sPrefGrp;
1902
}
1903

1904
void PrefColorButton::setEntryName(const QByteArray& name)
1905
{
1906
    m_sPrefName = name;
1907
}
1908

1909
void PrefColorButton::setParamGrpPath(const QByteArray& name)
1910
{
1911
    m_sPrefGrp = name;
1912
}
1913

1914
// --------------------------------------------------------------------
1915

1916
PrefLineEdit::PrefLineEdit(QWidget* parent)
1917
    : QLineEdit(parent)
1918
{}
1919

1920
PrefLineEdit::~PrefLineEdit()
1921
{}
1922

1923
QByteArray PrefLineEdit::entryName() const
1924
{
1925
    return m_sPrefName;
1926
}
1927

1928
QByteArray PrefLineEdit::paramGrpPath() const
1929
{
1930
    return m_sPrefGrp;
1931
}
1932

1933
void PrefLineEdit::setEntryName(const QByteArray& name)
1934
{
1935
    m_sPrefName = name;
1936
}
1937

1938
void PrefLineEdit::setParamGrpPath(const QByteArray& name)
1939
{
1940
    m_sPrefGrp = name;
1941
}
1942

1943
// --------------------------------------------------------------------
1944

1945
PrefComboBox::PrefComboBox(QWidget* parent)
1946
    : QComboBox(parent)
1947
{
1948
    setEditable(false);
1949
}
1950

1951
PrefComboBox::~PrefComboBox()
1952
{}
1953

1954
QByteArray PrefComboBox::entryName() const
1955
{
1956
    return m_sPrefName;
1957
}
1958

1959
QByteArray PrefComboBox::paramGrpPath() const
1960
{
1961
    return m_sPrefGrp;
1962
}
1963

1964
void PrefComboBox::setEntryName(const QByteArray& name)
1965
{
1966
    m_sPrefName = name;
1967
}
1968

1969
void PrefComboBox::setParamGrpPath(const QByteArray& name)
1970
{
1971
    m_sPrefGrp = name;
1972
}
1973

1974
// --------------------------------------------------------------------
1975

1976
PrefCheckBox::PrefCheckBox(QWidget* parent)
1977
    : QCheckBox(parent)
1978
{
1979
    setText("CheckBox");
1980
}
1981

1982
PrefCheckBox::~PrefCheckBox()
1983
{}
1984

1985
QByteArray PrefCheckBox::entryName() const
1986
{
1987
    return m_sPrefName;
1988
}
1989

1990
QByteArray PrefCheckBox::paramGrpPath() const
1991
{
1992
    return m_sPrefGrp;
1993
}
1994

1995
void PrefCheckBox::setEntryName(const QByteArray& name)
1996
{
1997
    m_sPrefName = name;
1998
}
1999

2000
void PrefCheckBox::setParamGrpPath(const QByteArray& name)
2001
{
2002
    m_sPrefGrp = name;
2003
}
2004

2005
// --------------------------------------------------------------------
2006

2007
PrefRadioButton::PrefRadioButton(QWidget* parent)
2008
    : QRadioButton(parent)
2009
{
2010
    setText("RadioButton");
2011
}
2012

2013
PrefRadioButton::~PrefRadioButton()
2014
{}
2015

2016
QByteArray PrefRadioButton::entryName() const
2017
{
2018
    return m_sPrefName;
2019
}
2020

2021
QByteArray PrefRadioButton::paramGrpPath() const
2022
{
2023
    return m_sPrefGrp;
2024
}
2025

2026
void PrefRadioButton::setEntryName(const QByteArray& name)
2027
{
2028
    m_sPrefName = name;
2029
}
2030

2031
void PrefRadioButton::setParamGrpPath(const QByteArray& name)
2032
{
2033
    m_sPrefGrp = name;
2034
}
2035

2036
// --------------------------------------------------------------------
2037

2038
PrefSlider::PrefSlider(QWidget* parent)
2039
    : QSlider(parent)
2040
{}
2041

2042
PrefSlider::~PrefSlider()
2043
{}
2044

2045
QByteArray PrefSlider::entryName() const
2046
{
2047
    return m_sPrefName;
2048
}
2049

2050
QByteArray PrefSlider::paramGrpPath() const
2051
{
2052
    return m_sPrefGrp;
2053
}
2054

2055
void PrefSlider::setEntryName(const QByteArray& name)
2056
{
2057
    m_sPrefName = name;
2058
}
2059

2060
void PrefSlider::setParamGrpPath(const QByteArray& name)
2061
{
2062
    m_sPrefGrp = name;
2063
}
2064

2065
// --------------------------------------------------------------------
2066

2067
PrefFontBox::PrefFontBox(QWidget* parent)
2068
    : QFontComboBox(parent)
2069
{}
2070

2071
PrefFontBox::~PrefFontBox()
2072
{}
2073

2074
QByteArray PrefFontBox::entryName() const
2075
{
2076
    return m_sPrefName;
2077
}
2078

2079
QByteArray PrefFontBox::paramGrpPath() const
2080
{
2081
    return m_sPrefGrp;
2082
}
2083

2084
void PrefFontBox::setEntryName(const QByteArray& name)
2085
{
2086
    m_sPrefName = name;
2087
}
2088

2089
void PrefFontBox::setParamGrpPath(const QByteArray& name)
2090
{
2091
    m_sPrefGrp = name;
2092
}
2093

Использование cookies

Мы используем файлы cookie в соответствии с Политикой конфиденциальности и Политикой использования cookies.

Нажимая кнопку «Принимаю», Вы даете АО «СберТех» согласие на обработку Ваших персональных данных в целях совершенствования нашего веб-сайта и Сервиса GitVerse, а также повышения удобства их использования.

Запретить использование cookies Вы можете самостоятельно в настройках Вашего браузера.