Update all instances of BTC currency references to PLM across multiple files including UI components, utility functions, and command descriptions to reflect the new currency denomination
178 lines
6.4 KiB
Python
178 lines
6.4 KiB
Python
# -*- coding: utf-8 -*-
|
|
|
|
from decimal import Decimal
|
|
from typing import Union
|
|
|
|
from PyQt6.QtCore import pyqtSignal, Qt, QSize
|
|
from PyQt6.QtGui import QPainter
|
|
from PyQt6.QtWidgets import (QLineEdit, QStyle, QStyleOptionFrame, QSizePolicy)
|
|
|
|
from .util import char_width_in_lineedit, ColorScheme
|
|
|
|
from electrum.util import (format_satoshis_plain, decimal_point_to_base_unit_name,
|
|
FEERATE_PRECISION, quantize_feerate, DECIMAL_POINT, UI_UNIT_NAME_FEERATE_SAT_PER_VBYTE)
|
|
from electrum.bitcoin import COIN, TOTAL_COIN_SUPPLY_LIMIT_IN_BTC
|
|
|
|
_NOT_GIVEN = object() # sentinel value
|
|
|
|
|
|
class FreezableLineEdit(QLineEdit):
|
|
frozen = pyqtSignal()
|
|
|
|
def setFrozen(self, b):
|
|
self.setReadOnly(b)
|
|
self.setStyleSheet(ColorScheme.LIGHTBLUE.as_stylesheet(True) if b else '')
|
|
self.frozen.emit()
|
|
|
|
def isFrozen(self):
|
|
return self.isReadOnly()
|
|
|
|
|
|
class SizedFreezableLineEdit(FreezableLineEdit):
|
|
|
|
def __init__(self, *, width: int, parent=None):
|
|
super().__init__(parent)
|
|
self._width = width
|
|
self.setSizePolicy(QSizePolicy.Policy.Preferred, QSizePolicy.Policy.Fixed)
|
|
self.setMaximumWidth(width)
|
|
|
|
def sizeHint(self) -> QSize:
|
|
sh = super().sizeHint()
|
|
return QSize(self._width, sh.height())
|
|
|
|
|
|
class AmountEdit(SizedFreezableLineEdit):
|
|
shortcut = pyqtSignal()
|
|
|
|
def __init__(self, base_unit, is_int=False, parent=None, *, max_amount=None):
|
|
# This seems sufficient for hundred-PLM amounts with 8 decimals
|
|
width = 16 * char_width_in_lineedit()
|
|
super().__init__(width=width, parent=parent)
|
|
self.base_unit = base_unit
|
|
self.textChanged.connect(self.numbify)
|
|
self.is_int = is_int
|
|
self.is_shortcut = False
|
|
self.extra_precision = 0
|
|
self.max_amount = max_amount
|
|
|
|
def decimal_point(self):
|
|
return 8
|
|
|
|
def max_precision(self):
|
|
return self.decimal_point() + self.extra_precision
|
|
|
|
def numbify(self):
|
|
text = self.text().strip()
|
|
if text == '!':
|
|
self.shortcut.emit()
|
|
return
|
|
pos = self.cursorPosition()
|
|
chars = '0123456789'
|
|
if not self.is_int: chars += DECIMAL_POINT
|
|
s = ''.join([i for i in text if i in chars])
|
|
if not self.is_int:
|
|
if DECIMAL_POINT in s:
|
|
p = s.find(DECIMAL_POINT)
|
|
s = s.replace(DECIMAL_POINT, '')
|
|
s = s[:p] + DECIMAL_POINT + s[p:p+self.max_precision()]
|
|
if self.max_amount:
|
|
if (amt := self._get_amount_from_text(s)) and amt >= self.max_amount:
|
|
s = self._get_text_from_amount(self.max_amount)
|
|
self.setText(s)
|
|
# setText sets Modified to False. Instead we want to remember
|
|
# if updates were because of user modification.
|
|
self.setModified(self.hasFocus())
|
|
self.setCursorPosition(pos)
|
|
|
|
def paintEvent(self, event):
|
|
QLineEdit.paintEvent(self, event)
|
|
if self.base_unit:
|
|
panel = QStyleOptionFrame()
|
|
self.initStyleOption(panel)
|
|
textRect = self.style().subElementRect(QStyle.SubElement.SE_LineEditContents, panel, self)
|
|
textRect.adjust(2, 0, -10, 0)
|
|
painter = QPainter(self)
|
|
painter.setPen(ColorScheme.GRAY.as_color())
|
|
painter.drawText(textRect, int(Qt.AlignmentFlag.AlignRight | Qt.AlignmentFlag.AlignVCenter), self.base_unit())
|
|
|
|
def _get_amount_from_text(self, text: str) -> Union[None, Decimal, int]:
|
|
try:
|
|
text = text.replace(DECIMAL_POINT, '.')
|
|
return (int if self.is_int else Decimal)(text)
|
|
except Exception:
|
|
return None
|
|
|
|
def get_amount(self) -> Union[None, Decimal, int]:
|
|
amt = self._get_amount_from_text(str(self.text()))
|
|
if self.max_amount and amt and amt >= self.max_amount:
|
|
return self.max_amount
|
|
return amt
|
|
|
|
def _get_text_from_amount(self, amount) -> str:
|
|
return "%d" % amount
|
|
|
|
def setAmount(self, amount):
|
|
text = self._get_text_from_amount(amount)
|
|
self.setText(text)
|
|
|
|
|
|
class BTCAmountEdit(AmountEdit):
|
|
|
|
def __init__(self, decimal_point, is_int=False, parent=None, *, max_amount=_NOT_GIVEN):
|
|
if max_amount is _NOT_GIVEN:
|
|
max_amount = TOTAL_COIN_SUPPLY_LIMIT_IN_BTC * COIN
|
|
AmountEdit.__init__(self, self._base_unit, is_int, parent, max_amount=max_amount)
|
|
self.decimal_point = decimal_point
|
|
|
|
def _base_unit(self):
|
|
return decimal_point_to_base_unit_name(self.decimal_point())
|
|
|
|
def _get_amount_from_text(self, text):
|
|
# returns amt in satoshis
|
|
try:
|
|
text = text.replace(DECIMAL_POINT, '.')
|
|
x = Decimal(text)
|
|
except Exception:
|
|
return None
|
|
# scale it to max allowed precision, make it an int
|
|
power = pow(10, self.max_precision())
|
|
max_prec_amount = int(power * x)
|
|
# if the max precision is simply what unit conversion allows, just return
|
|
if self.max_precision() == self.decimal_point():
|
|
return max_prec_amount
|
|
# otherwise, scale it back to the expected unit
|
|
amount = Decimal(max_prec_amount) / pow(10, self.max_precision()-self.decimal_point())
|
|
return Decimal(amount) if not self.is_int else int(amount)
|
|
|
|
def _get_text_from_amount(self, amount_sat):
|
|
text = format_satoshis_plain(amount_sat, decimal_point=self.decimal_point())
|
|
text = text.replace('.', DECIMAL_POINT)
|
|
return text
|
|
|
|
def setAmount(self, amount_sat):
|
|
if amount_sat is None:
|
|
self.setText(" ") # Space forces repaint in case units changed
|
|
else:
|
|
text = self._get_text_from_amount(amount_sat)
|
|
self.setText(text)
|
|
self.setFrozen(self.isFrozen()) # re-apply styling, as it is nuked by setText (?)
|
|
self.repaint() # macOS hack for #6269
|
|
|
|
|
|
class FeerateEdit(BTCAmountEdit):
|
|
|
|
def __init__(self, decimal_point, is_int=False, parent=None, *, max_amount=_NOT_GIVEN):
|
|
super().__init__(decimal_point, is_int, parent, max_amount=max_amount)
|
|
self.extra_precision = FEERATE_PRECISION
|
|
|
|
def _base_unit(self):
|
|
return UI_UNIT_NAME_FEERATE_SAT_PER_VBYTE
|
|
|
|
def _get_amount_from_text(self, text):
|
|
sat_per_byte_amount = super()._get_amount_from_text(text)
|
|
return quantize_feerate(sat_per_byte_amount)
|
|
|
|
def _get_text_from_amount(self, amount):
|
|
amount = quantize_feerate(amount)
|
|
return super()._get_text_from_amount(amount)
|