URI: 
       tkivy wizard: use own soft keyboard - electrum - Electrum Bitcoin wallet
  HTML git clone https://git.parazyd.org/electrum
   DIR Log
   DIR Files
   DIR Refs
   DIR Submodules
       ---
   DIR commit 656069070a9ba8c68c066226bdd4c02883f7c7ae
   DIR parent 950f3ae633ae2d774dbbd0f60dd23cd8be06c624
  HTML Author: ThomasV <thomasv@electrum.org>
       Date:   Sat, 13 Feb 2016 15:10:17 +0100
       
       kivy wizard: use own soft keyboard
       
       Diffstat:
         M gui/kivy/main_window.py             |       4 ++--
         M gui/kivy/uix/dialogs/create_restor… |     215 +++++++++++++++++++++++--------
         M lib/mnemonic.py                     |       5 +++++
       
       3 files changed, 168 insertions(+), 56 deletions(-)
       ---
   DIR diff --git a/gui/kivy/main_window.py b/gui/kivy/main_window.py
       t@@ -230,11 +230,11 @@ class ElectrumWindow(App):
        
            def set_URI(self, url):
                try:
       -            url = electrum.util.parse_URI(url, self.on_pr)
       +            d = electrum.util.parse_URI(url, self.on_pr)
                except:
                    self.show_info(_("Not a Bitcoin URI") + ':\n', url)
                    return
       -        self.send_screen.set_URI(url)
       +        self.send_screen.set_URI(d)
        
            def on_qr(self, data):
                if data.startswith('bitcoin:'):
   DIR diff --git a/gui/kivy/uix/dialogs/create_restore.py b/gui/kivy/uix/dialogs/create_restore.py
       t@@ -11,6 +11,7 @@ from kivy.clock import Clock
        from kivy.lang import Builder
        from kivy.properties import ObjectProperty, StringProperty, OptionProperty
        from kivy.core.window import Window
       +from kivy.uix.button import Button
        
        from electrum_gui.kivy.uix.dialogs import EventsDialog
        from electrum_gui.kivy.i18n import _
       t@@ -60,62 +61,49 @@ Builder.load_string('''
            BoxLayout:
                orientation: 'vertical' if self.width < self.height else 'horizontal'
                padding:
       -            min(dp(42), self.width/8), min(dp(60), self.height/9.7),\
       -            min(dp(42), self.width/8), min(dp(72), self.height/8)
       +            min(dp(42), self.width/16), min(dp(60), self.height/16),\
       +            min(dp(42), self.width/16), min(dp(72), self.height/16)
                spacing: '27dp'
                GridLayout:
                    id: grid_logo
                    cols: 1
                    pos_hint: {'center_y': .5}
       -            size_hint: 1, .42
       +            size_hint: 1, None
                    #height: self.minimum_height
       -            Image:
       -                id: logo_img
       -                mipmap: True
       -                allow_stretch: True
       -                size_hint: 1, None
       -                height: '110dp'
       -                source: 'atlas://gui/kivy/theming/light/electrum_icon640'
       -            Widget:
       -                size_hint: 1, None
       -                height: 0 if stepper.opacity else dp(15)
                    Label:
                        color: root.text_color
       -                opacity: 0 if stepper.opacity else 1
                        text: 'ELECTRUM'
                        size_hint: 1, None
                        height: self.texture_size[1] if self.opacity else 0
                        font_size: '33sp'
                        font_name: 'gui/kivy/data/fonts/tron/Tr2n.ttf'
       -            Image:
       -                id: stepper
       -                allow_stretch: True
       -                opacity: 0
       -                source: 'atlas://gui/kivy/theming/light/stepper_left'
       -                size_hint: 1, None
       -                height: grid_logo.height/2.5 if self.opacity else 0
       -        Widget:
       -            size_hint: None, None
       -            size: '5dp', '5dp'
                GridLayout:
                    cols: 1
                    id: crcontent
       -            spacing: '13dp'
       +            spacing: '1dp'
        
        
        <CreateRestoreDialog>
       +    Image:
       +        id: logo_img
       +        mipmap: True
       +        allow_stretch: True
       +        size_hint: 1, None
       +        height: '110dp'
       +        source: 'atlas://gui/kivy/theming/light/electrum_icon640'
       +    Widget:
       +        size_hint: 1, 1
            Label:
                color: root.text_color
                size_hint: 1, None
                text_size: self.width, None
                height: self.texture_size[1]
                text:
       -            _("Wallet file not found!!")+"\\n\\n" +\
       +            _("Wallet file not found")+"\\n\\n" +\
                    _("Do you want to create a new wallet ")+\
                    _("or restore an existing one?")
            Widget
       -        size_hint: 1, None
       -        height: dp(15)
       +        size_hint: 1, 1
            GridLayout:
                id: grid
                orientation: 'vertical'
       t@@ -133,7 +121,23 @@ Builder.load_string('''
                    root: root
        
        
       +<MButton@Button>:
       +    size_hint: 1, None
       +    height: '33dp'
       +    on_release:
       +        self.parent.update_amount(self.text)
       +
       +<WordButton@Button>:
       +    size_hint: None, None
       +    text_size: None, self.height
       +    width: self.texture_size[0]
       +    height: '30dp'
       +    on_release:
       +        self.parent.new_word(self.text)
       +
       +
        <RestoreSeedDialog>
       +    word: ''
            Label:
                color: root.text_color
                size_hint: 1, None
       t@@ -147,13 +151,20 @@ Builder.load_string('''
                spacing: '12dp'
                size_hint: 1, None
                height: self.minimum_height
       -        WizardTextInput:
       +        Button:
       +            border: 4, 4, 4, 4
       +            halign: 'justify'
       +            valign: 'middle'
       +            font_size: self.width/15
       +            text_size: self.width - dp(24), self.height - dp(12)
       +            color: .1, .1, .1, 1
       +            background_normal: 'atlas://gui/kivy/theming/light/white_bg_round_top'
       +            background_down: self.background_normal
                    id: text_input_seed
       -            size_hint: 1, None
       -            height: '110dp'
       -            hint_text:
       -                _('Enter your seedphrase')
       -            on_text: root._trigger_check_seed()
       +            size_hint_y: None
       +            height: dp(100)
       +            text: ''
       +            on_text: Clock.schedule_once(root.on_text)
                Label:
                    font_size: '12sp'
                    text_size: self.width, None
       t@@ -165,6 +176,80 @@ Builder.load_string('''
                    on_ref_press:
                        import webbrowser
                        webbrowser.open('https://electrum.org/faq.html#seed')
       +
       +        BoxLayout:
       +            id: suggestions
       +            height: '35dp'
       +            size_hint: 1, None
       +            new_word: root.on_word
       +
       +        BoxLayout:
       +            update_amount: root.update_text
       +            size_hint: 1, None
       +            height: '30dp'
       +            MButton:
       +                text: 'Q'
       +            MButton:
       +                text: 'W'
       +            MButton:
       +                text: 'E'
       +            MButton:
       +                text: 'R'
       +            MButton:
       +                text: 'T'
       +            MButton:
       +                text: 'Y'
       +            MButton:
       +                text: 'U'
       +            MButton:
       +                text: 'I'
       +            MButton:
       +                text: 'O'
       +            MButton:
       +                text: 'P'
       +        BoxLayout:
       +            update_amount: root.update_text
       +            size_hint: 1, None
       +            height: '30dp'
       +            MButton:
       +                text: 'A'
       +            MButton:
       +                text: 'S'
       +            MButton:
       +                text: 'D'
       +            MButton:
       +                text: 'F'
       +            MButton:
       +                text: 'G'
       +            MButton:
       +                text: 'H'
       +            MButton:
       +                text: 'J'
       +            MButton:
       +                text: 'K'
       +            MButton:
       +                text: 'L'
       +        BoxLayout:
       +            update_amount: root.update_text
       +            size_hint: 1, None
       +            height: '30dp'
       +            MButton:
       +                text: 'Z'
       +            MButton:
       +                text: 'X'
       +            MButton:
       +                text: 'C'
       +            MButton:
       +                text: 'V'
       +            MButton:
       +                text: 'B'
       +            MButton:
       +                text: 'N'
       +            MButton:
       +                text: 'M'
       +            MButton:
       +                text: '<'
       +
            GridLayout:
                rows: 1
                spacing: '12dp'
       t@@ -182,6 +267,7 @@ Builder.load_string('''
                    id: next
                    text: _('Next')
                    root: root
       +            disabled: True
        
        
        <ShowSeedDialog>
       t@@ -206,8 +292,6 @@ Builder.load_string('''
                    valign: 'middle'
                    font_size: self.width/15
                    text_size: self.width - dp(24), self.height - dp(12)
       -            #size_hint: 1, None
       -            #height: self.texture_size[1] + dp(24)
                    color: .1, .1, .1, 1
                    background_normal: 'atlas://gui/kivy/theming/light/white_bg_round_top'
                    background_down: self.background_normal
       t@@ -215,7 +299,6 @@ Builder.load_string('''
                Label:
                    rows: 1
                    size_hint: 1, .7
       -            id: but_seed
                    border: 4, 4, 4, 4
                    halign: 'justify'
                    valign: 'middle'
       t@@ -250,7 +333,6 @@ class WizardDialog(EventsDialog):
                Window.bind(size=_trigger_size_dialog,
                            rotation=_trigger_size_dialog)
                _trigger_size_dialog()
       -        Window.softinput_mode = 'pan'
        
            def _size_dialog(self, dt):
                app = App.get_running_app()
       t@@ -273,10 +355,7 @@ class WizardDialog(EventsDialog):
            def on_dismiss(self):
                app = App.get_running_app()
                if app.wallet is None and self._on_release is not None:
       -            print "on dismiss: stopping app"
                    app.stop()
       -        else:
       -            Window.softinput_mode = 'below_target'
        
        
        class CreateRestoreDialog(WizardDialog):
       t@@ -296,12 +375,12 @@ class ShowSeedDialog(WizardDialog):
            def on_parent(self, instance, value):
                if value:
                    app = App.get_running_app()
       -            stepper = self.ids.stepper
       -            stepper.opacity = 1
       -            stepper.source = 'atlas://gui/kivy/theming/light/stepper_full'
                    self._back = _back = partial(self.ids.back.dispatch, 'on_release')
        
        
       +class WordButton(Button):
       +    pass
       +
        class RestoreSeedDialog(WizardDialog):
        
            message = StringProperty('')
       t@@ -309,10 +388,34 @@ class RestoreSeedDialog(WizardDialog):
            def __init__(self, **kwargs):
                super(RestoreSeedDialog, self).__init__(**kwargs)
                self._test = kwargs['test']
       -        self._trigger_check_seed = Clock.create_trigger(self.check_seed)
       +        from electrum.mnemonic import Mnemonic
       +        self.mnemonic = Mnemonic('en')
       +
       +    def on_text(self, dt):
       +        text = self.get_seed_text()
       +        self.ids.next.disabled = not bool(self._test(text))
        
       -    def check_seed(self, dt):
       -        self.ids.next.disabled = not bool(self._test(self.get_seed_text()))
       +        if not text:
       +            last_word = ''
       +        elif text[-1] == ' ':
       +            last_word = ''
       +        else:
       +            last_word = text.split(' ')[-1]
       +
       +        self.ids.suggestions.clear_widgets()
       +        suggestions = [x for x in self.mnemonic.get_suggestions(last_word)]
       +        if suggestions and len(suggestions) < 10:
       +            for w in suggestions:
       +                b = WordButton(text=w)
       +                self.ids.suggestions.add_widget(b)
       +
       +    def on_word(self, w):
       +        text = self.get_seed_text()
       +        words = text.split(' ')
       +        words[-1] = w
       +        text = ' '.join(words)
       +        self.ids.text_input_seed.text = text + ' '
       +        self.ids.suggestions.clear_widgets()
        
            def get_seed_text(self):
                ti = self.ids.text_input_seed
       t@@ -320,6 +423,15 @@ class RestoreSeedDialog(WizardDialog):
                text = ' '.join(text.split())
                return text
        
       +    def update_text(self, c):
       +        c = c.lower()
       +        text = self.ids.text_input_seed.text
       +        if c == '<':
       +            text = text[:-1]
       +        else:
       +            text += c
       +        self.ids.text_input_seed.text = text
       +
            def scan_seed(self):
                def on_complete(text):
                    self.ids.text_input_seed.text = text
       t@@ -330,15 +442,10 @@ class RestoreSeedDialog(WizardDialog):
                if value:
                    tis = self.ids.text_input_seed
                    tis.focus = True
       -            tis._keyboard.bind(on_key_down=self.on_key_down)
       -            stepper = self.ids.stepper
       -            stepper.opacity = 1
       -            stepper.source = ('atlas://gui/kivy/theming'
       -                              '/light/stepper_restore_seed')
       +            #tis._keyboard.bind(on_key_down=self.on_key_down)
                    self._back = _back = partial(self.ids.back.dispatch,
                                                 'on_release')
                    app = App.get_running_app()
       -            #app.navigation_higherarchy.append(_back)
        
            def on_key_down(self, keyboard, keycode, key, modifiers):
                if keycode[0] in (13, 271):
       t@@ -359,7 +466,7 @@ class RestoreSeedDialog(WizardDialog):
                    tis.focus = False
        
            def close(self):
       -        self._remove_keyboard()
       +        #self._remove_keyboard()
                app = App.get_running_app()
                #if self._back in app.navigation_higherarchy:
                #    app.navigation_higherarchy.pop()
   DIR diff --git a/lib/mnemonic.py b/lib/mnemonic.py
       t@@ -132,6 +132,11 @@ class Mnemonic(object):
                    words.append(self.wordlist[x])
                return ' '.join(words)
        
       +    def get_suggestions(self, prefix):
       +        for w in self.wordlist:
       +            if w.startswith(prefix) and w!=prefix:
       +                yield w
       +
            def mnemonic_decode(self, seed):
                n = len(self.wordlist)
                words = seed.split()