tkivy: add context menus - electrum - Electrum Bitcoin wallet HTML git clone https://git.parazyd.org/electrum DIR Log DIR Files DIR Refs DIR Submodules --- DIR commit 6bd37723d3ddf89e9e34236ee07324c02ef1df14 DIR parent 06eb3142c44cdefb5baccb72ffd20b8a0235e2aa HTML Author: ThomasV <thomasv@electrum.org> Date: Sat, 12 Dec 2015 16:54:32 +0100 kivy: add context menus Diffstat: M gui/kivy/main.kv | 36 ++++++++++++++++++++++++------- M gui/kivy/main_window.py | 17 ++--------------- A gui/kivy/uix/context_menu.py | 43 ++++++++++++++++++++++++++++++ M gui/kivy/uix/dialogs/__init__.py | 1 + M gui/kivy/uix/screens.py | 49 ++++++++++++++++++++++++++----- M gui/kivy/uix/ui_screens/history.kv | 34 +++---------------------------- M gui/kivy/uix/ui_screens/invoices.kv | 15 +++------------ M gui/kivy/uix/ui_screens/requests.kv | 22 +++++++--------------- 8 files changed, 129 insertions(+), 88 deletions(-) --- DIR diff --git a/gui/kivy/main.kv b/gui/kivy/main.kv t@@ -187,6 +187,34 @@ size: self.size pos: self.pos +<xxCardItem@ToggleButtonBehavior+GridLayout> + canvas.before: + Color: + rgba: 0.192, .498, 0.745, 1 if self.state == 'down' else 0 + Rectangle + size: self.size + pos: self.x, self.y + dp(5) + padding: '2dp', '2dp' + spacing: '2dp' + height: self.minimum_height + + +<CardItem@ToggleButtonBehavior+BoxLayout> + size_hint: 1, None + height: '65dp' + group: 'requests' + padding: dp(12) + spacing: dp(5) + screen: None + on_release: + self.screen.show_menu(args[0]) if self.state == 'down' else self.screen.hide_menu() + canvas.before: + Color: + rgba: (0.192, .498, 0.745, 1) if self.state == 'down' else (0.3, 0.3, 0.3, 1) + Rectangle: + size: self.size + pos: self.pos + <AddressSelector@BlueSpinner> icon: 'atlas://gui/kivy/theming/light/globe' values: [] #app.wallet.addresses() if app.wallet else [] t@@ -388,14 +416,6 @@ BoxLayout: font_size: '22dp' minimum_width: '1dp' - ActionButton: - id: context_button - text: app.context - width: 0 - on_text: - self.width = 20 if self.text else 0 - on_release: app.context_action() - ActionOverflow: id: ao ActionOvrButton: DIR diff --git a/gui/kivy/main_window.py b/gui/kivy/main_window.py t@@ -78,8 +78,6 @@ class ElectrumWindow(App): keys = sorted(base_units.keys()) self.base_unit = keys[ (keys.index(self.base_unit) + 1) % len(keys)] - context = StringProperty('') - context_action = lambda x: None status = StringProperty('') fiat_unit = StringProperty('') t@@ -749,22 +747,11 @@ class ElectrumWindow(App): pos = (win.center[0], win.center[1] - (info_bubble.height/2)) info_bubble.show(pos, duration, width, modal=modal, exit=exit) - def tx_dialog(self, tx_hash): + def tx_dialog(self, obj): popup = Builder.load_file('gui/kivy/uix/ui_screens/transaction.kv') - popup.tx_hash = tx_hash + popup.tx_hash = obj.tx_hash popup.open() - def tx_selected(self, txid, state): - if state == 'down': - self.context = 'tx' - self.context_action = lambda: self.tx_dialog(txid) - else: - self.reset_context() - - def reset_context(self): - self.context = '' - self.context_action = lambda: None - def amount_dialog(self, screen, show_max): popup = Builder.load_file('gui/kivy/uix/ui_screens/amount.kv') but_max = popup.ids.but_max DIR diff --git a/gui/kivy/uix/context_menu.py b/gui/kivy/uix/context_menu.py t@@ -0,0 +1,43 @@ +#!python +#!/usr/bin/env python +from kivy.app import App +from kivy.uix.bubble import Bubble +from kivy.animation import Animation +from kivy.uix.floatlayout import FloatLayout +from kivy.lang import Builder +from kivy.factory import Factory + +Builder.load_string(''' +<MenuItem@Button> + background_color: .2, .9, 1, 1 + height: '40dp' + size_hint: 1, None + +<ContextMenu> + size_hint: 1, None + height: '32dp' + #size: 120, 250 + pos: (0, 0) + show_arrow: False + padding: 0 + orientation: 'horizontal' + BoxLayout: + size_hint: 1, 1 + height: '40dp' + orientation: 'horizontal' + id: buttons +''') + + +class MenuItem(Factory.Button): + pass + +class ContextMenu(Bubble): + def __init__(self, obj, action_list): + Bubble.__init__(self) + self.obj = obj + for k, v in action_list: + l = MenuItem() + l.text = k + l.on_release = lambda: v(obj) + self.ids.buttons.add_widget(l) DIR diff --git a/gui/kivy/uix/dialogs/__init__.py b/gui/kivy/uix/dialogs/__init__.py t@@ -144,6 +144,7 @@ class InfoBubble(Factory.Bubble): m.add_widget(self) else: Window.add_widget(self) + # wait for the bubble to adjust it's size according to text then animate Clock.schedule_once(lambda dt: self._show(pos, duration)) DIR diff --git a/gui/kivy/uix/screens.py b/gui/kivy/uix/screens.py t@@ -22,12 +22,17 @@ from electrum import bitcoin from electrum.util import timestamp_to_datetime from electrum.plugins import run_hook +from context_menu import ContextMenu + + class CScreen(Factory.Screen): __events__ = ('on_activate', 'on_deactivate', 'on_enter', 'on_leave') action_view = ObjectProperty(None) loaded = False kvname = None + context_menu = None + menu_actions = [] app = App.get_running_app() def _change_action_view(self): t@@ -65,8 +70,19 @@ class CScreen(Factory.Screen): self.dispatch('on_deactivate') def on_deactivate(self): - pass - #Clock.schedule_once(lambda dt: self._change_action_view()) + self.hide_menu() + + def hide_menu(self): + if self.context_menu: + self.screen.remove_widget(self.context_menu) + self.context_menu = None + + def show_menu(self, obj): + if self.context_menu is None: + self.context_menu = ContextMenu(obj, self.menu_actions) + self.screen.remove_widget(self.context_menu) + self.screen.add_widget(self.context_menu) + class HistoryScreen(CScreen): t@@ -77,6 +93,7 @@ class HistoryScreen(CScreen): def __init__(self, **kwargs): self.ra_dialog = None super(HistoryScreen, self).__init__(**kwargs) + self.menu_actions = [(_('Details'), self.app.tx_dialog)] def get_history_rate(self, btc_balance, timestamp): date = timestamp_to_datetime(timestamp) t@@ -120,14 +137,12 @@ class HistoryScreen(CScreen): if self.app.wallet is None: return - history_card = self.screen.ids.recent_activity_card + history_card = self.screen.ids.history_container history = self.parse_history(reversed( self.app.wallet.get_history(self.app.current_account))) # repopulate History Card - last_widget = history_card.ids.content.children[-1] - history_card.ids.content.clear_widgets() - history_add = history_card.ids.content.add_widget - history_add(last_widget) + history_card.clear_widgets() + history_add = history_card.add_widget RecentActivityItem = Factory.RecentActivityItem count = 0 for item in history: t@@ -141,6 +156,7 @@ class HistoryScreen(CScreen): ri.quote_text = quote_text ri.confirmations = conf ri.tx_hash = tx + ri.screen = self history_add(ri) if count == 8 and not see_all: break t@@ -345,6 +361,7 @@ class InvoicesScreen(CScreen): kvname = 'invoices' def update(self): + self.menu_actions = [(_('Pay'), self.do_pay), (_('Delete'), self.do_delete)] invoices_list = self.screen.ids.invoices_container invoices_list.clear_widgets() for pr in self.app.invoices.sorted_list(): t@@ -356,12 +373,22 @@ class InvoicesScreen(CScreen): #ci.status = self.invoices.get_status(key) exp = pr.get_expiration_date() ci.date = format_time(exp) if exp else _('Never') + ci.screen = self invoices_list.add_widget(ci) + def do_pay(self, x): + pass + + def do_delete(self, x): + pass + class RequestsScreen(CScreen): kvname = 'requests' def update(self): + + self.menu_actions = [(_('View'), self.do_view), (_('Delete'), self.do_delete)] + requests_list = self.screen.ids.requests_container requests_list.clear_widgets() for req in self.app.wallet.get_sorted_requests(self.app.electrum_config): t@@ -378,9 +405,17 @@ class RequestsScreen(CScreen): #ci.status = req.get('status') ci.amount = self.app.format_amount(amount) if amount else '' ci.date = format_time(timestamp) + ci.screen = self requests_list.add_widget(ci) + def do_view(self, o): + print o + + def do_delete(self, o): + print o + + class CSpinner(Factory.Spinner): '''CustomDropDown that allows fading out the dropdown DIR diff --git a/gui/kivy/uix/ui_screens/history.kv b/gui/kivy/uix/ui_screens/history.kv t@@ -38,20 +38,6 @@ size: self.texture_size[0] + dp(32), self.texture_size[1] + dp(7) -<CardItem@ToggleButtonBehavior+GridLayout> - canvas.before: - Color: - rgba: 0.192, .498, 0.745, 1 if self.state == 'down' else 0 - Rectangle - size: self.size - pos: self.x, self.y + dp(5) - cols: 1 - padding: '2dp', '2dp' - spacing: '2dp' - size_hint: 1, None - height: self.minimum_height - group: 'history' - <RecentActivityItem@CardItem> icon: 'atlas://gui/kivy/theming/light/important' address: 'no address set' t@@ -62,8 +48,7 @@ date: '0/0/0' quote_text: '.' spacing: '9dp' - on_release: - app.tx_selected(root.tx_hash, self.state) + cols: 1 BoxLayout: size_hint: 1, None spacing: '8dp' t@@ -100,16 +85,6 @@ u'[/color]'.format(amount_color=root.amount_color,\ amount=root.amount[1:], qt=root.quote_text, sign=root.amount[0],\ unit=app.base_unit) - CardSeparator - -<CardRecentActivity@Card> - GridLayout: - id: content - spacing: '7dp' - cols: 1 - size_hint: 1, None - height: self.minimum_height - CardSeparator HistoryScreen: t@@ -119,12 +94,9 @@ HistoryScreen: id: content do_scroll_x: False GridLayout - id: grid - cols: 1 #if root.width < root.height else 2 + id: history_container + cols: 1 size_hint: 1, None height: self.minimum_height padding: '12dp' spacing: '12dp' - CardRecentActivity: - id: recent_activity_card - DIR diff --git a/gui/kivy/uix/ui_screens/invoices.kv b/gui/kivy/uix/ui_screens/invoices.kv t@@ -4,22 +4,12 @@ halign: 'left' valign: 'middle' -<InvoiceItem@BoxLayout> +<InvoiceItem@CardItem> requestor: '' memo: '' amount: '' status: '' date: '' - size_hint_y: None - height: '65dp' - padding: dp(12) - spacing: dp(5) - canvas.before: - Color: - rgba: 0.3, 0.3, 0.3, 1 - Rectangle: - size: self.size - pos: self.pos InvoicesLabel: text: root.requestor InvoicesLabel: t@@ -45,6 +35,7 @@ InvoicesScreen: GridLayout: cols: 1 id: invoices_container - size_hint_y: None + size_hint: 1, None height: self.minimum_height spacing: '1dp' + padding: '12dp' DIR diff --git a/gui/kivy/uix/ui_screens/requests.kv b/gui/kivy/uix/ui_screens/requests.kv t@@ -1,35 +1,26 @@ -<InvoicesLabel@Label> +<RequestLabel@Label> #color: .305, .309, .309, 1 text_size: self.size halign: 'left' valign: 'middle' -<RequestItem@BoxLayout> +<RequestItem@CardItem> address: '' memo: '' amount: '' status: '' date: '' - size_hint_y: None - height: '65dp' - padding: dp(12) - spacing: dp(5) - canvas.before: - Color: - rgba: 0.3, 0.3, 0.3, 1 - Rectangle: - size: self.size - pos: self.pos - InvoicesLabel: + RequestLabel: text: root.address font_size: '13dp' - InvoicesLabel: + RequestLabel: text: root.memo - InvoicesLabel: + RequestLabel: text: root.amount #InvoicesLabel: # text: root.status + RequestsScreen: name: 'requests' on_activate: t@@ -51,3 +42,4 @@ RequestsScreen: size_hint_y: None height: self.minimum_height spacing: '1dp' + padding: '12dp'