Bitcoin Core 32.99.0
P2P Digital Currency
Loading...
Searching...
No Matches
bitcoinamountfield.cpp
Go to the documentation of this file.
1// Copyright (c) 2011-present The Bitcoin Core developers
2// Distributed under the MIT software license, see the accompanying
3// file COPYING or http://www.opensource.org/licenses/mit-license.php.
4
6
7#include <qt/bitcoinunits.h>
8#include <qt/guiconstants.h>
9#include <qt/guiutil.h>
10#include <qt/qvaluecombobox.h>
11
12#include <QApplication>
13#include <QAbstractSpinBox>
14#include <QHBoxLayout>
15#include <QKeyEvent>
16#include <QLineEdit>
17#include <QVariant>
18
19#include <cassert>
20
24class AmountSpinBox: public QAbstractSpinBox
25{
27
28public:
29 explicit AmountSpinBox(QWidget *parent):
30 QAbstractSpinBox(parent)
31 {
32 setAlignment(Qt::AlignRight);
33
34 connect(lineEdit(), &QLineEdit::textEdited, this, &AmountSpinBox::valueChanged);
35 }
36
37 QValidator::State validate(QString &text, int &pos) const override
38 {
39 if(text.isEmpty())
40 return QValidator::Intermediate;
41 bool valid = false;
42 parse(text, &valid);
43 /* Make sure we return Intermediate so that fixup() is called on defocus */
44 return valid ? QValidator::Intermediate : QValidator::Invalid;
45 }
46
47 void fixup(QString &input) const override
48 {
49 bool valid;
50 CAmount val;
51
52 if (input.isEmpty() && !m_allow_empty) {
53 valid = true;
54 val = m_min_amount;
55 } else {
56 valid = false;
57 val = parse(input, &valid);
58 }
59
60 if (valid) {
61 val = qBound(m_min_amount, val, m_max_amount);
63 lineEdit()->setText(input);
64 }
65 }
66
67 CAmount value(bool *valid_out=nullptr) const
68 {
69 return parse(text(), valid_out);
70 }
71
77
79 {
81 }
82
84 {
86 }
87
88 void stepBy(int steps) override
89 {
90 bool valid = false;
91 CAmount val = value(&valid);
92 val = val + steps * singleStep;
93 val = qBound(m_min_amount, val, m_max_amount);
94 setValue(val);
95 }
96
98 {
99 bool valid = false;
100 CAmount val = value(&valid);
101
102 currentUnit = unit;
104 if(valid)
105 setValue(val);
106 else
107 clear();
108 }
109
111 {
113 }
114
115 QSize minimumSizeHint() const override
116 {
117 if(cachedMinimumSizeHint.isEmpty())
118 {
120
121 const QFontMetrics fm(fontMetrics());
122 int h = lineEdit()->minimumSizeHint().height();
124 w += 2; // cursor blinking space
125
128 QSize hint(w, h);
129 QSize extra(35, 6);
130 opt.rect.setSize(hint + extra);
131 extra += hint - style()->subControlRect(QStyle::CC_SpinBox, &opt,
132 QStyle::SC_SpinBoxEditField, this).size();
133 // get closer to final result by repeating the calculation
134 opt.rect.setSize(hint + extra);
135 extra += hint - style()->subControlRect(QStyle::CC_SpinBox, &opt,
136 QStyle::SC_SpinBoxEditField, this).size();
137 hint += extra;
138 hint.setHeight(h);
139
140 opt.rect = rect();
141
142 cachedMinimumSizeHint = style()->sizeFromContents(QStyle::CT_SpinBox, &opt, hint, this);
143 }
145 }
146
147private:
148 BitcoinUnit currentUnit{BitcoinUnit::BTC};
149 CAmount singleStep{CAmount(100000)}; // satoshis
151 bool m_allow_empty{true};
154
160 CAmount parse(const QString &text, bool *valid_out=nullptr) const
161 {
162 CAmount val = 0;
163 bool valid = BitcoinUnits::parse(currentUnit, text, &val);
164 if(valid)
165 {
167 valid = false;
168 }
169 if(valid_out)
170 *valid_out = valid;
171 return valid ? val : 0;
172 }
173
174protected:
175 bool event(QEvent *event) override
176 {
177 if (event->type() == QEvent::KeyPress || event->type() == QEvent::KeyRelease)
178 {
179 QKeyEvent *keyEvent = static_cast<QKeyEvent *>(event);
180 if (keyEvent->key() == Qt::Key_Comma)
181 {
182 // Translate a comma into a period
183 QKeyEvent periodKeyEvent(event->type(), Qt::Key_Period, keyEvent->modifiers(), ".", keyEvent->isAutoRepeat(), keyEvent->count());
184 return QAbstractSpinBox::event(&periodKeyEvent);
185 }
186 }
187 return QAbstractSpinBox::event(event);
188 }
189
190 StepEnabled stepEnabled() const override
191 {
192 if (isReadOnly()) // Disable steps when AmountSpinBox is read-only
193 return StepNone;
194 if (text().isEmpty()) // Allow step-up with empty field
195 return StepUpEnabled;
196
198 bool valid = false;
199 CAmount val = value(&valid);
200 if (valid) {
201 if (val > m_min_amount)
203 if (val < m_max_amount)
204 rv |= StepUpEnabled;
205 }
206 return rv;
207 }
208
211};
212
213#include <qt/bitcoinamountfield.moc>
214
216 : QWidget(parent)
217{
218 amount = new AmountSpinBox(this);
219 amount->setLocale(QLocale::c());
220 amount->installEventFilter(this);
221 amount->setMaximumWidth(240);
222
223 QHBoxLayout *layout = new QHBoxLayout(this);
224 layout->addWidget(amount);
225 unit = new QValueComboBox(this);
226 unit->setModel(new BitcoinUnits(this));
227 layout->addWidget(unit);
228 layout->addStretch(1);
229 layout->setContentsMargins(0,0,0,0);
230
232
233 setFocusPolicy(Qt::TabFocus);
235
236 // If one if the widgets changes, the combined content changes as well
238 connect(unit, qOverload<int>(&QComboBox::currentIndexChanged), this, &BitcoinAmountField::unitChanged);
239
240 // Set default based on configuration
241 unitChanged(unit->currentIndex());
242}
243
245{
246 amount->clear();
247 unit->setCurrentIndex(0);
248}
249
251{
252 amount->setEnabled(fEnabled);
253 unit->setEnabled(fEnabled);
254}
255
257{
258 bool valid = false;
259 value(&valid);
260 setValid(valid);
261 return valid;
262}
263
265{
266 if (valid)
267 amount->setStyleSheet("");
268 else
269 amount->setStyleSheet(STYLE_INVALID);
270}
271
272bool BitcoinAmountField::eventFilter(QObject *object, QEvent *event)
273{
274 if (event->type() == QEvent::FocusIn)
275 {
276 // Clear invalid flag on focus
277 setValid(true);
278 }
279 return QWidget::eventFilter(object, event);
280}
281
283{
284 QWidget::setTabOrder(prev, amount);
285 QWidget::setTabOrder(amount, unit);
286 return unit;
287}
288
293
295{
297}
298
303
308
310{
311 // Use description tooltip for current unit for the combobox
312 unit->setToolTip(unit->itemData(idx, Qt::ToolTipRole).toString());
313
314 // Determine new unit ID
316 assert(new_unit.isValid());
318}
319
324
int64_t CAmount
Amount in satoshis (Can be negative)
Definition amount.h:12
QSpinBox that uses fixed-point numbers internally and uses our own formatting/parsing functions.
void SetMinValue(const CAmount &value)
bool event(QEvent *event) override
void setSingleStep(const CAmount &step)
AmountSpinBox(QWidget *parent)
QValidator::State validate(QString &text, int &pos) const override
CAmount value(bool *valid_out=nullptr) const
StepEnabled stepEnabled() const override
void fixup(QString &input) const override
CAmount parse(const QString &text, bool *valid_out=nullptr) const
Parse a string into a number of base monetary units and return validity.
void valueChanged()
void stepBy(int steps) override
void setDisplayUnit(BitcoinUnit unit)
QSize minimumSizeHint() const override
void setValue(const CAmount &value)
void SetAllowEmpty(bool allow)
AmountSpinBox * amount
void setEnabled(bool fEnabled)
Enable/Disable.
QValueComboBox * unit
void setDisplayUnit(BitcoinUnit new_unit)
Change unit used to display amount.
void setSingleStep(const CAmount &step)
Set single step in satoshis.
void SetMinValue(const CAmount &value)
Set the minimum value in satoshis.
bool eventFilter(QObject *object, QEvent *event) override
Intercept focus-in event and ',' key presses.
BitcoinAmountField(QWidget *parent=nullptr)
void clear()
Make field empty and ready for new input.
bool validate()
Perform input validation, mark field as invalid if entered value is not valid.
QWidget * setupTabChain(QWidget *prev)
Qt messes up the tab chain by default in some cases (issue https://bugreports.qt-project....
void setValid(bool valid)
Mark current value as invalid in UI.
void setValue(const CAmount &value)
void SetAllowEmpty(bool allow)
If allow empty is set to false the field will be set to the minimum allowed value if left empty.
Bitcoin unit definitions.
@ UnitRole
Unit identifier.
static CAmount maxMoney()
Return maximum number of base units (Satoshis)
static QString format(Unit unit, const CAmount &amount, bool plussign=false, SeparatorStyle separators=SeparatorStyle::STANDARD, bool justify=false)
Format as string.
static bool parse(Unit unit, const QString &value, CAmount *val_out)
Parse string to coin amount.
Unit
Bitcoin units.
void setValue(const QVariant &value)
#define STYLE_INVALID
int TextWidth(const QFontMetrics &fm, const QString &text)
Returns the distance in pixels appropriate for drawing a subsequent character after text.
Definition guiutil.cpp:911
ss clear()
constexpr auto Ticks(Dur2 d)
Helper to count the seconds of a duration/time_point.
Definition time.h:82
assert(!tx.IsCoinBase())