electrum

Electrum Bitcoin wallet
git clone https://git.parazyd.org/electrum
Log | Files | Refs | Submodules

commit 608d4cad744da11f80ccae10be968713b2b0f0f1
parent 4e54081c5c99967ce8172cd33d47aa8d69cea7cb
Author: Maran <maran.hidskes@gmail.com>
Date:   Thu,  2 Aug 2012 18:07:25 +0200

Merge branch 'cobleebuilder'

Diffstat:
MREADME | 5+++++
Ddata/icons/accounts.png | 0
Ddata/icons/expand.png | 0
Ddata/icons/interact.png | 0
Mdata/style.css | 81+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++------------------
Aelectrum.icns | 0
Mlib/gui_lite.py | 187+++++++++++++++++++++++++++++++++----------------------------------------------
Mlib/gui_qt.py | 2+-
Asetup-release.py | 74++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
9 files changed, 220 insertions(+), 129 deletions(-)

diff --git a/README b/README @@ -29,6 +29,11 @@ python mki18n.py pyrcc4 icons.qrc -o lib/icons_rc.py python setup.py sdist --format=zip,gztar +On Mac OS X: + + sudo python setup-release.py py2app + sudo hdiutil create -fs HFS+ -volname "Electrum" -srcfolder dist/Electrum.app dist/electrum-v0.61-macosx.dmg + == BROWSER CONFIGURATION == diff --git a/data/icons/accounts.png b/data/icons/accounts.png Binary files differ. diff --git a/data/icons/expand.png b/data/icons/expand.png Binary files differ. diff --git a/data/icons/interact.png b/data/icons/interact.png Binary files differ. diff --git a/data/style.css b/data/style.css @@ -1,35 +1,80 @@ #main_window { - background-image: url(background.png); + background: qlineargradient(x1: 0, y1: 0, x2:0,y2:1, stop: 0 white , stop: 1 #E8E8E8); } -#address_input[readOnly=true], #amount_input[readOnly=true] -{ - font: italic; - color: gray; +MiniWindow QPushButton { + color: #777; + border: 1px solid #CCC; + border-radius: 0px; + background-color: qlineargradient(x1: 0, y1: 0, x2: 0, y2: 1, + stop: 0 white, stop: 1 #E6E6E6); + min-height: 25px; + min-width: 30px; } -#address_input[readOnly=false], #amount_input[readOnly=false] -{ - font: normal; - color: black; + +#send_button{ + color: #E5F2FF; + border: 1px solid #3786E6; + border-radius: 4px; + background-color: qlineargradient(x1: 0, y1: 0, x2: 0, y2: 1, + stop: 0 #72B2F8, stop: 1 #3484E6); + min-width: 80px; + min-height: 23px; + padding: 2px; +} + +#send_button:disabled{ + color: #D3E8FE; + border: 1px solid #6DAEF7; + border-radius: 4px; + background-color: qlineargradient(x1: 0, y1: 0, x2: 0, y2: 1, + stop: 0 #A5CFFA, stop: 1 #72B2F8); + min-width: 80px; + min-height: 23px; + padding: 2px; } -#valid_address::indicator +#address_input, #amount_input { - width: 24px; - height: 24px; + color: #000; + padding: 5px; + border-radius: 4px; + border: 1px solid #AAA9A9; + width: 225px; + margin-top: 4px; } -#valid_address::indicator:checked + +#address_input[isValid=true] { - image: url(icons/confirmed.png); + color: #4D9948; + padding: 5px; + border-radius: 4px; + border: 1px solid #AAA9A9; + width: 225px; + margin-top: 4px; } -#valid_address::indicator:unchecked + +#address_input[isValid=false] { - image: url(icons/unconfirmed.png); + color: #CE4141; + padding: 5px; + border-radius: 4px; + border: 1px solid #AAA9A9; + width: 225px; + margin-top: 4px; } +#address_input[isValid=placeholder] +{ + color: blue; + padding: 5px; + border-radius: 4px; + border: 1px solid #AAA9A9; + width: 225px; + margin-top: 4px; +} #balance_label { - color: white; + color: #333; } - diff --git a/electrum.icns b/electrum.icns Binary files differ. diff --git a/lib/gui_lite.py b/lib/gui_lite.py @@ -109,34 +109,6 @@ class MiniWindow(QDialog): self.actuator = actuator - accounts_button = IconButton(rsrc("icons", "accounts.png")) - accounts_button.setObjectName("accounts_button") - - self.accounts_selector = QMenu() - accounts_button.setMenu(self.accounts_selector) - - interact_button = IconButton(rsrc("icons", "interact.png")) - interact_button.setObjectName("interact_button") - - app_menu = QMenu(interact_button) - acceptbit_action = app_menu.addAction(_("A&cceptBit")) - report_action = app_menu.addAction(_("&Report Bug")) - about_action = app_menu.addAction(_("&About Electrum")) - app_menu.addSeparator() - quit_action = app_menu.addAction(_("&Quit")) - interact_button.setMenu(app_menu) - - self.connect(acceptbit_action, SIGNAL("triggered()"), - self.acceptbit) - self.connect(report_action, SIGNAL("triggered()"), - self.show_report_bug) - self.connect(about_action, SIGNAL("triggered()"), self.show_about) - self.connect(quit_action, SIGNAL("triggered()"), self.close) - - expand_button = IconButton(rsrc("icons", "expand.png")) - expand_button.setObjectName("expand_button") - self.connect(expand_button, SIGNAL("clicked()"), expand_callback) - self.btc_balance = None self.quote_currencies = ["EUR", "USD", "GBP"] self.actuator.set_configured_currency(self.set_quote_currency) @@ -151,15 +123,16 @@ class MiniWindow(QDialog): self.receive_button = QPushButton(_("&Receive")) self.receive_button.setObjectName("receive_button") self.receive_button.setDefault(True) - self.connect(self.receive_button, SIGNAL("clicked()"), - self.copy_address) + self.connect(self.receive_button, SIGNAL("clicked()"), self.copy_address) - self.address_input = TextedLineEdit(_("Enter a Bitcoin address...")) + # Bitcoin address code + self.address_input = QLineEdit() + self.address_input.setPlaceholderText(_("Enter a Bitcoin address...")) self.address_input.setObjectName("address_input") - self.connect(self.address_input, SIGNAL("textEdited(QString)"), - self.address_field_changed) - resize_line_edit_width(self.address_input, - "1BtaFUr3qVvAmwrsuDuu5zk6e4s2rxd2Gy") + + + self.connect(self.address_input, SIGNAL("textEdited(QString)"), self.address_field_changed) + resize_line_edit_width(self.address_input, "1BtaFUr3qVvAmwrsuDuu5zk6e4s2rxd2Gy") self.address_completions = QStringListModel() address_completer = QCompleter(self.address_input) @@ -167,16 +140,11 @@ class MiniWindow(QDialog): address_completer.setModel(self.address_completions) self.address_input.setCompleter(address_completer) - self.valid_address = QCheckBox() - self.valid_address.setObjectName("valid_address") - self.valid_address.setEnabled(False) - self.valid_address.setChecked(False) - address_layout = QHBoxLayout() address_layout.addWidget(self.address_input) - address_layout.addWidget(self.valid_address) - self.amount_input = TextedLineEdit(_("... and amount")) + self.amount_input = QLineEdit() + self.amount_input.setPlaceholderText(_("... and amount")) self.amount_input.setObjectName("amount_input") # This is changed according to the user's displayed balance self.amount_validator = QDoubleValidator(self.amount_input) @@ -184,29 +152,50 @@ class MiniWindow(QDialog): self.amount_validator.setDecimals(8) self.amount_input.setValidator(self.amount_validator) + # This removes the very ugly OSX highlighting, please leave this in :D + self.address_input.setAttribute(Qt.WA_MacShowFocusRect, 0) + self.amount_input.setAttribute(Qt.WA_MacShowFocusRect, 0) + self.connect(self.amount_input, SIGNAL("textChanged(QString)"), self.amount_input_changed) - amount_layout = QHBoxLayout() - amount_layout.addWidget(self.amount_input) - amount_layout.addStretch() - - send_button = QPushButton(_("&Send")) - send_button.setObjectName("send_button") - self.connect(send_button, SIGNAL("clicked()"), self.send) + self.send_button = QPushButton(_("&Send")) + self.send_button.setObjectName("send_button") + self.send_button.setDisabled(True); + self.connect(self.send_button, SIGNAL("clicked()"), self.send) main_layout = QGridLayout(self) - main_layout.addWidget(accounts_button, 0, 0) - main_layout.addWidget(interact_button, 1, 0) - main_layout.addWidget(expand_button, 2, 0) - main_layout.addWidget(self.balance_label, 0, 1) - main_layout.addWidget(self.receive_button, 0, 2) + main_layout.addWidget(self.balance_label, 0, 0) + main_layout.addWidget(self.receive_button, 0, 1) + + main_layout.addWidget(self.address_input, 1, 0, 1, -1) - main_layout.addLayout(address_layout, 1, 1, 1, -1) + main_layout.addWidget(self.amount_input, 2, 0) + main_layout.addWidget(self.send_button, 2, 1) - main_layout.addLayout(amount_layout, 2, 1) - main_layout.addWidget(send_button, 2, 2) + menubar = QMenuBar() + electrum_menu = menubar.addMenu(_("&Electrum")) + electrum_menu.addMenu(_("&Servers")) + electrum_menu.addSeparator() + electrum_menu.addAction(_("&Quit")) + + view_menu = menubar.addMenu(_("&View")) + expert_gui = view_menu.addAction(_("&Pro Mode")) + self.connect(expert_gui, SIGNAL("triggered()"), expand_callback) + view_menu.addMenu(_("&Themes")) + view_menu.addSeparator() + view_menu.addAction(_("Show History")) + + settings_menu = menubar.addMenu(_("&Settings")) + settings_menu.addAction(_("&Configure Electrum")) + + help_menu = menubar.addMenu(_("&Help")) + help_menu.addAction(_("&Contents")) + help_menu.addSeparator() + help_menu.addAction(_("&Report Bug")) + help_menu.addAction(_("&About")) + main_layout.setMenuBar(menubar) quit_shortcut = QShortcut(QKeySequence("Ctrl+Q"), self) self.connect(quit_shortcut, SIGNAL("activated()"), self.close) @@ -219,16 +208,18 @@ class MiniWindow(QDialog): self.layout().setSizeConstraint(QLayout.SetFixedSize) self.setObjectName("main_window") self.show() + + def recompute_style(self): + qApp.style().unpolish(self) + qApp.style().polish(self) def closeEvent(self, event): super(MiniWindow, self).closeEvent(event) qApp.quit() def set_payment_fields(self, dest_address, amount): - self.address_input.become_active() self.address_input.setText(dest_address) self.address_field_changed(dest_address) - self.amount_input.become_active() self.amount_input.setText(amount) def activate(self): @@ -264,14 +255,11 @@ class MiniWindow(QDialog): quote_text = "(%s)" % quote_text btc_balance = "%.2f" % (btc_balance / bitcoin(1)) self.balance_label.set_balance_text(btc_balance, quote_text) - main_account_info = \ - "Checking - %s BTC" % btc_balance - self.setWindowTitle("Electrum - %s" % main_account_info) - self.accounts_selector.clear() - self.accounts_selector.addAction("%s %s" % (main_account_info, - quote_text)) + self.setWindowTitle("Electrum - %s BTC" % btc_balance) def amount_input_changed(self, amount_text): + self.check_button_status() + try: amount = D(str(amount_text)) except decimal.InvalidOperation: @@ -295,16 +283,33 @@ class MiniWindow(QDialog): return quote_text def send(self): - if self.actuator.send(self.address_input.text(), - self.amount_input.text(), self): - self.address_input.become_inactive() - self.amount_input.become_inactive() + if self.actuator.send(self.address_input.text(), self.amount_input.text(), self): + self.address_input.setText("") + self.amount_input.setText("") + + def check_button_status(self): + if self.address_input.property("isValid") == True and len(self.amount_input.text()) != 0: + self.send_button.setDisabled(False) + else: + self.send_button.setDisabled(True) def address_field_changed(self, address): if self.actuator.is_valid(address): - self.valid_address.setChecked(True) + self.check_button_status() + self.address_input.setProperty("isValid", True) + self.recompute_style(self.address_input) else: - self.valid_address.setChecked(False) + self.send_button.setDisabled(True) + self.address_input.setProperty("isValid", False) + self.recompute_style(self.address_input) + + if len(address) == 0: + self.address_input.setProperty("isValid", None) + self.recompute_style(self.address_input) + + def recompute_style(self, element): + self.style().unpolish(element) + self.style().polish(element) def copy_address(self): receive_popup = ReceivePopup(self.receive_button) @@ -344,7 +349,7 @@ class BalanceLabel(QLabel): def set_balance_text(self, btc_balance, quote_text): if self.state == self.SHOW_CONNECTING: self.state = self.SHOW_BALANCE - self.balance_text = "<span style='font-size: 16pt'>%s</span> <span style='font-size: 10pt'>BTC</span> <span style='font-size: 10pt'>%s</span>" % (btc_balance, quote_text) + self.balance_text = "<span style='font-size: 18pt'>%s</span> <span style='font-size: 10pt'>BTC</span> <span style='font-size: 10pt'>%s</span>" % (btc_balance, quote_text) if self.state == self.SHOW_BALANCE: self.setText(self.balance_text) @@ -363,44 +368,6 @@ class BalanceLabel(QLabel): self.state = self.SHOW_AMOUNT self.setText(self.amount_text) -class TextedLineEdit(QLineEdit): - - def __init__(self, inactive_text, parent=None): - super(QLineEdit, self).__init__(parent) - self.inactive_text = inactive_text - self.become_inactive() - - def mousePressEvent(self, event): - if self.isReadOnly(): - self.become_active() - QLineEdit.mousePressEvent(self, event) - - def focusOutEvent(self, event): - if self.text() == "": - self.become_inactive() - QLineEdit.focusOutEvent(self, event) - - def focusInEvent(self, event): - if self.isReadOnly(): - self.become_active() - QLineEdit.focusInEvent(self, event) - - def become_inactive(self): - self.setReadOnly(True) - self.recompute_style() - self.setText(self.inactive_text) - - def become_active(self): - self.setReadOnly(False) - self.recompute_style() - self.setText("") - - def recompute_style(self): - qApp.style().unpolish(self) - qApp.style().polish(self) - # also possible but more expensive: - #qApp.setStyleSheet(qApp.styleSheet()) - def ok_cancel_buttons(dialog): row_layout = QHBoxLayout() row_layout.addStretch(1) diff --git a/lib/gui_qt.py b/lib/gui_qt.py @@ -153,7 +153,7 @@ class QRCodeWidget(QWidget): def paintEvent(self, e): qp = QtGui.QPainter() qp.begin(self) - boxsize = 7 + boxsize = 6 size = self.qr.getModuleCount()*boxsize k = self.qr.getModuleCount() black = QColor(0, 0, 0, 255) diff --git a/setup-release.py b/setup-release.py @@ -0,0 +1,74 @@ +""" +py2app/py2exe build script for Electrum Litecoin + +Usage (Mac OS X): + python setup.py py2app + +Usage (Windows): + python setup.py py2exe +""" + +import sys, os, shutil, re +from setuptools import setup +from lib.version import ELECTRUM_VERSION as version +from lib.util import print_error + + +name = "Electrum" +mainscript = 'electrum' + +if sys.version_info[:3] < (2,6,0): + print_error("Error: " + name + " requires Python version >= 2.6.0...") + sys.exit(1) + +if sys.platform == 'darwin': + shutil.copy(mainscript, mainscript + '.py') + mainscript += '.py' + extra_options = dict( + setup_requires=['py2app'], + app=[mainscript], + options=dict(py2app=dict(argv_emulation=True, + iconfile='electrum.icns', + resources=["data/background.png", "data/style.css", "data/icons"])), + ) +elif sys.platform == 'win32': + extra_options = dict( + setup_requires=['py2exe'], + app=[mainscript], + ) +else: + extra_options = dict( + # Normally unix-like platforms will use "setup.py install" + # and install the main script as such + scripts=[mainscript], + ) + +setup( + name = name, + version = version, + **extra_options +) + +if sys.platform == 'darwin': + # Remove the copied py file + os.remove(mainscript) + resource = "dist/" + name + ".app/Contents/Resources/" + + # Try to locate qt_menu + # Let's try the port version first! + if os.path.isfile("/opt/local/lib/Resources/qt_menu.nib"): + qt_menu_location = "/opt/local/lib/Resources/qt_menu.nib" + else: + # No dice? Then let's try the brew version + qt_menu_location = os.popen("mdfind -name qt_menu.nib | grep Cellar | head").read() + qt_menu_location = re.sub('\n','', qt_menu_location) + + if(len(qt_menu_location) == 0): + print "Sorry couldn't find your qt_menu.nib this probably won't work" + + # Need to include a copy of qt_menu.nib + shutil.copytree(qt_menu_location, resource + "qt_menu.nib") + # Need to touch qt.conf to avoid loading 2 sets of Qt libraries + fname = resource + "qt.conf" + with file(fname, 'a'): + os.utime(fname, None)