Beispiel #1
0
async def ux_enter_number(prompt, max_value):
    # return the decimal number which the user has entered
    # - default/blank value assumed to be zero
    # - clamps large values to the max
    from main import dis
    from display import FontTiny
    from math import log

    # allow key repeat on X only
    press = PressRelease('1234567890y')

    y = 26
    value = ''
    max_w = int(log(max_value, 10) + 1)

    dis.clear()
    dis.text(0, 0, prompt)
    dis.text(None, -1, "X to DELETE, or OK when DONE.", FontTiny)
    dis.save()

    while 1:
        dis.restore()

        # text centered
        if value:
            bx = dis.text(None, y, value)
            dis.icon(bx + 1, y + 11, 'space')
        else:
            dis.icon(64 - 7, y + 11, 'space')

        dis.show()

        ch = await press.wait()
        if ch == 'y':

            if not value: return 0
            return min(max_value, int(value))

        elif ch == 'x':
            if value:
                value = value[0:-1]
            else:
                # quit if they press X on empty screen
                return 0
        else:
            if len(value) == max_w:
                value = value[0:-1] + ch
            else:
                value += ch

            # cleanup leading zeros and such
            value = str(int(value))
Beispiel #2
0
    async def add_numbers(self, *a):
        # collect a series of digits
        from main import dis
        from display import FontTiny, FontSmall
        global pp_sofar

        # allow key repeat on X only
        press = PressRelease('1234567890y')

        footer = "X to DELETE, or OK when DONE."
        lx = 6
        y = 16
        here = ''

        dis.clear()
        dis.text(None, -1, footer, FontTiny)
        dis.save()

        while 1:
            dis.restore()

            # text centered
            msg = here
            by = y
            bx = dis.text(lx, y, msg[0:16])
            dis.text(lx, y - 9,
                     str(pp_sofar, 'ascii').replace(' ', '_'), FontTiny)

            if len(msg) > 16:
                # second line when needed (left just)
                by += 15
                bx = dis.text(lx, by, msg[16:])

            if len(here) < 32:
                dis.icon(bx, by - 2, 'sm_box')

            dis.show()

            ch = await press.wait()
            if ch == 'y':
                pp_sofar += here
                self.check_length()
                return
            elif ch == 'x':
                if here:
                    here = here[0:-1]
                else:
                    # quit if they press X on empty screen
                    return
            else:
                if len(here) < 32:
                    here += ch
Beispiel #3
0
    def show_pin(self, force_draw=False):
        if self.randomize:
            return self.show_pin_randomized(force_draw)

        filled = len(self.pin)
        y = 27

        if force_draw:
            dis.clear()

            if not self.pin_prefix:
                prompt="Enter PIN Prefix" 
            else:
                prompt="Enter rest of PIN" 


            if self.subtitle:
                dis.text(None, 0, self.subtitle)
                dis.text(None, 16, prompt, FontTiny)
            else:
                dis.text(None, 4, prompt)

            if self.footer:
                footer = self.footer
            elif self.is_repeat:
                footer = "CONFIRM PIN VALUE"
            elif not self.pin_prefix:
                footer = "X to CANCEL, or OK when DONE"
            else:
                footer = "X to CANCEL, or OK to CONTINUE"

            dis.text(None, -1, footer, FontTiny)

        else:
            # just clear what we need to: the PIN area
            dis.clear_rect(0, y, 128, 21)

        w = 18

        # extra (empty) box after
        if not filled:
            dis.icon(64-(w//2), y, 'box')
        else:
            x = 64 - ((w*filled)//2)
            # filled boxes
            for idx in range(filled):
                dis.icon(x, y, 'xbox')
                x += w

        dis.show()
Beispiel #4
0
    def show_pin(self, show_hint=False):
        filled = len(self.pin)
        if show_hint:
            filled -= 1
            hint = self.pin[-1]
        else:
            hint = '' if len(self.pin) == MAX_PIN_PART_LEN else ' '

        dis.clear()

        if not self.pin_prefix:
            prompt="Enter PIN Prefix" 
        else:
            prompt="Enter rest of PIN" 


        if self.subtitle:
            dis.text(None, 0, self.subtitle)
            dis.text(None, 16, prompt, FontTiny)
        else:
            dis.text(None, 4, prompt)

        y = 26
        w = 18
        if 0:
            x = 64 - ((w * (filled+(1 if hint else 0))) // 2)
            x += w//2
        else:
            x = 12

        for idx in range(filled):
            dis.icon(x, y, 'xbox')
            x += w
        if hint:
            dis.text(x+1, y+1, hint, FontLarge)
            dis.icon(x, y, 'box')

        # BTW: √ also works here, but looks like square root, not a checkmark
        if self.is_repeat:
            footer = "CONFIRM PIN VALUE"
        elif not self.pin_prefix:
            footer = "X to CANCEL, or OK when DONE."
        else:
            footer = "X to CANCEL, or OK to CONTINUE."

        dis.text(None, -1, footer, FontTiny)

        dis.show()
Beispiel #5
0
    def show_pin(self, show_hint=False):
        filled = len(self.pin)
        if show_hint:
            filled -= 1
            hint = self.pin[-1] if not version.has_membrane else None

        dis.clear()

        if not self.pin_prefix:
            prompt="Enter PIN Prefix" 
        else:
            prompt="Enter rest of PIN" 


        if self.subtitle:
            dis.text(None, 0, self.subtitle)
            dis.text(None, 16, prompt, FontTiny)
        else:
            dis.text(None, 4, prompt)

        y = 27
        w = 18
        x = 12

        for idx in range(filled):
            dis.icon(x, y, 'xbox')
            x += w

        if show_hint:
            if not version.has_membrane:
                dis.text(x+1, y+1, hint, FontLarge)
                dis.icon(x, y, 'box')
            else:
                dis.icon(x, y, 'tbox')
        else:
            if len(self.pin) != MAX_PIN_PART_LEN:
                dis.icon(x, y, 'box')

        # BTW: √ also works here, but looks like square root, not a checkmark
        if self.footer:
            footer = self.footer
        elif self.is_repeat:
            footer = "CONFIRM PIN VALUE"
        elif not self.pin_prefix:
            footer = "X to CANCEL, or OK when DONE"
        else:
            footer = "X to CANCEL, or OK to CONTINUE"

        dis.text(None, -1, footer, FontTiny)

        dis.show()
Beispiel #6
0
    def show(self):
        #
        # Redraw the menu.
        #
        dis.clear()

        #print('cur=%d ypos=%d' % (self.cursor, self.ypos))

        # subclass hook
        self.early_draw(dis)

        x, y = (10, 2)
        h = 14
        for n in range(self.ypos + PER_M + 1):
            if n + self.ypos >= self.count: break
            msg = self.items[n + self.ypos].label
            is_sel = (self.cursor == n + self.ypos)
            if is_sel:
                dis.dis.fill_rect(0, y, 128, h - 1, 1)
                dis.icon(2, y, 'wedge', invert=1)
                dis.text(x, y, msg, invert=1)
            else:
                dis.text(x, y, msg)

            if self.chosen is not None and (n + self.ypos) == self.chosen:
                dis.icon(108, y, 'selected', invert=is_sel)

            y += h
            if y > 128: break

        # subclass hook
        self.late_draw(dis)

        if self.count > PER_M:
            dis.scroll_bar(self.ypos / (self.count - PER_M))

        dis.show()
Beispiel #7
0
    def show_pin(self, show_hint=False):
        if self.randomize:
            return self.show_pin_randomized()

        filled = len(self.pin)
        if show_hint:
            filled -= 1
            hint = None     # used to be: self.pin[-1]  (for Mk1)

        dis.clear()

        if not self.pin_prefix:
            prompt="Enter PIN Prefix" 
        else:
            prompt="Enter rest of PIN" 


        if self.subtitle:
            dis.text(None, 0, self.subtitle)
            dis.text(None, 16, prompt, FontTiny)
        else:
            dis.text(None, 4, prompt)

        y = 27
        w = 18
        x = 12

        for idx in range(filled):
            dis.icon(x, y, 'xbox')
            x += w

        if show_hint:
            dis.icon(x, y, 'tbox')
        else:
            if len(self.pin) != MAX_PIN_PART_LEN:
                dis.icon(x, y, 'box')

        if self.footer:
            footer = self.footer
        elif self.is_repeat:
            footer = "CONFIRM PIN VALUE"
        elif not self.pin_prefix:
            footer = "X to CANCEL, or OK when DONE"
        else:
            footer = "X to CANCEL, or OK to CONTINUE"

        dis.text(None, -1, footer, FontTiny)

        dis.show()
Beispiel #8
0
async def spinner_edit(pw):
    # Allow them to pick each digit using "D-pad"
    from main import dis
    from display import FontTiny, FontSmall

    # Should allow full unicode, NKDN
    # - but limited to what we can show in FontSmall
    # - so really just ascii; not even latin-1
    # - 8-bit codepoints only
    my_rng = range(32, 127)          # FontSmall.code_range
    symbols = b' !"#$%&\'()*+,-./:;<=>?@[\\]^_`{|}~'
    letters = b'abcdefghijklmnopqrstuvwxyz'
    Letters = b'ABCDEFGHIJKLMNOPQRSTUVWXYZ'
    numbers = b'1234567890'
    #assert len(set(symbols+letters+Letters+numbers)) == len(my_rng)
    
    footer1 = "1=Letters  2=Numbers  3=Symbols"
    footer2 = "4=SwapCase  0=HELP"
    y = 20
    pw = bytearray(pw or 'A')

    pos = len(pw)-1       # which part being changed
    n_visible = const(9)
    scroll_x = max(pos - n_visible, 0)

    def cycle_set(which, direction=1):
        # pick next item in set of choices
        for n, s in enumerate(which):
            if pw[pos] == s:
                try:
                    pw[pos] = which[n+direction]
                except IndexError:
                    pw[pos] = which[0 if direction==1 else -1]
                return
        pw[pos] = which[0]

    def change(dx):
        # next/prev within the same subset of related chars
        ch = pw[pos]
        for subset in [symbols, letters, Letters, numbers]:
            if ch in subset:
                return cycle_set(subset, dx)

        # probably unreachable code: numeric up/down
        ch = pw[pos] + dx
        if ch not in my_rng:
            ch = (my_rng.stop-1) if dx < 0 else my_rng.start
            assert ch in my_rng
        pw[pos] = ch

    # no key-repeat on certain keys
    press = PressRelease('4xy')
    while 1:
        dis.clear()

        lr = pos - scroll_x     # left/right distance of cursor
        if lr < 4 and scroll_x:
            scroll_x -= 1
        elif lr < 0:
            scroll_x = pos
        elif lr >= (n_visible-1):
            # past right edge
            scroll_x += 1

        for i in range(n_visible):
            # calc abs position in string
            ax = scroll_x + i
            x = 4 + (13*i)
            try:
                ch = pw[ax]
            except IndexError:
                continue

            if ax == pos:
                # draw cursor
                if len(pw) < 2*n_visible:
                    dis.text(x-4, y-19, '0x%02X' % ch, FontTiny)
                dis.icon(x-2, y-10, 'spin')

            if ch == 0x20:
                dis.icon(x, y+11, 'space')
            else:
                dis.text(x, y, chr(ch) if ch in my_rng else chr(215), FontSmall)

        if scroll_x > 0:
            dis.text(2, y-14, str(pw, 'ascii')[0:scroll_x].replace(' ', '_'), FontTiny)
        if scroll_x + n_visible < len(pw):
            dis.text(-1, 1, "MORE>", FontTiny)

        if 0:
            wy = 6
            count = len(pw)
            dis.text(-8, wy-4, "%d" % count)


        dis.text(None, -10, footer1, FontTiny)
        dis.text(None, -1, footer2, FontTiny)
        dis.show()

        ch = await press.wait()
        if ch == 'y':
            return str(pw, 'ascii')
        elif ch == 'x':
            if len(pw) > 1:
                # delete current char
                pw = pw[0:pos] + pw[pos+1:]
                if pos >= len(pw):
                    pos = len(pw)-1
            else:
                pp = await ux_show_story("OK to leave without any changes? Or X to cancel leaving.")
                if pp == 'x': continue
                return None

        elif ch == '7':      # left
            pos -= 1
            if pos < 0: pos = 0
        elif ch == '9':      # right
            pos += 1
            if pos >= len(pw):
                if len(pw) < 100 and pw[-3:] != b'   ':
                    pw += ' '       # expand with spaces
                else:
                    pos -= 1        # abort addition

        elif ch == '5':     # up
            change(1)
        elif ch == '8':     # down
            change(-1)
        elif ch == '1':     # alpha
            cycle_set(b'Aa')
        elif ch == '4':     # toggle case
            if (pw[pos] & ~0x20) in range(65, 91):
                pw[pos] ^= 0x20
        elif ch == '2':     # numbers
            cycle_set(numbers)
        elif ch == '3':     # symbols (all of them)
            cycle_set(symbols)
        elif ch == '0':     # help
            await ux_show_story('''\
Use arrow keys (5789) to select letter and move around. 

1=Letters (Aa..)
2=Numbers (12..)
3=Symbols (!@#&*)
4=Swap Case (q/Q)
X=Delete char

To quit without changes, delete everything. \
Add more characters by moving past end (right side).
''')