]> Git Repo - VerusCoin.git/blob - src/qt/bitcoinamountfield.cpp
Remove references to X11 licence
[VerusCoin.git] / src / qt / bitcoinamountfield.cpp
1 // Copyright (c) 2011-2014 The Bitcoin developers
2 // Distributed under the MIT software license, see the accompanying
3 // file COPYING or http://www.opensource.org/licenses/mit-license.php.
4
5 #include "bitcoinamountfield.h"
6
7 #include "bitcoinunits.h"
8 #include "guiconstants.h"
9 #include "qvaluecombobox.h"
10
11 #include <QApplication>
12 #include <QAbstractSpinBox>
13 #include <QHBoxLayout>
14 #include <QKeyEvent>
15 #include <QLineEdit>
16
17 /** QSpinBox that uses fixed-point numbers internally and uses our own
18  * formatting/parsing functions.
19  */
20 class AmountSpinBox: public QAbstractSpinBox
21 {
22     Q_OBJECT
23 public:
24     explicit AmountSpinBox(QWidget *parent):
25         QAbstractSpinBox(parent),
26         currentUnit(BitcoinUnits::BTC),
27         singleStep(100000) // satoshis
28     {
29         setAlignment(Qt::AlignRight);
30
31         connect(lineEdit(), SIGNAL(textEdited(QString)), this, SIGNAL(valueChanged()));
32     }
33
34     QValidator::State validate(QString &text, int &pos) const
35     {
36         if(text.isEmpty())
37             return QValidator::Intermediate;
38         bool valid = false;
39         parse(text, &valid);
40         /* Make sure we return Intermediate so that fixup() is called on defocus */
41         return valid ? QValidator::Intermediate : QValidator::Invalid;
42     }
43
44     void fixup(QString &input) const
45     {
46         bool valid = false;
47         CAmount val = parse(input, &valid);
48         if(valid)
49         {
50             input = BitcoinUnits::format(currentUnit, val, false, BitcoinUnits::separatorAlways);
51             lineEdit()->setText(input);
52         }
53     }
54
55     CAmount value(bool *valid_out=0) const
56     {
57         return parse(text(), valid_out);
58     }
59
60     void setValue(const CAmount& value)
61     {
62         lineEdit()->setText(BitcoinUnits::format(currentUnit, value, false, BitcoinUnits::separatorAlways));
63         emit valueChanged();
64     }
65
66     void stepBy(int steps)
67     {
68         bool valid = false;
69         CAmount val = value(&valid);
70         val = val + steps * singleStep;
71         val = qMin(qMax(val, CAmount(0)), BitcoinUnits::maxMoney());
72         setValue(val);
73     }
74
75     StepEnabled stepEnabled() const
76     {
77         StepEnabled rv = 0;
78         if(text().isEmpty()) // Allow step-up with empty field
79             return StepUpEnabled;
80         bool valid = false;
81         CAmount val = value(&valid);
82         if(valid)
83         {
84             if(val > 0)
85                 rv |= StepDownEnabled;
86             if(val < BitcoinUnits::maxMoney())
87                 rv |= StepUpEnabled;
88         }
89         return rv;
90     }
91
92     void setDisplayUnit(int unit)
93     {
94         bool valid = false;
95         CAmount val = value(&valid);
96
97         currentUnit = unit;
98
99         if(valid)
100             setValue(val);
101         else
102             clear();
103     }
104
105     void setSingleStep(const CAmount& step)
106     {
107         singleStep = step;
108     }
109
110     QSize minimumSizeHint() const
111     {
112         if(cachedMinimumSizeHint.isEmpty())
113         {
114             ensurePolished();
115
116             const QFontMetrics fm(fontMetrics());
117             int h = lineEdit()->minimumSizeHint().height();
118             int w = fm.width(BitcoinUnits::format(BitcoinUnits::BTC, BitcoinUnits::maxMoney(), false, BitcoinUnits::separatorAlways));
119             w += 2; // cursor blinking space
120
121             QStyleOptionSpinBox opt;
122             initStyleOption(&opt);
123             QSize hint(w, h);
124             QSize extra(35, 6);
125             opt.rect.setSize(hint + extra);
126             extra += hint - style()->subControlRect(QStyle::CC_SpinBox, &opt,
127                                                     QStyle::SC_SpinBoxEditField, this).size();
128             // get closer to final result by repeating the calculation
129             opt.rect.setSize(hint + extra);
130             extra += hint - style()->subControlRect(QStyle::CC_SpinBox, &opt,
131                                                     QStyle::SC_SpinBoxEditField, this).size();
132             hint += extra;
133             hint.setHeight(h);
134
135             opt.rect = rect();
136
137             cachedMinimumSizeHint = style()->sizeFromContents(QStyle::CT_SpinBox, &opt, hint, this)
138                                     .expandedTo(QApplication::globalStrut());
139         }
140         return cachedMinimumSizeHint;
141     }
142 private:
143     int currentUnit;
144     CAmount singleStep;
145     mutable QSize cachedMinimumSizeHint;
146
147     /**
148      * Parse a string into a number of base monetary units and
149      * return validity.
150      * @note Must return 0 if !valid.
151      */
152     CAmount parse(const QString &text, bool *valid_out=0) const
153     {
154         CAmount val = 0;
155         bool valid = BitcoinUnits::parse(currentUnit, text, &val);
156         if(valid)
157         {
158             if(val < 0 || val > BitcoinUnits::maxMoney())
159                 valid = false;
160         }
161         if(valid_out)
162             *valid_out = valid;
163         return valid ? val : 0;
164     }
165
166 protected:
167     bool event(QEvent *event)
168     {
169         if (event->type() == QEvent::KeyPress || event->type() == QEvent::KeyRelease)
170         {
171             QKeyEvent *keyEvent = static_cast<QKeyEvent *>(event);
172             if (keyEvent->key() == Qt::Key_Comma)
173             {
174                 // Translate a comma into a period
175                 QKeyEvent periodKeyEvent(event->type(), Qt::Key_Period, keyEvent->modifiers(), ".", keyEvent->isAutoRepeat(), keyEvent->count());
176                 return QAbstractSpinBox::event(&periodKeyEvent);
177             }
178         }
179         return QAbstractSpinBox::event(event);
180     }
181
182 signals:
183     void valueChanged();
184 };
185
186 #include "bitcoinamountfield.moc"
187
188 BitcoinAmountField::BitcoinAmountField(QWidget *parent) :
189     QWidget(parent),
190     amount(0)
191 {
192     amount = new AmountSpinBox(this);
193     amount->setLocale(QLocale::c());
194     amount->installEventFilter(this);
195     amount->setMaximumWidth(170);
196
197     QHBoxLayout *layout = new QHBoxLayout(this);
198     layout->addWidget(amount);
199     unit = new QValueComboBox(this);
200     unit->setModel(new BitcoinUnits(this));
201     layout->addWidget(unit);
202     layout->addStretch(1);
203     layout->setContentsMargins(0,0,0,0);
204
205     setLayout(layout);
206
207     setFocusPolicy(Qt::TabFocus);
208     setFocusProxy(amount);
209
210     // If one if the widgets changes, the combined content changes as well
211     connect(amount, SIGNAL(valueChanged()), this, SIGNAL(valueChanged()));
212     connect(unit, SIGNAL(currentIndexChanged(int)), this, SLOT(unitChanged(int)));
213
214     // Set default based on configuration
215     unitChanged(unit->currentIndex());
216 }
217
218 void BitcoinAmountField::clear()
219 {
220     amount->clear();
221     unit->setCurrentIndex(0);
222 }
223
224 void BitcoinAmountField::setEnabled(bool fEnabled)
225 {
226     amount->setEnabled(fEnabled);
227     unit->setEnabled(fEnabled);
228 }
229
230 bool BitcoinAmountField::validate()
231 {
232     bool valid = false;
233     value(&valid);
234     setValid(valid);
235     return valid;
236 }
237
238 void BitcoinAmountField::setValid(bool valid)
239 {
240     if (valid)
241         amount->setStyleSheet("");
242     else
243         amount->setStyleSheet(STYLE_INVALID);
244 }
245
246 bool BitcoinAmountField::eventFilter(QObject *object, QEvent *event)
247 {
248     if (event->type() == QEvent::FocusIn)
249     {
250         // Clear invalid flag on focus
251         setValid(true);
252     }
253     return QWidget::eventFilter(object, event);
254 }
255
256 QWidget *BitcoinAmountField::setupTabChain(QWidget *prev)
257 {
258     QWidget::setTabOrder(prev, amount);
259     QWidget::setTabOrder(amount, unit);
260     return unit;
261 }
262
263 CAmount BitcoinAmountField::value(bool *valid_out) const
264 {
265     return amount->value(valid_out);
266 }
267
268 void BitcoinAmountField::setValue(const CAmount& value)
269 {
270     amount->setValue(value);
271 }
272
273 void BitcoinAmountField::setReadOnly(bool fReadOnly)
274 {
275     amount->setReadOnly(fReadOnly);
276     unit->setEnabled(!fReadOnly);
277 }
278
279 void BitcoinAmountField::unitChanged(int idx)
280 {
281     // Use description tooltip for current unit for the combobox
282     unit->setToolTip(unit->itemData(idx, Qt::ToolTipRole).toString());
283
284     // Determine new unit ID
285     int newUnit = unit->itemData(idx, BitcoinUnits::UnitRole).toInt();
286
287     amount->setDisplayUnit(newUnit);
288 }
289
290 void BitcoinAmountField::setDisplayUnit(int newUnit)
291 {
292     unit->setValue(newUnit);
293 }
294
295 void BitcoinAmountField::setSingleStep(const CAmount& step)
296 {
297     amount->setSingleStep(step);
298 }
This page took 0.039167 seconds and 4 git commands to generate.