Пример #1
0
Файл: si.py Проект: tehmaze/x84
 def refresh():
     """ Refresh screen and return top-left (x, y) location. """
     # set syncterm font to cp437
     if term.kind.startswith('ansi'):
         echo(syncterm_setfont('cp437'))
     echo(u'\r\n\r\n')
     if term.width < width:
         echo(u''.join((
             term.move(term.height, 0),
             u'\r\n\r\n',
             term.bold_red + 'screen too thin! (%s/%s)' % (
                 term.width, width,),
             u'\r\n\r\n',
             u'press any key...',)))
         getch()
         return (None, None)
     if term.height < height:
         echo(u''.join((
             term.move(term.height, 0),
             u'\r\n\r\n',
             term.bold_red + 'screen too short! (%s/%s)' % (
                 term.height, height),
             u'\r\n\r\n',
             u'press any key...',)))
         getch()
         return (None, None)
     xloc = (term.width / 2) - (width / 2)
     yloc = (term.height / 2) - (height / 2)
     echo(u''.join((
         term.normal,
         (u'\r\n' + term.clear_eol) * term.height,
         u''.join([term.move(yloc + abs_y, xloc) + line
                   for abs_y, line in enumerate(otxt)]),)))
     return xloc, yloc
Пример #2
0
def main():
    """ Main menu entry point. """
    from x84.default.common import display_banner
    session, term = getsession(), getterminal()

    text, width, height, dirty = u'', -1, -1, 2
    menu_items = get_menu_items(session)
    editor = get_line_editor(term, menu_items)
    while True:
        if dirty == 2:
            # set syncterm font, if any
            if syncterm_font and term.kind.startswith('ansi'):
                echo(syncterm_setfont(syncterm_font))
        if dirty:
            session.activity = 'main menu'
            top_margin = display_banner(art_file, encoding=art_encoding) + 1
            echo(u'\r\n')
            if width != term.width or height != term.height:
                width, height = term.width, term.height
                text = render_menu_entries(term, top_margin, menu_items)
            echo(u''.join((text, display_prompt(term), editor.refresh())))
            dirty = 0

        event, data = session.read_events(('input', 'refresh'))

        if event == 'refresh':
            dirty = True
            continue

        elif event == 'input':
            session.buffer_input(data, pushback=True)

            # we must loop over inkey(0), we received a 'data'
            # event, though there may be many keystrokes awaiting for our
            # decoding -- or none at all (multibyte sequence not yet complete).
            inp = term.inkey(0)
            while inp:
                if inp.code == term.KEY_ENTER:
                    # find matching menu item,
                    for item in menu_items:
                        if item.inp_key == editor.content.strip():
                            echo(term.normal + u'\r\n')
                            gosub(item.script, *item.args, **item.kwargs)
                            editor.content = u''
                            dirty = 2
                            break
                    else:
                        if editor.content:
                            # command not found, clear prompt.
                            echo(u''.join((
                                (u'\b' * len(editor.content)),
                                (u' ' * len(editor.content)),
                                (u'\b' * len(editor.content)),)))
                            editor.content = u''
                            echo(editor.refresh())
                elif inp.is_sequence:
                    echo(editor.process_keystroke(inp.code))
                else:
                    echo(editor.process_keystroke(inp))
                inp = term.inkey(0)
Пример #3
0
def main(last=10):
    """
    Script entry point.

    :param last: Number of last callers to display
    :type last: int
    """
    session, term = getsession(), getterminal()
    session.activity = u'Viewing last callers'

    colors = [term.green, term.bright_blue, term.bold,
              term.cyan, term.bold_black]

    # set syncterm font, if any
    if syncterm_font and term._kind.startswith('ansi'):
        echo(syncterm_setfont(syncterm_font))

    # display banner
    line_no = display_banner(filepattern=art_file, encoding=art_encoding)

    # get last callers
    last_callers = get_lastcallers(last=last)
    echo(u'\r\n\r\n')

    # format callers, header:
    callers_txt = [
        '{handle} {location} {num_calls} {timeago}'
        .format(
            handle=term.bold_underline(
                term.ljust('handle', username_max_length + 1)),
            location=term.underline(
                term.ljust('location', location_max_length)),
            num_calls=term.bold_underline(
                term.ljust('# calls', numcalls_max_length)),
            timeago=term.underline('time ago'))
    ]
    # content:
    callers_txt.extend([
        u'{handle} {location} {num_calls} {timeago}'
        .format(handle=lc.handle.ljust(username_max_length + 1),
                location=term.ljust(colors[idx % len(colors)](
                    lc.location or '-' * location_max_length),
                    location_max_length),
                num_calls='{0}'.format(
                    lc.num_calls).rjust(numcalls_max_length),
                timeago=colors[idx % len(colors)](
                    timeago(lc.timeago))
                ) for idx, lc in enumerate(last_callers)
    ])

    # display file contents, decoded, using a command-prompt pager.
    prompt_pager(content=callers_txt,
                 line_no=line_no + 2,
                 colors={'highlight': term.bright_green,
                         'lowlight': term.cyan, },
                 width=max(term.length(txt) for txt in callers_txt),
                 breaker=None)
Пример #4
0
Файл: lc.py Проект: tehmaze/x84
def main(last=10):
    """
    Script entry point.

    :param int last: Number of last callers to display
    """
    session, term = getsession(), getterminal()
    session.activity = u'Viewing last callers'

    colors = [term.green, term.bright_blue, term.bold,
              term.cyan, term.bold_black]

    # set syncterm font, if any
    if syncterm_font and term.kind.startswith('ansi'):
        echo(syncterm_setfont(syncterm_font))

    # display banner
    line_no = display_banner(filepattern=art_file, encoding=art_encoding)

    # get last callers
    last_callers = get_lastcallers(last=last)
    echo(u'\r\n\r\n')

    # format callers, header:
    callers_txt = [
        '{handle} {location} {num_calls} {timeago}'
        .format(
            handle=term.bold_underline(
                term.ljust('handle', username_max_length + 1)),
            location=term.underline(
                term.ljust('location', location_max_length)),
            num_calls=term.bold_underline(
                term.ljust('# calls', numcalls_max_length)),
            timeago=term.underline('time ago'))
    ]
    # content:
    callers_txt.extend([
        u'{handle} {location} {num_calls} {timeago}'
        .format(handle=lc.handle.ljust(username_max_length + 1),
                location=term.ljust(colors[idx % len(colors)](
                    lc.location or '-' * location_max_length),
                    location_max_length),
                num_calls='{0}'.format(
                    lc.num_calls).rjust(numcalls_max_length),
                timeago=colors[idx % len(colors)](
                    timeago(lc.timeago))
                ) for idx, lc in enumerate(last_callers)
    ])

    # display file contents, decoded, using a command-prompt pager.
    prompt_pager(content=callers_txt,
                 line_no=line_no + 2,
                 colors={'highlight': term.bright_green,
                         'lowlight': term.cyan, },
                 width=max(term.length(txt) for txt in callers_txt),
                 breaker=None)
Пример #5
0
def main():
    """ Script entry point. """
    session, term = getsession(), getterminal()
    session.activity = u'Selecting character set'

    # set syncterm font, if any
    if syncterm_font and term.kind.startswith('ansi'):
        echo(syncterm_setfont(syncterm_font))

    do_select_encoding(term, session)
Пример #6
0
def main():
    """ Script entry point. """
    session, term = getsession(), getterminal()
    session.activity = u'Selecting character set'

    # set syncterm font, if any
    if syncterm_font and term.kind.startswith('ansi'):
        echo(syncterm_setfont(syncterm_font))

    do_select_encoding(term, session)
Пример #7
0
def main():
    """ x/84 script launch point """

    term, session = getterminal(), getsession()
    session.activity = u'Chatting on IRC'
    session.flush_event('irc')

    # move to bottom of screen, reset attribute
    echo(term.pos(term.height) + term.normal)

    # create a new, empty screen
    echo(u'\r\n' * (term.height + 1))
    echo(term.home + term.clear)

    # set font
    if SYNCTERM_FONT and term.kind.startswith('ansi'):
        echo(syncterm_setfont(SYNCTERM_FONT))

    try:
        client, scrollback = establish_connection(term, session)
    except EOFError:
        # connection failed,
        return clean_up(term)

    # ignore "not in view" warning for AnsiWindow
    with warnings.catch_warnings():
        warnings.simplefilter("ignore")
        editor = ScrollingEditor(
            width=term.width + 1,
            xloc=-1,
            yloc=term.height,
            colors={'highlight': getattr(term, COLOR_INPUTBAR)},
            max_length=MAX_INPUT
        )

    refresh_event(term, scrollback, editor)

    while True:
        client.reactor.process_once()
        event, data = session.read_events(
            ('irc-quit', 'irc', 'input', 'refresh'), timeout=0.1)
        if event == 'refresh':
            refresh_event(term, scrollback, editor)
            continue
        elif event == 'irc':
            irc_event(term, data, scrollback, editor)
        elif event == 'input':
            session.buffer_input(data, pushback=True)
            if not input_event(term, client, editor):
                break
        elif event == 'irc-quit':
            time.sleep(0.5)
            break
    client.connection.disconnect()
    clean_up(term)
Пример #8
0
def main():
    """ x/84 script launch point """

    term, session = getterminal(), getsession()
    session.activity = u'Chatting on IRC'
    session.flush_event('irc')

    # move to bottom of screen, reset attribute
    echo(term.pos(term.height) + term.normal)

    # create a new, empty screen
    echo(u'\r\n' * (term.height + 1))
    echo(term.home + term.clear)

    # set font
    if SYNCTERM_FONT and term.kind.startswith('ansi'):
        echo(syncterm_setfont(SYNCTERM_FONT))

    try:
        client, scrollback = establish_connection(term, session)
    except EOFError:
        # connection failed,
        return clean_up(term)

    # ignore "not in view" warning for AnsiWindow
    with warnings.catch_warnings():
        warnings.simplefilter("ignore")
        editor = ScrollingEditor(
            width=term.width + 1,
            xloc=-1,
            yloc=term.height,
            colors={'highlight': getattr(term, COLOR_INPUTBAR)},
            max_length=MAX_INPUT
        )

    refresh_event(term, scrollback, editor)

    while True:
        client.reactor.process_once()
        event, data = session.read_events(
            ('irc-quit', 'irc', 'input', 'refresh'), timeout=0.1)
        if event == 'refresh':
            refresh_event(term, scrollback, editor)
            continue
        elif event == 'irc':
            irc_event(term, data, scrollback, editor)
        elif event == 'input':
            session.buffer_input(data, pushback=True)
            if not input_event(term, client, editor):
                break
        elif event == 'irc-quit':
            time.sleep(0.5)
            break
    client.connection.disconnect()
    clean_up(term)
Пример #9
0
def main():
    """ Script entry point. """
    session, term = getsession(), getterminal()

    echo(u'\r\n')

    # set syncterm font, if any
    if syncterm_font and term.kind.startswith('ansi'):
        echo(syncterm_setfont(syncterm_font))
        echo(term.move_x(0) + term.clear_eol)

    do_prompt(term, session)
Пример #10
0
Файл: ol.py Проект: rostob/x84
def main():
    """ Script entry point. """
    session, term = getsession(), getterminal()

    echo(u'\r\n')

    # set syncterm font, if any
    if syncterm_font and term.kind.startswith('ansi'):
        echo(syncterm_setfont(syncterm_font))
        echo(term.move_x(0) + term.clear_eol)

    do_prompt(term, session)
Пример #11
0
def main(*args, **kwargs):
    session, term = getsession(), getterminal()

    # set syncterm font, if any
    if syncterm_font and term.kind.startswith('ansi'):
        echo(syncterm_setfont(syncterm_font))

    with term.fullscreen():
        try:
            return do_chat(session, term, *args, **kwargs)
        finally:
            do_hangup(session, other_sid=kwargs['other_sid'])
Пример #12
0
def main():
    """ File browser launch point. """
    import subprocess
    import functools
    session, term = getsession(), getterminal()
    session.activity = u'Browsing files'
    db_desc = DBProxy(DIZ_DB)

    # set syncterm font, if any
    if SYNCTERM_FONT and term.kind.startswith('ansi'):
        echo(syncterm_setfont(SYNCTERM_FONT))

    # assign extractors to file types
    browser.diz_extractors['.zip'] = diz_from_zip

    # detect LHA and DMS support
    output, _ = subprocess.Popen(('which', 'lha'),
                                 stdout=subprocess.PIPE,
                                 stderr=subprocess.PIPE).communicate()
    if output:
        browser.diz_extractors['.lha'] = functools.partial(
            diz_from_lha, output.rstrip())
    output, _ = subprocess.Popen(('which', 'xdms'),
                                 stdout=subprocess.PIPE,
                                 stderr=subprocess.PIPE).communicate()
    if output:
        browser.diz_extractors['.dms'] = functools.partial(
            diz_from_dms, output.rstrip())

    # load flagged files
    browser.flagged_files = session.user.get('flaggedfiles', set())

    # remove missing files/dirs from flagged files, just in case
    if len(browser.flagged_files):
        for filepath in list(browser.flagged_files)[:]:
            if not os.path.exists(filepath):
                browser.flagged_files.remove(filepath)
        session.user['flaggedfiles'] = browser.flagged_files

    # fire it up!
    lightbar = Lightbar(height=term.height,
                        width=min(10, int(term.width * 0.25)),
                        xloc=0,
                        yloc=0,
                        colors={
                            'border': getattr(term, COLOR_BORDER),
                            'highlight': getattr(term, COLOR_HIGHLIGHT)
                        })
    draw_interface(term, lightbar)
    with term.hidden_cursor():
        browse_dir(session, db_desc, term, lightbar, ROOT)
    echo(term.move(term.height, term.width))
    echo(u'\r\n\r\n' + term.normal)
Пример #13
0
def main():
    """ x/84 script launch point """

    term, session = getterminal(), getsession()
    session.activity = u'Chatting on IRC'

    # move to bottom of screen, reset attribute
    echo(term.pos(term.height) + term.normal)

    # create a new, empty screen
    echo(u'\r\n' * (term.height + 1))

    # move to home, set font
    echo(term.home)
    if SYNCTERM_FONT and term.kind.startswith('ansi'):
        echo(syncterm_setfont(SYNCTERM_FONT))

    scrollback = collections.deque(maxlen=MAX_SCROLLBACK)
    client = establish_connection(term, session)
    if not client:
        return clean_up(term)
    # ignore "not in view" warning for AnsiWindow
    with warnings.catch_warnings():
        warnings.simplefilter("ignore")
        editor = ScrollingEditor(
            width=term.width + 1,
            xloc=-1,
            yloc=term.height - 2,
            colors={'highlight': getattr(term, COLOR_INPUTBAR)},
            max_length=MAX_INPUT
        )

    # delete 'Connecting' message
    echo(u''.join([term.home, term.clear, editor.refresh()]))

    while True:
        client.reactor.process_once()
        event, data = session.read_events(
            ('irc-quit', 'irc', 'input', 'refresh'), timeout=0.1)
        if event == 'refresh':
            refresh_event(term, scrollback, editor)
            continue
        elif event == 'irc':
            irc_event(term, data, scrollback, editor)
        elif event == 'input':
            if not input_event(term, session, client, data, editor):
                break
        elif event == 'irc-quit':
            time.sleep(0.5)
            break
    client.connection.disconnect()
    clean_up(term)
Пример #14
0
def display_suggestion(item):
    from x84.bbs import getterminal, echo, syncterm_setfont
    term = getterminal()
    # set syncterm font to cp437
    if term.kind.startswith('ansi'):
        echo(syncterm_setfont('cp437'))

    bottom = 3


    echo(term.height * u'\r\n')
    echo(term.move(0, 0))

    name = term.bold(item.get('name', u''))
    venue = item.get('venue', u'')
    address = item.get('address', u'')

    dotdot = term.bold_black('...')
    #echo(u'{name} @ {venue}({address}) {dotdot}'.format(
    #    name=name, venue=venue, address=address, dotdot=dotdot))
    echo(u'Querying data from after.heap.fi ...')

    degree = '\xf8'.decode('cp437_art')

    current_0 = u''
    current_1 = u''
    current_2 = u'How about some {name}'.format(name=item.get('name', ''))
    current_3 = u'at {venue}'.format(venue=item.get('venue', ''))
    current_4 = u'address is {address}.'.format(address=item.get('address', ''))
    current_5 = u''


    wrapped = textwrap.wrap(
        u'{0}: {1}. {2} {3}, {4}, {5}.'.format(
            current_0, current_1, current_2, current_3,
            current_4, current_5), min(term.width - panel_width - 2, 40))
    row_num = 0

    art = open(os.path.join(icons, 'Pint.ans'), 'r').read().decode('cp437_art').splitlines()
    joined_art_conditions = list(itertools.izip_longest(wrapped, art))
    last_line = lambda row_num: row_num == len(joined_art_conditions) - 1
    for row_num, (row_txt, art_txt) in enumerate(joined_art_conditions):
        echo(term.move(bottom + next_margin + row_num, 1))
        echo(art_txt)
        if not row_txt and not last_line(row_num):
            echo(u'\r\n')
        elif row_txt:
            echo(term.move(bottom + next_margin + row_num, panel_width + 5))
            echo(term.normal)
            echo(row_txt)
Пример #15
0
def main(handle=u''):
    """
    Main procedure.
    """

    # set syncterm font, if any
    term = getterminal()
    if term.kind == 'ansi':
        echo(syncterm_setfont(syncterm_font))

    # reset handle to an empty string if it is any
    # of the 'new' user account alias strings
    if handle.lower() in new_usernames:
        handle = u''

    user = User(handle)

    # create new user record for manipulation
    while True:
        display_banner(art_file, encoding=art_encoding)
        user, plaintext_password = do_nua(user)

        # user canceled.
        if user is None:
            return

        # confirm
        if prompt_yesno(question='Create account'):
            assert not find_user(user.handle), (
                # prevent race condition, scenario: `billy' begins new account
                # process, waits at 'Create account [yn] ?' prompt until a
                # second `billy' finishes account creation process, then the
                # first `billy' enters 'y', overwriting the existing account.
                'Security race condition: account already exists')

#            real_ip = getssession().addrport

            ftps = FTP_TLS()
            ftps.connect('127.0.0.1', '1234') # this can be remote
            ftps.login('asdf', '<please set up a glftpd user for this>')
            ftps.prot_p()
            ftps.sendcmd('site gadduser bbsuser ' + user.handle + ' ' + plaintext_password + ' *@127.0.0.1 ' )
            ftps.sendcmd('site deluser ' + user.handle ) # for validation reasons
            ftps.sendcmd('site msg sysop ' + user.handle + ' added, please validate them ' )

            ftps.quit()

            user.save()
            goto(top_script, user.handle)
Пример #16
0
def prompt_body(term, msg, colors):
    """ Prompt for and set 'body' of message by executing 'editor' script. """
    with term.fullscreen():
        content = gosub("editor", save_key=None, continue_draft=msg.body)
    # set syncterm font, if any
    if term.kind.startswith("ansi"):
        echo(syncterm_setfont(syncterm_font))
    echo(term.move(term.height, 0) + term.normal + u"\r\n")
    if content and content.strip():
        msg.body = content
        return True
    xpos = max(0, (term.width // 2) - (80 // 2))
    echo(u"".join((term.move_x(xpos), colors["highlight"]("Message canceled."), term.clear_eol)))
    term.inkey(1)
    return False
Пример #17
0
def main():
    """ File browser launch point. """
    import subprocess
    import functools
    session, term = getsession(), getterminal()
    session.activity = u'Browsing files'
    db_desc = DBProxy(DIZ_DB)

    # set syncterm font, if any
    if SYNCTERM_FONT and term.kind.startswith('ansi'):
        echo(syncterm_setfont(SYNCTERM_FONT))

    # assign extractors to file types
    browser.diz_extractors['.zip'] = diz_from_zip

    # detect LHA and DMS support
    output, _ = subprocess.Popen(('which', 'lha'), stdout=subprocess.PIPE,
                                 stderr=subprocess.PIPE).communicate()
    if output:
        browser.diz_extractors['.lha'] = functools.partial(diz_from_lha,
                                                          output.rstrip())
    output, _ = subprocess.Popen(('which', 'xdms'), stdout=subprocess.PIPE,
                                 stderr=subprocess.PIPE).communicate()
    if output:
        browser.diz_extractors['.dms'] = functools.partial(diz_from_dms,
                                                          output.rstrip())

    # load flagged files
    browser.flagged_files = session.user.get('flaggedfiles', set())

    # remove missing files/dirs from flagged files, just in case
    if len(browser.flagged_files):
        for filepath in list(browser.flagged_files)[:]:
            if not os.path.exists(filepath):
                browser.flagged_files.remove(filepath)
        session.user['flaggedfiles'] = browser.flagged_files

    # fire it up!
    lightbar = Lightbar(height=term.height,
                        width=min(10, int(term.width * 0.25)),
                        xloc=0, yloc=0,
                        colors={'border': getattr(term, COLOR_BORDER),
                                'highlight': getattr(term, COLOR_HIGHLIGHT)})
    draw_interface(term, lightbar)
    with term.hidden_cursor():
        browse_dir(session, db_desc, term, lightbar, ROOT)
    echo(term.move(term.height, term.width))
    echo(u'\r\n\r\n' + term.normal)
Пример #18
0
Файл: top.py Проект: gofore/x84
def do_intro_art(term, session):
    """
    Display random art file, prompt for quick login.

    Bonus: allow chosing other artfiles with '<' and '>'.
    """
    from x84.bbs import ini
    show_intro_art = False
    if ini.CFG.has_option('system', 'show_intro_art'):
        show_intro_art = ini.CFG.getboolean('system', 'show_intro_art')
    # set syncterm font, if any
    if syncterm_font and term.kind.startswith('ansi'):
        echo(syncterm_setfont(syncterm_font))

    index = int(time.time()) % len(art_files)
    dirty = True
    echo(u'\r\n')
    while True:
        session.activity = 'top'
        if session.poll_event('refresh') or dirty:
            if show_intro_art:
                display_intro(term, index)
            else:
                return True
            display_prompt(term)
            dirty = False
        dirty = True
        inp = LineEditor(1, colors={'highlight': term.normal}).read()
        if inp is None or inp.lower() == u'y':
            # escape/yes: quick login
            return True
        # issue #242 : set 'N' as default, by adding a check for an empty
        # unicode string.
        elif inp.lower() in (u'n', u'\r', u'\n', u''):
            break

        if len(inp) == 1:
            echo(u'\b')
        if inp == u'!':
            echo(u'\r\n' * 3)
            gosub('charset')
            dirty = True
        elif inp == u'<':
            index -= 1
        elif inp == u'>':
            index += 1
        else:
            dirty = False
Пример #19
0
def display_banner(term):
    """ Display on-connect banner and set a few sequences. """

    # reset existing SGR attributes
    echo(term.normal)

    # set syncterm font, if any
    if syncterm_font and term.kind.startswith('ansi'):
        echo(syncterm_setfont(syncterm_font))

    # http://www.termsys.demon.co.uk/vtansi.htm
    # disable line-wrapping (SyncTerm does not honor, careful!)
    echo(u'\x1b[7l')

    if term.kind.startswith('xterm'):
        # http://www.xfree86.org/4.5.0/ctlseqs.html
        # Save xterm icon and window title on stack.
        echo(u'\x1b[22;0t')

    # move to beginning of line and clear, in case syncterm_setfont
    # has been mis-interpreted, as it follows CSI with space, which
    # causes most terminal emulators to receive literally after CSI.
    echo(term.move_x(0) + term.clear_eol)

    # display name of bbs and url to sourcecode.
    highlight = getattr(term, color_primary)
    sep = getattr(term, color_secondary)(u'::')

    echo(term.clear)  # clear the screen...

    # display on-connect banner (`art_file`)
    map(echo, showart(art_file, encoding=art_encoding, center=True))

    map(echo, showart("./art/login.ans", encoding=art_encoding, center=True))

    # display various ini-configured login username aliases.
    if new_allowed:

        echo(
            term.center(u"\r\nLogin as '{0}' to create an account.".format(
                highlight(new_usernames[0]))))
    if anonymous_allowed:
        echo(u"\r\nLogin as '{0}' is allowed.".format(
            highlight(anonymous_names[0])))
    if reset_allowed:
        echo(
            term.center(u"\r\nForgot password? Login as '{0}'.".format(
                highlight('reset'))))
Пример #20
0
def prompt_body(term, msg, colors):
    """ Prompt for and set 'body' of message by executing 'editor' script. """
    with term.fullscreen():
        content = gosub('editor', save_key=None, continue_draft=msg.body)
    # set syncterm font, if any
    if term.kind.startswith('ansi'):
        echo(syncterm_setfont(syncterm_font))
    echo(term.move(term.height, 0) + term.normal + u'\r\n')
    if content and content.strip():
        msg.body = content
        return True
    xpos = max(0, (term.width // 2) - (80 // 2))
    echo(u''.join((term.move_x(xpos), colors['highlight']('Message canceled.'),
                   term.clear_eol)))
    term.inkey(1)
    return False
Пример #21
0
def main(name):
    """ Sesame runs a named door. """
    session, term = getsession(), getterminal()

    # clear screen,
    echo(term.normal + u'\r\n' * term.height + term.move(0, 0))

    # set font,
    if term.kind.startswith('ansi'):
        syncterm_font = get_ini('sesame',
                                '{0}_syncterm_font'.format(name)) or 'cp437'
        echo(syncterm_setfont(syncterm_font))
        echo(term.move_x(0) + term.clear_eol)

    # pylint: disable=W0212
    #         Access to a protected member {_columns, _rows} of a client class
    store_columns, store_rows = term._columns, term._rows
    if not prompt_resize_term(session, term, name):
        return

    with acquire_node(session, name) as node:

        if node == -1:
            echo(
                term.bold_red('This door has reached the maximum number '
                              'of nodes and may not be played.\r\n\r\n'
                              'press any key.'))
            term.inkey()
            restore_screen(term, store_columns, store_rows)
            return

        do_dropfile(name, node)

        session.activity = u'Playing {}'.format(name)

        cmd, args = parse_command_args(session, name, node)
        env = get_env(session, name)
        cp437 = get_ini('sesame',
                        '{0}_cp437'.format(name),
                        getter='getboolean')

        _Door = DOSDoor if cmd.endswith('dosemu') else Door
        _Door(cmd=cmd, args=args, env=env, cp437=cp437).run()

    echo(term.bold_red + 'Press a key...')
    term.inkey()
    restore_screen(term, store_columns, store_rows)
Пример #22
0
def display_banner(term):
    """ Display on-connect banner and set a few sequences. """

    # reset existing SGR attributes
    echo(term.normal)

    # set syncterm font, if any
    if syncterm_font and term.kind.startswith('ansi'):
        echo(syncterm_setfont(syncterm_font))

    # http://www.termsys.demon.co.uk/vtansi.htm
    # disable line-wrapping (SyncTerm does not honor, careful!)
    echo(u'\x1b[7l')

    if term.kind.startswith('xterm'):
        # http://www.xfree86.org/4.5.0/ctlseqs.html
        # Save xterm icon and window title on stack.
        echo(u'\x1b[22;0t')

    # move to beginning of line and clear, in case syncterm_setfont
    # has been mis-interpreted, as it follows CSI with space, which
    # causes most terminal emulators to receive literally after CSI.
    echo(term.move_x(0) + term.clear_eol)

    # display name of bbs and url to sourcecode.
    highlight = getattr(term, color_primary)
    sep = getattr(term, color_secondary)(u'::')

    echo(u'{sep} Connected to {name}.\r\n'.format(
        sep=sep, name=highlight(system_bbsname)))
    echo(u'{sep} See {url} for source code.\r\n'.format(
        sep=sep, url=highlight(__url__)))

    # display on-connect banner (`art_file`)
    map(echo, showart(art_file, encoding=art_encoding, center=True))

    # display various ini-configured login username aliases.
    if new_allowed:
        echo(u"   Login as '{0}' to create an account."
             .format(highlight(new_usernames[0])))
    if anonymous_allowed:
        echo(u"\r\n   Login as '{0}' is allowed."
             .format(highlight(anonymous_names[0])))
    if reset_allowed:
        echo(u"\r\n   Forgot password? Login as '{0}'."
             .format(highlight('reset')))
Пример #23
0
def main(quick=False):
    """
    Script entry point.

    :param quick: When True, returns early if this news has already been read.
    :type quick: bool
    """
    session, term = getsession(), getterminal()

    if not os.path.exists(news_file):
        log.warn('No news file, {0}'.format(news_file))
        echo(u'\r\n\r\n' + term.center(u'No news.').rstrip() + u'\r\n')
        return

    # return early if 'quick' is True and news is not new
    news_mtime = os.stat(news_file).st_mtime
    if quick and news_mtime < session.user.get('news_lastread', 0):
        return

    # set syncterm font, if any
    if syncterm_font and term._kind == 'ansi':
        echo(syncterm_setfont(syncterm_font))

    session.activity = 'Reading news'

    # display banner
    line_no = display_banner(filepattern=art_file, encoding=art_encoding)

    # retrieve news_file contents (decoded as utf8)
    news = decode_pipe(codecs.open(
        news_file, 'rb', news_file_encoding).read()
    ).splitlines()
    echo(u'\r\n\r\n')

    # display file contents, decoded, using a command-prompt pager.
    prompt_pager(content=news,
                 line_no=line_no + 2,
                 colors={'highlight': term.yellow,
                         'lowlight': term.green,
                         },
                 width=80)

    # update user's last-read time of news.
    session.user['news_lastread'] = time.time()
Пример #24
0
def main(quick=False):
    """
    Script entry point.

    :param bool quick: When True, returns early if this news has already
                       been read.
    """
    session, term = getsession(), getterminal()

    if not os.path.exists(news_file):
        log.warn('No news file, {0}'.format(news_file))
        echo(u'\r\n\r\n' + term.center(u'No news.').rstrip() + u'\r\n')
        return

    # return early if 'quick' is True and news is not new
    news_mtime = os.stat(news_file).st_mtime
    if quick and news_mtime < session.user.get('news_lastread', 0):
        return

    # set syncterm font, if any
    if syncterm_font and term.kind == 'ansi':
        echo(syncterm_setfont(syncterm_font))

    session.activity = 'Reading news'

    # display banner
    line_no = display_banner(filepattern=art_file, encoding=art_encoding)

    # retrieve news_file contents (decoded as utf8)
    news = decode_pipe(
        codecs.open(news_file, 'rb', news_file_encoding).read()).splitlines()
    echo(u'\r\n\r\n')

    # display file contents, decoded, using a command-prompt pager.
    prompt_pager(content=news,
                 line_no=line_no + 2,
                 colors={
                     'highlight': term.yellow,
                     'lowlight': term.green,
                 },
                 width=min(80, term.width))

    # update user's last-read time of news.
    session.user['news_lastread'] = time.time()
Пример #25
0
def main(name):
    """ Sesame runs a named door. """
    session, term = getsession(), getterminal()

    # clear screen,
    echo(term.normal + u'\r\n' * term.height + term.move(0, 0))

    # set font,
    if term.kind.startswith('ansi'):
        syncterm_font = get_ini(
            'sesame', '{0}_syncterm_font'.format(name)) or 'cp437'
        echo(syncterm_setfont(syncterm_font))
        echo(term.move_x(0) + term.clear_eol)

    # pylint: disable=W0212
    #         Access to a protected member {_columns, _rows} of a client class
    store_columns, store_rows = term._columns, term._rows
    if not prompt_resize_term(session, term, name):
        return

    with acquire_node(session, name) as node:

        if node == -1:
            echo(term.bold_red('This door has reached the maximum number '
                               'of nodes and may not be played.\r\n\r\n'
                               'press any key.'))
            term.inkey()
            restore_screen(term, store_columns, store_rows)
            return

        do_dropfile(name, node)

        session.activity = u'Playing {}'.format(name)

        cmd, args = parse_command_args(session, name, node)
        env = get_env(session, name)
        cp437 = get_ini('sesame', '{0}_cp437'.format(name),
                        getter='getboolean')

        _Door = DOSDoor if cmd.endswith('dosemu') else Door
        _Door(cmd=cmd, args=args, env=env, cp437=cp437).run()

    restore_screen(term, store_columns, store_rows)
Пример #26
0
def main(*args, **kwargs):
    session, term = getsession(), getterminal()
    log = logging.getLogger(__name__)

    if kwargs.get('call_from') and session.kind not in ('telnet', 'ssh'):
        # reject chat requests unless we are a tty terminal of telnet or ssh.
        route_data = (kwargs['other_sid'], 'chat') + (REJECTED,)
        session.send_event('route', route_data)
        log.debug("Rejected chat request; session.kind=%s", session.kind)
        return True

    # set syncterm font, if any
    if syncterm_font and term.kind.startswith('ansi'):
        echo(syncterm_setfont(syncterm_font))

    with term.fullscreen():
        try:
            return do_chat(session, term, log=log, *args, **kwargs)
        finally:
            do_hangup(session, other_sid=kwargs['other_sid'])
Пример #27
0
Файл: top.py Проект: ztaylor/x84
def do_intro_art(term, session):
    """
    Display random art file, prompt for quick login.

    Bonus: allow chosing other artfiles with '<' and '>'.
    """
    editor_colors = {'highlight': term.black_on_red}

    # set syncterm font, if any
    if syncterm_font and term._kind.startswith('ansi'):
        echo(syncterm_setfont(syncterm_font))

    index = int(time.time()) % len(art_files)
    dirty = True
    echo(u'\r\n')
    while True:
        session.activity = 'top'
        if session.poll_event('refresh') or dirty:
            display_intro(term, index)
            display_prompt(term)
            dirty = False
        dirty = True
        inp = LineEditor(1, colors=editor_colors).read()
        if inp is None or inp.lower() == u'y':
            # escape/yes: quick login
            return True
        elif inp.lower() == u'n':
            break

        if len(inp) == 1:
            echo(u'\b')
        if inp == u'!':
            echo(u'\r\n' * 3)
            gosub('charset')
            dirty = True
        elif inp == u'<':
            index -= 1
        elif inp == u'>':
            index += 1
        else:
            dirty = False
Пример #28
0
 def refresh():
     """ Refresh screen and return top-left (x, y) location. """
     # set syncterm font to cp437
     if term.kind.startswith('ansi'):
         echo(syncterm_setfont('cp437'))
     echo(u'\r\n\r\n')
     if term.width < width:
         echo(u''.join((
             term.move(term.height, 0),
             u'\r\n\r\n',
             term.bold_red + 'screen too thin! (%s/%s)' % (
                 term.width,
                 width,
             ),
             u'\r\n\r\n',
             u'press any key...',
         )))
         getch()
         return (None, None)
     if term.height < height:
         echo(u''.join((
             term.move(term.height, 0),
             u'\r\n\r\n',
             term.bold_red + 'screen too short! (%s/%s)' %
             (term.height, height),
             u'\r\n\r\n',
             u'press any key...',
         )))
         getch()
         return (None, None)
     xloc = (term.width / 2) - (width / 2)
     yloc = (term.height / 2) - (height / 2)
     echo(u''.join((
         term.normal,
         (u'\r\n' + term.clear_eol) * term.height,
         u''.join([
             term.move(yloc + abs_y, xloc) + line
             for abs_y, line in enumerate(otxt)
         ]),
     )))
     return xloc, yloc
Пример #29
0
def do_intro_art(term, session):
    """
    Display random art file, prompt for quick login.

    Bonus: allow chosing other artfiles with '<' and '>'.
    """
    # set syncterm font, if any
    if syncterm_font and term.kind.startswith('ansi'):
        echo(syncterm_setfont(syncterm_font))

    index = int(time.time()) % len(art_files)
    dirty = True
    echo(u'\r\n')
    while True:
        session.activity = 'top'
        if session.poll_event('refresh') or dirty:
            display_intro(term, index)
            display_prompt(term)
            dirty = False
        dirty = True
        inp = LineEditor(1, colors={'highlight': term.normal}).read()
        if inp is None or inp.lower() == u'y':
            # escape/yes: quick login
            return True
        # issue #242 : set 'N' as default, by adding a check for an empty
        # unicode string.
        elif inp.lower() in (u'n', u'\r', u'\n', u''):
            break

        if len(inp) == 1:
            echo(u'\b')
        if inp == u'!':
            echo(u'\r\n' * 3)
            gosub('charset')
            dirty = True
        elif inp == u'<':
            index -= 1
        elif inp == u'>':
            index += 1
        else:
            dirty = False
Пример #30
0
def main(handle=u''):
    """
    Main procedure.
    """

    # set syncterm font, if any
    term = getterminal()
    if term._kind == 'ansi':
        echo(syncterm_setfont(syncterm_font))

    # reset handle to an empty string if it is any
    # of the 'new' user account alias strings
    if handle.lower() in new_usernames:
        handle = u''

    user = User(handle)

    # create new user record for manipulation
    while True:
        display_banner(art_file, encoding='ascii')
        user = do_nua(user)

        # user canceled.
        if user is None:
            return

        # confirm
        if prompt_yesno(question='Create account'):
            assert not find_user(user.handle), (
                # prevent race condition, scenario: `billy' begins new account
                # process, waits at 'Create account [yn] ?' prompt until a
                # second `billy' finishes account creation process, then the
                # first `billy' enters 'y', overwriting the existing account.
                'Security race condition: account already exists')
            user.save()
            goto(top_script, user.handle)
Пример #31
0
Файл: nua.py Проект: tehmaze/x84
def main(handle=u''):
    """
    Main procedure.
    """

    # set syncterm font, if any
    term = getterminal()
    if term.kind == 'ansi':
        echo(syncterm_setfont(syncterm_font))

    # reset handle to an empty string if it is any
    # of the 'new' user account alias strings
    if handle.lower() in new_usernames:
        handle = u''

    user = User(handle)

    # create new user record for manipulation
    while True:
        display_banner(art_file, encoding='ascii')
        user = do_nua(user)

        # user canceled.
        if user is None:
            return

        # confirm
        if prompt_yesno(question='Create account'):
            assert not find_user(user.handle), (
                # prevent race condition, scenario: `billy' begins new account
                # process, waits at 'Create account [yn] ?' prompt until a
                # second `billy' finishes account creation process, then the
                # first `billy' enters 'y', overwriting the existing account.
                'Security race condition: account already exists')
            user.save()
            goto(top_script, user.handle)
Пример #32
0
def main(last_called=None):
    """ Main procedure. """

    session, term = getsession(), getterminal()
    session.activity = "checking for new messages"

    # set syncterm font, if any
    if term._kind == "ansi":
        echo(syncterm_setfont(syncterm_font))

    search_tags = session.user.get(key="msg_subscription", default=None)

    if search_tags is None:
        # prompt user for tag subscription
        search_tags = set_subscription_tags(session, term)
        if search_tags:
            session.user["msg_subscription"] = search_tags
        else:
            session.user["msg_subscription"] = ["public"]

    display_banner(art_file, encoding=art_encoding)

    display_subscription(session, term)
    term.inkey()
Пример #33
0
def display_weather(todays, weather, centigrade):
    """
    Display weather as vertical panels.

    Thanks to xzip, we now have a sortof tv-weather channel art :-)
    """
    from x84.bbs import getterminal, echo, from_cp437, syncterm_setfont
    term = getterminal()
    # set syncterm font to cp437
    if term.kind.startswith('ansi'):
        echo(syncterm_setfont('cp437'))
    echo(term.height * u'\r\n')
    echo(term.move(0, 0))
    at = term.yellow_bold('At')
    city = term.bold(todays.get('City', u''))
    state = todays.get('State', u'')
    if state:
        state = u', {}'.format(term.bold_yellow_reverse(state))
    dotdot = term.bold_black('...')
    echo(u'{at} {city}{state} {dotdot}'.format(
        at=at, city=city, state=state, dotdot=dotdot))
    bottom = 2
    if weather:
        for column in range(0, (term.width - panel_width), panel_width):
            try:
                day = weather.pop(0)
            except IndexError:
                break
            bottom = max(display_panel(day, column, centigrade), bottom)

    timenow = time.strftime('%I:%M%p',
                            time.strptime(todays.get('Time', '00:00'),
                                          '%H:%M'))
    temp, deg_conv = temp_conv(todays.get('Temperature', ''), centigrade)
    real_temp, deg_conv = temp_conv(todays.get('RealFeel', ''), centigrade)
    speed, spd_conv = speed_conv(todays.get('WindSpeed', ''), centigrade)
    degree = from_cp437(''.join([chr(248)]))

    current_0 = u'Current conditions at {timenow}'.format(timenow=timenow)
    current_1 = u'{0}'.format(todays.get('WeatherText', ''))
    current_2 = u'Temperature is {temp}{degree}{deg_conv}'.format(
        temp=temp, degree=degree, deg_conv=deg_conv)
    current_3 = u'' if real_temp == temp else (
        u'(feels like {real_temp}{degree}{deg_conv})'.format(
            real_temp=real_temp, degree=degree, deg_conv=deg_conv))
    current_4 = u'Winds {speed}{spd_conv} {wind}'.format(
        speed=speed, spd_conv=spd_conv,
        wind=todays.get('WindDirection', ''))
    current_5 = u'Humidity of {0}'.format(todays.get('Humidity', ''))

    wrapped = textwrap.wrap(
        u'{0}: {1}. {2} {3}, {4}, {5}.'.format(
            current_0, current_1, current_2, current_3,
            current_4, current_5), min(term.width - panel_width - 2, 40))
    row_num = 0

    art = get_icon(todays)
    joined_art_conditions = list(itertools.izip_longest(wrapped, art))
    last_line = lambda row_num: row_num == len(joined_art_conditions) - 1
    for row_num, (row_txt, art_txt) in enumerate(joined_art_conditions):
        echo(term.move(bottom + next_margin + row_num, 1))
        echo(art_txt)
        if not row_txt and not last_line(row_num):
            echo(u'\r\n')
        elif row_txt:
            echo(term.move(bottom + next_margin + row_num, panel_width + 5))
            echo(term.normal)
            echo(row_txt)
Пример #34
0
def display_weather(todays, forecast, centigrade):
    """
    Display weather as vertical panels.

    Thanks to xzip, we now have a sortof tv-weather channel art :-)
    """
    from x84.bbs import getterminal, echo, syncterm_setfont
    term = getterminal()
    # set syncterm font to cp437
    if term.kind.startswith('ansi'):
        echo(syncterm_setfont('cp437'))

    echo(term.height * u'\r\n')
    echo(term.move(0, 0))
    city = term.bold(todays.get('City', u''))
    state = todays.get('State', u'')
    if state:
        state = u', {}'.format(term.bold(state))
    dotdot = term.bold_black('...')
    echo(u'At {city}{state} {dotdot}'.format(city=city,
                                             state=state,
                                             dotdot=dotdot))

    bottom = 3
    if forecast:
        end = (term.width - panel_width)
        step = panel_width
        for idx, column in enumerate(range(0, end, step)):
            try:
                day = forecast[idx]
            except IndexError:
                break
            bottom = max(display_panel(day, column, centigrade), bottom)

    timenow = time.strftime(
        '%I:%M%p', time.strptime(todays.get('Time', '00:00'), '%H:%M'))
    temp, deg_conv = temp_conv(todays.get('Temperature', ''), centigrade)
    real_temp, deg_conv = temp_conv(todays.get('RealFeel', ''), centigrade)
    speed, spd_conv = speed_conv(todays.get('WindSpeed', ''), centigrade)
    degree = '\xf8'.decode('cp437_art')

    current_0 = u'Current conditions at {timenow}'.format(timenow=timenow)
    current_1 = u'{0}'.format(todays.get('WeatherText', ''))
    current_2 = u'Temperature is {temp}{degree}{deg_conv}'.format(
        temp=temp, degree=degree, deg_conv=deg_conv)
    current_3 = u'' if real_temp == temp else (
        u'(feels like {real_temp}{degree}{deg_conv})'.format(
            real_temp=real_temp, degree=degree, deg_conv=deg_conv))
    current_4 = u'Winds {speed}{spd_conv} {wind}'.format(speed=speed,
                                                         spd_conv=spd_conv,
                                                         wind=todays.get(
                                                             'WindDirection',
                                                             ''))
    current_5 = u'Humidity of {0}'.format(todays.get('Humidity', ''))

    wrapped = textwrap.wrap(
        u'{0}: {1}. {2} {3}, {4}, {5}.'.format(current_0, current_1, current_2,
                                               current_3, current_4,
                                               current_5),
        min(term.width - panel_width - 2, 40))
    row_num = 0

    art = get_icon(todays)
    joined_art_conditions = list(itertools.izip_longest(wrapped, art))
    last_line = lambda row_num: row_num == len(joined_art_conditions) - 1
    for row_num, (row_txt, art_txt) in enumerate(joined_art_conditions):
        echo(term.move(bottom + next_margin + row_num, 1))
        echo(art_txt)
        if not row_txt and not last_line(row_num):
            echo(u'\r\n')
        elif row_txt:
            echo(term.move(bottom + next_margin + row_num, panel_width + 5))
            echo(term.normal)
            echo(row_txt)
Пример #35
0
def main():
    """ Main menu entry point. """
    import os, random, time
    from x84.bbs import showart
    session, term = getsession(), getterminal()
    global menutoggle
    global arttoggle
    global bgtoggle

    text, width, height, dirty = u'', -1, -1, 2
    menu_items = get_menu_items(session)
    colors = {}
    if colored_menu_items:
       colors['backlight'] = getattr(term, color_backlight)
       colors['highlight'] = getattr(term, color_highlight)
       colors['lowlight'] = getattr(term, color_lowlight)
    editor = get_line_editor(term, menu_items)
    menumode = False
    tallmode = False
    widemode = False

    if term.width >= 132:
        widemode = True
    if term.height >= 43:
        tallmode = True

    #if session.user['bg'] is None:
    randombgset()
    starttime = time.time()
    while True:
        if dirty  > 1:
            # set syncterm font, if any
            if syncterm_font and term.kind.startswith('ansi'):
                echo(syncterm_setfont(syncterm_font))
        if dirty == 2:
	    menutoggle, arttoggle, bgtoggle = True, True, True
        if dirty:
            session.activity = 'main menu'
	    if width != term.width or height != term.height:
                width, height = term.width, term.height
            renderscreen(menutoggle, arttoggle, bgtoggle)
            echo(term.move(term.height, 2))
            echo(u''.join((text,
	    display_prompt(term, colors),
	    editor.refresh()+term.normal)))
            dirty = 0

        event, data = session.read_events(('input', 'refresh'), 0.1)
        if event == 'refresh':
            dirty = True
            continue

        elif event == 'input':
            session.buffer_input(data, pushback=True)

            # we must loop over inkey(0), we received a 'data'
            # event, though there may be many keystrokes awaiting for our
            # decoding -- or none at all (multibyte sequence not yet complete).
            inp = term.inkey(0)
            while inp:
                if inp == u'*':
                    menutoggle = not menutoggle
                    dirty = True
                    break
                if inp.code == term.KEY_TAB:
                    starttime = time.time()
		    randombgset()
                    dirty = True
                    break
                if inp.code == term.KEY_ENTER:
                    # find matching menu item,
                    for item in menu_items:
                        if item.inp_key == editor.content.strip():
                            echo(term.normal + u'\r\n')
                            gosub(item.script, *item.args, **item.kwargs)
                            editor.content = u''
                            dirty = 3
                            break
                    else:
                        if editor.content:
                            # command not found, clear prompt.
                            echo(u''.join((
                                (u'\b' * len(editor.content)),
                                (u' ' * len(editor.content)),
                                (u'\b' * len(editor.content)),)))
                            editor.content = u''
                            echo(editor.refresh()+term.normal)
                elif inp.is_sequence:
                    echo(editor.process_keystroke(inp.code))
                else:
                    echo(editor.process_keystroke(inp))
                inp = term.inkey(0)
        if time.time() - starttime > 1800:
            dirty = True
            starttime = time.time()
            randombgset()
            continue
Пример #36
0
def main():
    session = getsession()
    session.activity = u'hanging out in voting script'
    term = getterminal()
    echo(syncterm_setfont('topaz'))

    db = DBProxy(databasename)
    if 'questions' not in db:
        generate_database()

    while True:
        # clears the screen and displays the vote art header
        echo(term.clear())
        for line in showart(
                os.path.join(os.path.dirname(__file__), 'art', 'vote.ans'), 'cp437'):
            echo(term.cyan + term.move_x(max(0, (term.width / 2) - 40)) + line)

        if 'sysop' in session.user.groups:
            spacing = 1
        else:
            spacing = 7
            echo(' ')
        echo(term.magenta(u'\n (') + term.cyan(u'r') + term.magenta(u')') +
             term.white(u'esults') + ' ' * spacing +
             term.magenta(u'(') + term.cyan(u'v') + term.magenta(u')') +
             term.white(u'ote on a question') + u' ' * spacing +
             term.magenta(u'(') + term.cyan(u'a') + term.magenta(u')') +
             term.white(u'dd a new question') + u' ' * spacing)
        if 'sysop' in session.user.groups:
            echo(term.magenta(u'(') + term.cyan(u'd') + term.magenta(u')') +
                 term.white(u'elete a question') + u' ' * spacing)
        echo(term.magenta(u'(') + term.cyan(u'q') + term.magenta(u')') + term.white(u'uit') +
             term.magenta(u'\r\n\r\nx/84 voting booth command: '))
        le = LineEditor(10)
        le.colors['highlight'] = term.cyan
        inp = le.read()
        # makes the input indifferent to wheter you used lower case when typing
        # in a command or not..
        inp = (inp or u'').lower()

        if 'sysop' in session.user.groups and inp == u'd':
            while True:
                questionnumber = query_question()
                if questionnumber == -1:
                    break
                delete_question(questionnumber)
        elif inp == u'r':
            while True:
                questionnumber = query_question()
                if questionnumber == -1:
                    break
                list_results(questionnumber)
        elif inp == u'v':
            while True:
                questionnumber = query_question()
                if questionnumber == -1:
                    break
                vote(questionnumber)
        elif inp == u'a':
            add_question()
        elif inp == u'q':
            return
        else:
            # if no valid key is pressed then do some ami/x esthetics.
            echo(term.red(u'\r\nNo such command. Try again.\r\n'))
            waitprompt(term)
Пример #37
0
def main(quick=False):
    """ Main procedure. """

    session, term = getsession(), getterminal()
    session.activity = 'checking for new messages'

    # set syncterm font, if any
    if term.kind.startswith('ansi'):
        echo(syncterm_setfont(syncterm_font))

    colors = dict(
        highlight=lambda txt: txt,
        lowlight=lambda txt: txt,
        backlight=lambda txt: txt,
        text=lambda txt: txt
    ) if not colored_menu_items else dict(
        highlight=getattr(term, color_highlight),
        lowlight=getattr(term, color_lowlight),
        backlight=getattr(term, color_backlight),
        text=getattr(term, color_text))

    yloc = top_margin = 0
    subscription = session.user.get('msg_subscription', [])
    dirty = 2

    while True:
        if dirty == 2:
            # display header art,
            yloc = display_banner(art_file, encoding=art_encoding, center=True)
            xloc = max(0, (term.width // 2) - 40)
            echo(u'\r\n')
            top_margin = yloc = (yloc + 1)

        elif dirty:
            echo(term.move(top_margin, 0) + term.normal + term.clear_eos)
            echo(term.move(top_margin, xloc))

        if dirty:

            if not subscription:
                # prompt the user for a tag subscription, and loop
                # back again when completed to re-draw and show new messages.
                subscription = session.user['msg_subscription'] = (
                    prompt_subscription(
                        session=session, term=term, yloc=top_margin,
                        subscription=subscription, colors=colors))
                continue

            messages, messages_bytags = get_messages_by_subscription(
                session, subscription)

            # When quick login ('y') selected in top.py, return immediately
            # when no new messages are matched any longer.
            if quick and not messages['new']:
                echo(term.move_x(xloc) + u'\r\nNo new messages.\r\n')
                return waitprompt(term)

            txt = describe_message_area(
                term=term, subscription=subscription,
                messages_bytags=messages_bytags, colors=colors)

            yloc = top_margin + show_description(
                term=term, description=txt, color=None,
                subsequent_indent=' ' * len('message area: '))

            echo(render_menu_entries(
                term=term, top_margin=yloc,
                menu_items=get_menu(messages),
                colors=colors, max_cols=2))
            echo(display_prompt(term=term, colors=colors))
            echo(colors['backlight'](u' \b'))
            dirty = False

        event, data = session.read_events(('refresh', 'newmsg', 'input'))

        if event == 'refresh':
            # screen resized, redraw.
            dirty = 2
            continue

        elif event == 'newmsg':
            # When a new message is sent, 'newmsg' event is broadcasted.
            session.flush_event('newmsg')
            nxt_msgs, nxt_bytags = get_messages_by_subscription(
                session, subscription)
            if nxt_msgs['new'] - messages['new']:
                # beep and re-display when a new message has arrived.
                echo(u'\b')
                messages, messages_bytags = nxt_msgs, nxt_bytags
                dirty = True
                continue

        elif event == 'input':
            # on input, block until carriage return
            session.buffer_input(data, pushback=True)
            given_inp = LineEditor(
                1, colors={'highlight': colors['backlight']}
            ).read()

            if given_inp is None:
                # escape/cancel
                continue

            inp = given_inp.strip()
            if inp.lower() in (u'n', 'a', 'v'):
                # read new/all/private messages
                message_indices = sorted(list(
                    {'n': messages['new'],
                     'a': messages['all'],
                     'v': messages['private'],
                     }[inp.lower()]))
                if message_indices:
                    dirty = 2
                    read_messages(session=session, term=term,
                                  message_indices=message_indices,
                                  colors=colors)
            elif inp.lower() == u'm' and messages['new']:
                # mark all messages as read
                dirty = 1
                do_mark_as_read(session, messages['new'])
            elif inp.lower() in (u'p', u'w'):
                # write new public/private message
                dirty = 2
                public = bool(inp.lower() == u'p')
                msg = Msg()
                if (
                        not prompt_recipient(
                            term=term, msg=msg,
                            colors=colors, public=public
                        ) or not prompt_subject(
                            term=term, msg=msg, colors=colors
                        ) or not prompt_body(
                            term=term, msg=msg, colors=colors
                        ) or not prompt_tags(
                            session=session, term=term, msg=msg,
                            colors=colors, public=public
                        )):
                    continue
                do_send_message(session=session, term=term,
                                msg=msg, colors=colors)
            elif inp.lower() == u'c':
                # prompt for new tag subscription (at next loop)
                subscription = []
                dirty = 1
            elif inp.lower() == u'?':
                # help
                echo(term.move(top_margin, 0) + term.clear_eos)
                do_describe_message_system(term, colors)
                waitprompt(term)
                dirty = 1
            elif inp.lower() == u'q':
                return
            if given_inp:
                # clear out line editor prompt
                echo(colors['backlight'](u'\b \b'))
Пример #38
0
def play():
    import time
    from random import randint
    import os
    from x84.bbs import getterminal, from_cp437, AnsiWindow, syncterm_setfont
    from x84.bbs import echo as echo_unbuffered
    term = getterminal()
    field = []
    global charcache
    charcache = u''
    field_width = 10
    field_height = 20
    # Access scheme looks like this:
    #   layout[p][r][ypox][xpos]
    # layoutcolor = [ 7,2,3,4,4,6,7 ]
    layout = [
        #  ##
        #  ##
        [
            [
                [1, 1, ],
                [1, 1, ],
            ],
        ],
        #  #
        #  #
        #  #
        #  #
        [
            [
                [0, 1, 0, 0],
                [0, 1, 0, 0],
                [0, 1, 0, 0],
                [0, 1, 0, 0],
            ],
            [
                [0, 0, 0, 0],
                [1, 1, 1, 1],
                [0, 0, 0, 0],
                [0, 0, 0, 0],
            ]
        ],
        #  ###
        #   #
        [
            [
                [0, 0, 0],
                [1, 1, 1],
                [0, 1, 0],
            ],
            [
                [0, 1, 0],
                [0, 1, 1],
                [0, 1, 0],
            ],
            [
                [0, 1, 0],
                [1, 1, 1],
                [0, 0, 0],
            ],
            [
                [0, 1, 0],
                [1, 1, 0],
                [0, 1, 0],
            ],
        ],
        #  #
        #  #
        #  ##
        [
            [
                [0, 1, 0],
                [0, 1, 0],
                [0, 1, 1],
            ],
            [
                [0, 0, 1],
                [1, 1, 1],
                [0, 0, 0],
            ],
            [
                [1, 1, 0],
                [0, 1, 0],
                [0, 1, 0],
            ],
            [
                [0, 0, 0],
                [1, 1, 1],
                [1, 0, 0],
            ],
        ],
        #   #
        #   #
        #  ##
        [
            [
                [0, 1, 0],
                [0, 1, 0],
                [1, 1, 0],
            ],
            [
                [0, 0, 0],
                [1, 1, 1],
                [0, 0, 1],
            ],
            [
                [0, 1, 1],
                [0, 1, 0],
                [0, 1, 0],
            ],
            [
                [1, 0, 0],
                [1, 1, 1],
                [0, 0, 0],
            ],
        ],
        #  ##
        #   ##
        [
            [
                [0, 1, 0],
                [1, 1, 0],
                [1, 0, 0],
            ],
            [
                [0, 0, 0],
                [1, 1, 0],
                [0, 1, 1],
            ],
        ],
        #   ##
        #  ##
        [
            [
                [0, 1, 0],
                [0, 1, 1],
                [0, 0, 1],
            ],
            [
                [0, 0, 0],
                [0, 1, 1],
                [1, 1, 0],
            ],
        ],
    ]

    fieldx1 = 32
    fieldy1 = 10
    scorex1 = 11
    scorey1 = 11

    class RectRedraw:
        x1 = None
        y1 = None
        x2 = None
        y2 = None

        def max(r, val, valmax):
            if val > valmax:
                return valmax
            return val

        def min(r, val, valmin):
            if val < valmin:
                return valmin
            return val

        def merge(r, x1, y1, x2, y2):
            if r.x1 is None or r.x1 > x1:
                r.x1 = r.min(x1, 0)
            if r.y1 is None or r.y1 > y1:
                r.y1 = r.min(y1, 0)
            if r.x2 is None or r.x2 < x2:
                r.x2 = r.max(x2, field_width)
            if r.y2 is None or r.y2 < y2:
                r.y2 = r.max(y2, field_height)
            # print r.x1,r.y1,r.x2,r.y2

        def clean(r):
            r.x1 = None
            r.y1 = None
            r.x2 = None
            r.y2 = None
    rr = RectRedraw()
    for _ in range(field_height):
        field.append([0] * field_width)

    def echo(s):
        global charcache
        charcache += s
    assert term.height > (field_height + 1)
    echo_unbuffered(u''.join((
        u'\r\n\r\n',
        u'REAdY YOUR tERMiNAl %s ' % (term.bold_blue('(!)'),),
        u'\r\n\r\n',
        u'%s PRESS ANY kEY' % (term.bold_black('...'),),
    )))

    term.inkey()

    # set syncterm font to cp437
    if term.kind.startswith('ansi'):
        echo_unbuffered(syncterm_setfont('cp437'))
    artfile = os.path.join(os.path.dirname(__file__), 'art', 'tetris.ans')
    echo_unbuffered(u'\r\n' * term.height)  # cls
    if os.path.exists(artfile):
        echo_unbuffered(from_cp437(open(artfile).read()).rstrip())

    def gotoxy(x, y):
        echo(term.move(y, x))

    def plotblock(color, lastcolor):
        if color:
            c = u'\u2588\u2588'  # '\xDB\xDB'
        else:  # both empty
            c = '  '
            color = 0
        # Output optimization
        if color % 8 == 0:
            color = color / 8
        if color == lastcolor:
            echo(c)
        else:
            if color:
                fg = str(30 + color % 8)
            else:
                fg = '37'
            if color >= 8:
                bg = ';%d' % (40 + color / 8)
            else:
                bg = ''
            echo('\x1b[0;' + fg + bg + 'm')
            echo(c)
            lastcolor = color
        return lastcolor

    def drawfield():
        lastcolor = ''
        for y in range(0, field_height, 2):
            # gotoxy(field_width,2+y/2)
            gotoxy(fieldx1 + 2, fieldy1 + 1 + y / 2)
            # Which block to show, full, half-up, half-down or empty.
            for x in range(field_width):
                color = field[y][x] + field[y + 1][x] * 8
                if field[y][x] and field[y + 1][x]:
                    c = u'\u2588'  # '\xDB'
                    if field[y][x] == field[y + 1][x]:
                        color = color % 8
                    else:
                        c = u'\u2580'  # '\xDF'
                elif field[y][x] and not field[y + 1][x]:
                    c = u'\u2580'  # '\xDF'
                elif not field[y][x] and field[y + 1][x]:
                    c = u'\u2584'  # '\xDC'
                else:  # both empty
                    c = ' '
                # Output optimization
                if color % 8 == 0:
                    color = color / 8
                if color == lastcolor:
                    echo(c)
                else:
                    if color:
                        fg = str(30 + color % 8)
                    else:
                        fg = '37'
                    if color >= 8:
                        bg = ';%d' % (40 + color / 8)
                    else:
                        bg = ''
                    echo('\x1b[0;' + fg + bg + 'm')
                    echo(c)
                    lastcolor = color
        echo(term.normal)

    layoutcolor = [7, 2, 7, 6, 3, 6, 3]
    # p    = -1  # Current piece type
    nextpiece = randint(0, len(layout) - 1)
    p = randint(0, len(layout) - 1)
    p = 1
    r = 0   # Current rotation
    xpos = 4   # X position
    # ypos = -2  # Y position
    ypos = -len(layout[p][0])
    level = 1
    score = 0
    lines = 0

    def flush():
        global charcache
        echo_unbuffered(charcache)
        charcache = u''

    def fillpiece(x, y, p, r, value):
        row = 0
        for line in layout[p][r]:
            col = 0
            for c in line:
                if c and (y + row) >= 0:
                    field[y + row][x + col] = value
                col += 1
            row += 1

    def showpiece(x, y, p, r):
        fillpiece(x, y, p, r, layoutcolor[p])

    def hidepiece():
        fillpiece(xpos, ypos, p, r, 0)

    def testpiece(x, y, newr):
        hidepiece()
        # Space at the new location?
        row = 0
        for line in layout[p][newr]:
            col = 0
            for c in line:
                try:
                    if c:
                        if ((y + row) >= 0 and field[y + row][x + col]
                                or (x + col) < 0 or (x + col) > 9):
                            return 0
                except IndexError:
                    return 0
                col += 1
            row += 1
        # Movement possible
        return 1

    def movepiece(x, y, newr):
        if testpiece(x, y, newr):
            # Build redraw rectangle
            rr.merge(xpos, ypos,
                     xpos + len(layout[p][0][0]), ypos + len(layout[p][0]))
            rr.merge(x, y,
                     x + len(layout[p][0][0]), y + len(layout[p][0]))
            showpiece(x, y, p, newr)
            return (x, y, newr, 1)
        else:
            showpiece(xpos, ypos, p, r)
            return (xpos, ypos, r, 0)

    def shownext(p):
        r = 0
        for y in range(4):
            gotoxy(26, 18 + y)
            echo(u' ' * 4)

        echo(term.color(layoutcolor[p]))

        yoffset = int(len(layout[p][r][0]) < 4)
        xoffset = int(len(layout[p][r]) < 3)
        for y in range(len(layout[p][r])):
            for x in range(len(layout[p][r][y])):
                val = layout[p][r][y][x]
                if val:
                    gotoxy(26 + x + xoffset, 18 + y + yoffset)
                    echo(u'\u2588\u2588')

    def drawstats():
        echo(term.move(scorey1, scorex1) + '%d' % level)
        echo(term.move(scorey1 + 2, scorex1) + '%d' % lines)
        echo(term.move(scorey1 + 3, scorex1) + '%d' % score)

    drawstats()
    ticksize = 0.4
    nexttick = time.time() + ticksize
    showpiece(xpos, ypos, p, r)
    gotoxy(26, 17)
    echo(term.blue_reverse('next'))
    shownext(nextpiece)

    # Full redraw first frame
    rr.merge(0, 0, field_width, field_height)

    buf = ''
    while True:
        drawfield()
        # gotoxy(0,0)
        # echo('\x1b[37mx: %d, y: %d, p: %d         '%(xpos,ypos,p))
        slice = nexttick - time.time()
        if slice < 0:
            slice = 0
        echo(buf)
        buf = ''
        flush()
        key = term.inkey(slice + 0.01)
        now = time.time()
        # hidepiece()
        if key is not None:
            if key in (u'q', u'Q'):
                return (0, 0, 0)
            elif key.code == term.KEY_LEFT or key == u'h':
                xpos, ypos, r, m = movepiece(xpos - 1, ypos, r)
            elif key.code == term.KEY_RIGHT or key == u'l':
                xpos, ypos, r, m = movepiece(xpos + 1, ypos, r)
            elif key.code == term.KEY_UP or key == u'k':
                xpos, ypos, r, m = movepiece(
                    xpos, ypos, (r + 1) % len(layout[p]))
            elif key.code == term.KEY_DOWN or key == u'j':
                xpos, ypos, r, m = movepiece(xpos, ypos + 1, r)
            elif key in (' ',):
                m = True
                c = 0
                while m:
                    xpos, ypos, r, m = movepiece(xpos, ypos + 1, r)
                    if m:
                        c += 1
                if c:
                    nexttick = time.time() + ticksize
        # New tick?
        if now > nexttick:
            nexttick += ticksize
            # Move down piece
            xpos, ypos, r, moved = movepiece(xpos, ypos + 1, r)
            # Piece has touched down?
            if not moved:
                # Is the player dead?
                if ypos <= -len(layout[p][0]):
                    death_win = AnsiWindow(height=6, width=40,
                                           yloc=fieldy1 + 10 / 2, xloc=fieldx1 - 11)
                    death_win.colors['border'] = term.bold_black
                    echo_unbuffered(death_win.clear() + death_win.border())
                    echo_unbuffered(
                        term.move(fieldy1 + 10 / 2 + 1, fieldx1 - 11))
                    echo_unbuffered((
                                    u'!! gAME OVeR!! Score was: %i' % (score,)).center(40))
                    echo_unbuffered(
                        term.move(fieldy1 + 10 / 2 + 3, fieldx1 - 11))
                    echo_unbuffered(u'press RETURN'.center(40))
                    while True:
                        inp = term.inkey()
                        if inp.code == term.KEY_ENTER:
                            break
                    return (score, level, lines)

                # Any complete rows to remove?
                complete = []
                for y in range(field_height):
                    x = 0
                    while x < field_width:
                        if field[y][x] == 0:
                            break
                        x += 1
                    if x == field_width:
                        complete.append(y)
                if len(complete) > 0:
                    # Add score
                    lines += len(complete)
                    score += len(complete) * len(complete) * 100
                    # Shrink field
                    for line in complete:
                        del field[line]
                        field.insert(0, [0] * field_width)

                    if lines >= level * 10:
                        level += 1
                        ticksize = 0.4 - level * 0.02
                    drawstats()

                    # Redraw complete field
                    rr.merge(0, 0, field_width, field_height)

                # Time for a new piece
                p = nextpiece
                nextpiece = randint(0, len(layout) - 1)
                r = 0
                xpos = 4
                ypos = -len(layout[p][0])
                showpiece(xpos, ypos, p, r)
                shownext(nextpiece)
Пример #39
0
def main():
    session = getsession()
    session.activity = u'hanging out in voting script'
    term = getterminal()
    echo(term.clear + syncterm_setfont('topaz'))

    db = DBProxy(databasename)
    if not 'questions' in db:
        generate_database()

    while True:
        # clears the screen and displays the vote art header
        echo(term.clear())
        for line in showart(
                os.path.join(os.path.dirname(__file__), 'art', 'vote.ans'), 'cp437'):
            echo(term.cyan + term.move_x(max(0, (term.width / 2) - 40)) + line)

        if 'sysop' in session.user.groups:
            spacing = 1
        else:
            spacing = 7
            echo(' ')
        echo(term.magenta + '\n (' + term.cyan + 'r' + term.magenta + ')' +
             term.white + 'esults' + ' ' * spacing)
        echo(term.magenta + '(' + term.cyan + 'v' + term.magenta + ')' +
             term.white + 'ote on a question' + ' ' * spacing)
        echo(term.magenta + '(' + term.cyan + 'a' + term.magenta + ')' +
             term.white + 'dd a new question' + ' ' * spacing)
        if 'sysop' in session.user.groups:
            echo(term.magenta + '(' + term.cyan + 'd' + term.magenta + ')' +
                 term.white + 'elete a question' + ' ' * spacing)
        echo(
            term.magenta + '(' + term.cyan + 'q' + term.magenta + ')' + term.white + 'uit')
        echo(term.magenta + '\r\n\r\n\r\nx/84 voting booth command: ')
        le = LineEditor(30)
        le.colors['highlight'] = term.cyan
        inp = le.read()
        # makes the input indifferent to wheter you used lower case when typing
        # in a command or not..
        inp = inp.lower()

        if 'sysop' in session.user.groups and inp == 'd':
            while True:
                questionnumber = query_question()
                if questionnumber == 999:
                    break
                delete_question(questionnumber)
        elif inp == 'r':
            while True:
                questionnumber = query_question()
                if questionnumber == 999:
                    break
                list_results(questionnumber)
        elif inp == 'v':
            while True:
                questionnumber = query_question()
                if questionnumber == 999:
                    break
                vote(questionnumber)
        elif inp == 'a':
            add_question()
        elif inp == 'q':
            return
        else:
            # if no valid key is pressed then do some ami/x esthetics.
            echo(term.red + '\r\nNo such command. Try again.\r\n')
            waitprompt()
Пример #40
0
Файл: ol.py Проект: hick/x84
def main():
    """ Main procedure. """
    # pylint: disable=R0912
    #        Too many branches
    import logging
    from x84.bbs import getsession, getterminal, ini, echo, getch, syncterm_setfont
    session, term = getsession(), getterminal()
    pager, selector = get_pager(), get_selector()
    log = logging.getLogger(__name__)

    thread = None
    if ini.CFG.has_section('bbs-scene'):
        log.info('starting bbs-scene.org oneliners thread...')
        thread = FetchUpdates()
        thread.start()
    elif ini.CFG.has_section('shroo-ms'):
        log.info('starting shroo.ms oneliners thread...')
        thread = FetchUpdatesShrooMs()
        thread.start()
    else:
        log.info('using built-in oneliners...')

    if thread is not None:
        session.activity = u'one-liners [%s]' % (thread.ident,)
    else:
        session.activity = u'one-liners'

    # flag a pager update,
    dirty = True
    # force screen clear on first loop,
    session.buffer_event('refresh', ('init',))

    # makes syncterm switch back to the amiga topaz font
    if term._kind.startswith('ansi'):
        echo(syncterm_setfont('topaz'))

    while True:
        # 1. calculate and redraw screen,
        # or enter dumb pager mode (no scrolling)
        if session.poll_event('refresh'):
            pager, selector = get_pager(), get_selector(selector.selection)
            echo(banner())
            dirty = True
        if chk_thread(thread):
            thread = None
        while session.read_event('oneliner_update', 0.15):
            dirty = True
        if dirty and (not session.user.get('expert', False)
                      and term.width >= 78 and term.height >= 20):
            # smart terminal
            redraw(pager, selector)
            dirty = False
        elif dirty:
            # dumb terminal
            if thread is not None:
                wait_for(thread)
            if chk_thread(thread):
                thread = None
            echo(u'\r\n\r\n')
            return dummy_pager()

        # 2. detect and process keyboard input,
        inp = getch(1)
        if inp is not None:
            # input is multiplexed to both interfaces
            echo(pager.process_keystroke(inp))
            echo(selector.process_keystroke(inp))

            # selected 'yes' & return, 'say something'
            if (selector.selected and selector.selection == selector.left):
                # re-assign thread so that it is checked for updates
                thread = saysomething(dumb=False)
                # undo 'selected' state of yes/no bar,
                selector.selected = False

            # quit 'q', or selected 'no' & return
            elif (selector.selected and selector.selection == selector.right
                    or pager.quit):
                # makes syncterm switch back to the cp437 font
                if term._kind.startswith('ansi'):
                    echo(syncterm_setfont('cp437'))

                return
Пример #41
0
def main(save_key=None, continue_draft=False):
    """
    Main Editor procedure.

    When argument ``save_key`` is non-None, the result is saved
    to the user attribute of the same name.  When unset, the
    contents are returned to the caller.

    When argument ``continue_draft`` is non-None, the editor
    continues a previously saved draft, whose contents is its
    value.
    """
    # pylint: disable=R0914,R0912,R0915
    #         Too many local variables
    #         Too many branches
    #         Too many statements
    session, term = getsession(), getterminal()

    # set syncterm font, if any
    if term.kind.startswith('ansi'):
        echo(syncterm_setfont(syncterm_font))

    movement = (term.KEY_UP, term.KEY_DOWN, term.KEY_NPAGE,
                term.KEY_PPAGE, term.KEY_HOME, term.KEY_END,
                u'\r', term.KEY_ENTER)
    keyset = {'edit': ('\r', '\n'),
              'command': (unichr(27),),
              'kill': (u'K',),
              'undo': (u'u', 'U',),
              'goto': (u'G',),
              'insert': (u'I',),
              'insert-before': (u'O',),
              'insert-after': (u'o',),
              'join': (u'J',),
              'rubout': (unichr(8), unichr(127), unichr(23)),
              }

    def merge():
        """
        Merges line editor content as a replacement for the currently
        selected lightbar row. Returns True if text inserted caused
        additional rows to be appended, which is meaningful in a window
        refresh context.
        """
        lightbar.content[lightbar.index] = [
            lightbar.selection[0],
            softwrap_join(wrap_rstrip(lneditor.content))
            + HARDWRAP]
        prior_length = len(lightbar.content)
        prior_position = lightbar.position
        set_lbcontent(lightbar, get_lbcontent(lightbar))
        if len(lightbar.content) - prior_length == 0:
            echo(lightbar.refresh_row(prior_position[0]))
            return False
        while len(lightbar.content) - prior_length > 0:
            # hidden move-down for each appended line
            lightbar.move_down()
            prior_length += 1
        return True

    def statusline(lightbar):
        """
        Display status line and command help on ``lightbar`` borders
        """
        lightbar.colors['border'] = term.red if edit else term.yellow
        keyset_cmd = u''
        if not edit:
            keyset_cmd = u''.join((
                term.yellow(u'-( '),
                term.yellow_underline(u'S'), u':', term.bold(u'ave'),
                u' ',
                term.yellow_underline(u'A'), u':', term.bold(u'bort'),
                u' ',
                term.yellow_underline(u'?'), u':', term.bold(u'help'),
                term.yellow(u' )-'),))
            keyset_xpos = max(0, lightbar.width -
                              (term.length(keyset_cmd) + 3))
            keyset_cmd = lightbar.pos(lightbar.yloc + lightbar.height - 1,
                                      keyset_xpos
                                      ) + keyset_cmd
        return u''.join((
            lightbar.border(),
            keyset_cmd,
            lightbar.pos(lightbar.yloc + lightbar.height - 1,
                         lightbar.xpadding),
            u''.join((
                term.red(u'-[ '),
                u'EditiNG liNE ',
                term.reverse_red('%d' % (lightbar.index + 1,)),
                term.red(u' ]-'),)) if edit else u''.join((
                    term.yellow(u'-( '),
                    u'liNE ',
                    term.yellow('%d/%d ' % (
                        lightbar.index + 1,
                        len(lightbar.content),)),
                    '%3d%% ' % (
                        int((float(lightbar.index + 1)
                             / max(1, len(lightbar.content))) * 100)),
                    term.yellow(u' )-'),)),
            lightbar.title(u''.join((
                term.red('-] '),
                term.bold(u'Escape'),
                u':', term.bold_red(u'command mode'),
                term.red(' [-'),)
            ) if edit else u''.join((
                term.yellow('-( '),
                term.bold(u'Enter'),
                u':', term.bold_yellow(u'edit mode'),
                term.yellow(' )-'),))),
            lightbar.fixate(),
        ))

    def redraw_lneditor(lightbar, lneditor):
        """
        Return ucs suitable for refreshing line editor.
        """
        return ''.join((
            term.normal,
            statusline(lightbar),
            lneditor.border(),
            lneditor.refresh()))

    def get_ui(ucs, lightbar=None):
        """
        Returns Lightbar and ScrollingEditor instance.
        """
        lbr = get_lightbar(ucs)
        lbr.position = (lightbar.position
                        if lightbar is not None else (0, 0))
        lne = get_lneditor(lbr)
        return lbr, lne

    def banner():
        """
        Returns string suitable clearing screen
        """
        return u''.join((
            term.move(0, 0),
            term.normal,
            term.clear))

    def redraw(lightbar, lneditor):
        """
        Returns ucs suitable for redrawing Lightbar
        and ScrollingEditor UI elements.
        """
        return u''.join((
            term.normal,
            redraw_lightbar(lightbar),
            redraw_lneditor(lightbar, lneditor) if edit else u'',
        ))

    def redraw_lightbar(lightbar):
        """ Returns ucs suitable for redrawing Lightbar. """
        return u''.join((
            statusline(lightbar),
            lightbar.refresh(),))

    def resize(lightbar):
        """ Resize Lightbar. """
        if edit:
            # always re-merge current line on resize,
            merge()
        lbr, lne = get_ui(get_lbcontent(lightbar), lightbar)
        echo(redraw(lbr, lne))
        return lbr, lne

    if continue_draft:
        ucs = continue_draft
    else:
        ucs = u''
    lightbar, lneditor = get_ui(ucs, None)
    echo(banner())
    dirty = True
    edit = False
    digbuf, num_repeat = u'', -1
    count_repeat = lambda: range(max(num_repeat, 1))
    while True:
        # poll for refresh
        if session.poll_event('refresh'):
            echo(banner())
            lightbar, lneditor = resize(lightbar)
            dirty = True
        if dirty:
            session.activity = 'editing %s' % (save_key,)
            echo(redraw(lightbar, lneditor))
            dirty = False

        # poll for input
        inp = term.inkey()

        # buffer keystrokes for repeat
        if (not edit and inp and inp.isdigit()):
            digbuf += inp
            if len(digbuf) > 10:
                # overflow,
                echo(u'\a')
                digbuf = inp
            try:
                num_repeat = int(digbuf)
            except ValueError:
                try:
                    num_repeat = int(inp)
                except ValueError:
                    pass
            continue
        else:
            digbuf = u''

        # toggle edit mode,
        if (inp in keyset['command']) or not edit and inp in keyset['edit']:

            edit = not edit  # toggle

            if not edit:
                # switched to command mode, merge our lines

                echo(term.normal + lneditor.erase_border())

                merge()
                lightbar.colors['highlight'] = term.yellow_reverse

            else:
                # switched to edit mode, save draft,
                # instantiate new line editor
                save_draft(save_key, get_lbcontent(lightbar))
                lneditor = get_lneditor(lightbar)
                lightbar.colors['highlight'] = term.red_reverse
            dirty = True

        # command mode, kill line
        elif not edit and inp in keyset['kill']:
            # when 'killing' a line, make accomidations to clear
            # bottom-most row, otherwise a ghosting effect occurs
            for _ in count_repeat():
                del lightbar.content[lightbar.index]
                set_lbcontent(lightbar, get_lbcontent(lightbar))
            if lightbar.visible_bottom > len(lightbar.content):
                echo(lightbar.refresh_row(lightbar.visible_bottom + 1))
            else:
                dirty = True
            save_draft(save_key, get_lbcontent(lightbar))

        # command mode, insert line
        elif not edit and inp in keyset['insert']:
            for _ in count_repeat():
                lightbar.content.insert(lightbar.index,
                                        (lightbar.index, HARDWRAP,))
                set_lbcontent(lightbar, get_lbcontent(lightbar))
            save_draft(save_key, get_lbcontent(lightbar))
            dirty = True

        # command mode; goto line
        elif not edit and inp in keyset['goto']:
            if num_repeat == -1:
                # 'G' alone goes to end of file,
                num_repeat = len(lightbar.content)
            echo(lightbar.goto((num_repeat or 1) - 1))
            echo(statusline(lightbar))

        # command mode; insert-before (switch to edit mode)
        elif not edit and inp in keyset['insert-before']:
            lightbar.content.insert(lightbar.index,
                                    (lightbar.index, HARDWRAP,))
            set_lbcontent(lightbar, get_lbcontent(lightbar))
            edit = dirty = True
            # switched to edit mode, save draft,
            # instantiate new line editor
            lightbar.colors['highlight'] = term.red_reverse
            lneditor = get_lneditor(lightbar)
            save_draft(save_key, get_lbcontent(lightbar))

        # command mode; insert-after (switch to edit mode)
        elif not edit and inp in keyset['insert-after']:
            lightbar.content.insert(lightbar.index + 1,
                                    (lightbar.index + 1, HARDWRAP,))
            set_lbcontent(lightbar, get_lbcontent(lightbar))
            edit = dirty = True
            # switched to edit mode, save draft,
            # instantiate new line editor
            lightbar.colors['highlight'] = term.red_reverse
            lightbar.move_down()
            lneditor = get_lneditor(lightbar)
            save_draft(save_key, get_lbcontent(lightbar))

        # command mode, undo
        elif not edit and inp in keyset['undo']:
            for _ in count_repeat():
                if len(UNDO):
                    set_lbcontent(lightbar, UNDO.pop())
                    dirty = True
                else:
                    echo(u'\a')
                    break

        # command mode, join line
        elif not edit and inp in keyset['join']:
            for _ in count_repeat():
                if lightbar.index + 1 < len(lightbar.content):
                    idx = lightbar.index
                    lightbar.content[idx] = (
                        idx, WHITESPACE.join((
                            lightbar.content[idx][1].rstrip(),
                            lightbar.content[idx + 1][1].lstrip(),))
                    )
                    del lightbar.content[idx + 1]
                    prior_length = len(lightbar.content)
                    set_lbcontent(lightbar, get_lbcontent(lightbar))
                    if len(lightbar.content) - prior_length > 0:
                        lightbar.move_down()
                    dirty = True
                else:
                    echo(u'\a')
                    break
            if dirty:
                save_draft(save_key, get_lbcontent(lightbar))

        # command mode, basic cmds & movement
        elif not edit and inp:
            if inp in (u'a', u'A',):
                if yes_no(lightbar, term.yellow(u'- ')
                          + term.bold_red(u'AbORt')
                          + term.yellow(u' -')):
                    return False
                dirty = True
            elif inp in (u's', u'S',):
                if yes_no(lightbar, term.yellow(u'- ')
                          + term.bold_green(u'SAVE')
                          + term.yellow(u' -'), term.reverse_green):
                    # save contents to user attribtue
                    content = get_contents(lightbar)
                    if not save_key:
                        # return entire message body as return value
                        return content
                    save(save_key, content)
                    return True
                dirty = True
            elif inp in (u'?',):
                show_help(term)
                term.inkey()
                dirty = True
            else:
                moved = False
                for _ in count_repeat():
                    echo(lightbar.process_keystroke(inp))
                    moved = lightbar.moved or moved
                if moved:
                    echo(statusline(lightbar))

        # edit mode; movement
        elif edit and (inp in movement or inp.code in movement):
            dirty = merge()
            if inp in (u'\r', u'\n') or inp.code == term.KEY_ENTER:
                lightbar.content.insert(lightbar.index + 1,
                                        [lightbar.selection[0] + 1, u''])
                lightbar.move_down()
                dirty = True
            ucs = lightbar.process_keystroke(inp)
            #if lightbar.moved: # XXX optimize redraws
            echo(term.normal + lneditor.erase_border())
            echo(ucs)
            lneditor = get_lneditor(lightbar)
            save_draft(save_key, get_lbcontent(lightbar))
            echo(lneditor.border() + lneditor.refresh())

        # edit mode -- append character / backspace
        elif edit and inp:
            if (inp in keyset['rubout'] and
                    len(lneditor.content) == 0 and
                    lightbar.index > 0):
                # erase past margin,
                echo(term.normal + lneditor.erase_border())
                del lightbar.content[lightbar.index]
                lightbar.move_up()
                set_lbcontent(lightbar, get_lbcontent(lightbar))
                lneditor = get_lneditor(lightbar)
                dirty = True
            else:
                # edit mode, add/delete ch
                echo(lneditor.process_keystroke(inp))
                if lneditor.moved:
                    echo(statusline(lightbar))

        if inp and not inp.isdigit():
            # commands were processed, reset num_repeat to 1
            num_repeat = -1
Пример #42
0
Файл: ol.py Проект: hick/x84
def main():
    """ Main procedure. """
    # pylint: disable=R0912
    #        Too many branches
    import logging
    from x84.bbs import getsession, getterminal, ini, echo, getch, syncterm_setfont
    session, term = getsession(), getterminal()
    pager, selector = get_pager(), get_selector()
    log = logging.getLogger(__name__)

    thread = None
    if ini.CFG.has_section('bbs-scene'):
        log.info('starting bbs-scene.org oneliners thread...')
        thread = FetchUpdates()
        thread.start()
    elif ini.CFG.has_section('shroo-ms'):
        log.info('starting shroo.ms oneliners thread...')
        thread = FetchUpdatesShrooMs()
        thread.start()
    else:
        log.info('using built-in oneliners...')

    if thread is not None:
        session.activity = u'one-liners [%s]' % (thread.ident, )
    else:
        session.activity = u'one-liners'

    # flag a pager update,
    dirty = True
    # force screen clear on first loop,
    session.buffer_event('refresh', ('init', ))

    # makes syncterm switch back to the amiga topaz font
    if term._kind.startswith('ansi'):
        echo(syncterm_setfont('topaz'))

    while True:
        # 1. calculate and redraw screen,
        # or enter dumb pager mode (no scrolling)
        if session.poll_event('refresh'):
            pager, selector = get_pager(), get_selector(selector.selection)
            echo(banner())
            dirty = True
        if chk_thread(thread):
            thread = None
        while session.read_event('oneliner_update', 0.15):
            dirty = True
        if dirty and (not session.user.get('expert', False)
                      and term.width >= 78 and term.height >= 20):
            # smart terminal
            redraw(pager, selector)
            dirty = False
        elif dirty:
            # dumb terminal
            if thread is not None:
                wait_for(thread)
            if chk_thread(thread):
                thread = None
            echo(u'\r\n\r\n')
            return dummy_pager()

        # 2. detect and process keyboard input,
        inp = getch(1)
        if inp is not None:
            # input is multiplexed to both interfaces
            echo(pager.process_keystroke(inp))
            echo(selector.process_keystroke(inp))

            # selected 'yes' & return, 'say something'
            if (selector.selected and selector.selection == selector.left):
                # re-assign thread so that it is checked for updates
                thread = saysomething(dumb=False)
                # undo 'selected' state of yes/no bar,
                selector.selected = False

            # quit 'q', or selected 'no' & return
            elif (selector.selected and selector.selection == selector.right
                  or pager.quit):
                # makes syncterm switch back to the cp437 font
                if term._kind.startswith('ansi'):
                    echo(syncterm_setfont('cp437'))

                return
Пример #43
0
def main():
    """ Main menu entry point. """
    session, term = getsession(), getterminal()

    text, width, height, dirty = u'', -1, -1, 2
    menu_items = get_menu_items(session)
    editor = get_line_editor(term, menu_items)
    colors = {}
    if colored_menu_items:
        colors['backlight'] = getattr(term, color_backlight)
        colors['highlight'] = getattr(term, color_highlight)
        colors['lowlight'] = getattr(term, color_lowlight)

    while True:
        if dirty == 2:
            # set syncterm font, if any
            if syncterm_font and term.kind.startswith('ansi'):
                echo(syncterm_setfont(syncterm_font))
        if dirty:
            session.activity = 'main menu'
            top_margin = display_banner(art_file, encoding=art_encoding) + 1
            echo(u'\r\n')
            if width != term.width or height != term.height:
                width, height = term.width, term.height
                text = render_menu_entries(
                    term, top_margin, menu_items, colors)
            echo(u''.join((text,
                           display_prompt(term, colors),
                           editor.refresh())))
            dirty = 0

        event, data = session.read_events(('input', 'refresh'))

        if event == 'refresh':
            dirty = True
            continue

        elif event == 'input':
            session.buffer_input(data, pushback=True)

            # we must loop over inkey(0), we received a 'data'
            # event, though there may be many keystrokes awaiting for our
            # decoding -- or none at all (multibyte sequence not yet complete).
            inp = term.inkey(0)
            while inp:
                if inp.code == term.KEY_ENTER:
                    # find matching menu item,
                    for item in menu_items:
                        if item.inp_key == editor.content.strip():
                            echo(term.normal + u'\r\n')
                            gosub(item.script, *item.args, **item.kwargs)
                            editor.content = u''
                            dirty = 2
                            break
                    else:
                        if editor.content:
                            # command not found, clear prompt.
                            echo(u''.join((
                                (u'\b' * len(editor.content)),
                                (u' ' * len(editor.content)),
                                (u'\b' * len(editor.content)),)))
                            editor.content = u''
                            echo(editor.refresh())
                elif inp.is_sequence:
                    echo(editor.process_keystroke(inp.code))
                else:
                    echo(editor.process_keystroke(inp))
                inp = term.inkey(0)
Пример #44
0
def main(quick=False):
    """ Main procedure. """

    session, term = getsession(), getterminal()
    session.activity = 'checking for new messages'

    # set syncterm font, if any
    if term.kind.startswith('ansi'):
        echo(syncterm_setfont(syncterm_font))

    colors = dict(highlight=lambda txt: txt,
                  lowlight=lambda txt: txt,
                  backlight=lambda txt: txt,
                  text=lambda txt: txt) if not colored_menu_items else dict(
                      highlight=getattr(term, color_highlight),
                      lowlight=getattr(term, color_lowlight),
                      backlight=getattr(term, color_backlight),
                      text=getattr(term, color_text))

    yloc = top_margin = 0
    subscription = session.user.get('msg_subscription', [])
    dirty = 2

    while True:
        if dirty == 2:
            # display header art,
            yloc = display_banner(art_file, encoding=art_encoding, center=True)
            xloc = max(0, (term.width // 2) - 40)
            echo(u'\r\n')
            top_margin = yloc = (yloc + 1)

        elif dirty:
            echo(term.move(top_margin, 0) + term.normal + term.clear_eos)
            echo(term.move(top_margin, xloc))

        if dirty:

            if not subscription:
                # prompt the user for a tag subscription, and loop
                # back again when completed to re-draw and show new messages.
                subscription = session.user['msg_subscription'] = (
                    prompt_subscription(session=session,
                                        term=term,
                                        yloc=top_margin,
                                        subscription=subscription,
                                        colors=colors))
                continue

            messages, messages_bytags = get_messages_by_subscription(
                session, subscription)

            # When quick login ('y') selected in top.py, return immediately
            # when no new messages are matched any longer.
            if quick and not messages['new']:
                echo(term.move_x(xloc) + u'\r\nNo new messages.\r\n')
                return waitprompt(term)

            txt = describe_message_area(term=term,
                                        subscription=subscription,
                                        messages_bytags=messages_bytags,
                                        colors=colors)

            yloc = top_margin + show_description(
                term=term,
                description=txt,
                color=None,
                subsequent_indent=' ' * len('message area: '))

            echo(
                render_menu_entries(term=term,
                                    top_margin=yloc,
                                    menu_items=get_menu(messages),
                                    colors=colors,
                                    max_cols=2))
            echo(display_prompt(term=term, colors=colors))
            echo(colors['backlight'](u' \b'))
            dirty = False

        event, data = session.read_events(('refresh', 'newmsg', 'input'))

        if event == 'refresh':
            # screen resized, redraw.
            dirty = 2
            continue

        elif event == 'newmsg':
            # When a new message is sent, 'newmsg' event is broadcasted.
            session.flush_event('newmsg')
            nxt_msgs, nxt_bytags = get_messages_by_subscription(
                session, subscription)
            if nxt_msgs['new'] - messages['new']:
                # beep and re-display when a new message has arrived.
                echo(u'\b')
                messages, messages_bytags = nxt_msgs, nxt_bytags
                dirty = True
                continue

        elif event == 'input':
            # on input, block until carriage return
            session.buffer_input(data, pushback=True)
            given_inp = LineEditor(1,
                                   colors={
                                       'highlight': colors['backlight']
                                   }).read()

            if given_inp is None:
                # escape/cancel
                continue

            inp = given_inp.strip()
            if inp.lower() in (u'n', 'a', 'v'):
                # read new/all/private messages
                message_indices = sorted(
                    list({
                        'n': messages['new'],
                        'a': messages['all'],
                        'v': messages['private'],
                    }[inp.lower()]))
                if message_indices:
                    dirty = 2
                    read_messages(session=session,
                                  term=term,
                                  message_indices=message_indices,
                                  colors=colors)
            elif inp.lower() == u'm' and messages['new']:
                # mark all messages as read
                dirty = 1
                do_mark_as_read(session, messages['new'])
            elif inp.lower() in (u'p', u'w'):
                # write new public/private message
                dirty = 2
                public = bool(inp.lower() == u'p')
                msg = Msg()
                if (not prompt_recipient(
                        term=term, msg=msg, colors=colors, public=public) or
                        not prompt_subject(term=term, msg=msg, colors=colors)
                        or not prompt_body(term=term, msg=msg, colors=colors)
                        or not prompt_tags(session=session,
                                           term=term,
                                           msg=msg,
                                           colors=colors,
                                           public=public)):
                    continue
                do_send_message(session=session,
                                term=term,
                                msg=msg,
                                colors=colors)
            elif inp.lower() == u'c':
                # prompt for new tag subscription (at next loop)
                subscription = []
                dirty = 1
            elif inp.lower() == u'?':
                # help
                echo(term.move(top_margin, 0) + term.clear_eos)
                do_describe_message_system(term, colors)
                waitprompt(term)
                dirty = 2
            elif inp.lower() == u'q':
                return
            if given_inp:
                # clear out line editor prompt
                echo(colors['backlight'](u'\b \b'))
Пример #45
0
def play():
    import time
    from random import randint
    import os
    from x84.bbs import getterminal, getch, from_cp437, AnsiWindow, syncterm_setfont
    from x84.bbs import echo as echo_unbuffered
    term = getterminal()
    field = []
    global charcache
    charcache = u''
    field_width = 10
    field_height = 20
    # Access scheme looks like this:
    #   layout[p][r][ypox][xpos]
    # layoutcolor = [ 7,2,3,4,4,6,7 ]
    layout = [
        #  ##
        #  ##
        [
            [
                [1, 1, ],
                [1, 1, ],
            ],
        ],
        #  #
        #  #
        #  #
        #  #
        [
            [
                [0, 1, 0, 0],
                [0, 1, 0, 0],
                [0, 1, 0, 0],
                [0, 1, 0, 0],
            ],
            [
                [0, 0, 0, 0],
                [1, 1, 1, 1],
                [0, 0, 0, 0],
                [0, 0, 0, 0],
            ]
        ],
        #  ###
        #   #
        [
            [
                [0, 0, 0],
                [1, 1, 1],
                [0, 1, 0],
            ],
            [
                [0, 1, 0],
                [0, 1, 1],
                [0, 1, 0],
            ],
            [
                [0, 1, 0],
                [1, 1, 1],
                [0, 0, 0],
            ],
            [
                [0, 1, 0],
                [1, 1, 0],
                [0, 1, 0],
            ],
        ],
        #  #
        #  #
        #  ##
        [
            [
                [0, 1, 0],
                [0, 1, 0],
                [0, 1, 1],
            ],
            [
                [0, 0, 1],
                [1, 1, 1],
                [0, 0, 0],
            ],
            [
                [1, 1, 0],
                [0, 1, 0],
                [0, 1, 0],
            ],
            [
                [0, 0, 0],
                [1, 1, 1],
                [1, 0, 0],
            ],
        ],
        #   #
        #   #
        #  ##
        [
            [
                [0, 1, 0],
                [0, 1, 0],
                [1, 1, 0],
            ],
            [
                [0, 0, 0],
                [1, 1, 1],
                [0, 0, 1],
            ],
            [
                [0, 1, 1],
                [0, 1, 0],
                [0, 1, 0],
            ],
            [
                [1, 0, 0],
                [1, 1, 1],
                [0, 0, 0],
            ],
        ],
        #  ##
        #   ##
        [
            [
                [0, 1, 0],
                [1, 1, 0],
                [1, 0, 0],
            ],
            [
                [0, 0, 0],
                [1, 1, 0],
                [0, 1, 1],
            ],
        ],
        #   ##
        #  ##
        [
            [
                [0, 1, 0],
                [0, 1, 1],
                [0, 0, 1],
            ],
            [
                [0, 0, 0],
                [0, 1, 1],
                [1, 1, 0],
            ],
        ],
    ]

    fieldx1 = 32
    fieldy1 = 10
    scorex1 = 11
    scorey1 = 11

    class RectRedraw:
        x1 = None
        y1 = None
        x2 = None
        y2 = None

        def max(r, val, valmax):
            if val > valmax:
                return valmax
            return val

        def min(r, val, valmin):
            if val < valmin:
                return valmin
            return val

        def merge(r, x1, y1, x2, y2):
            if r.x1 is None or r.x1 > x1:
                r.x1 = r.min(x1, 0)
            if r.y1 is None or r.y1 > y1:
                r.y1 = r.min(y1, 0)
            if r.x2 is None or r.x2 < x2:
                r.x2 = r.max(x2, field_width)
            if r.y2 is None or r.y2 < y2:
                r.y2 = r.max(y2, field_height)
            # print r.x1,r.y1,r.x2,r.y2

        def clean(r):
            r.x1 = None
            r.y1 = None
            r.x2 = None
            r.y2 = None
    rr = RectRedraw()
    for _ in range(field_height):
        field.append([0] * field_width)

    def echo(s):
        global charcache
        charcache += s
    assert term.height > (field_height + 1)
    echo_unbuffered(u''.join((
        u'\r\n\r\n',
        u'REAdY YOUR tERMiNAl %s ' % (term.bold_blue('(!)'),),
        u'\r\n\r\n',
        u'%s PRESS ANY kEY' % (term.bold_black('...'),),
    )))
    getch()
    # set syncterm font to cp437
    if term.kind.startswith('ansi'):
        echo_unbuffered(syncterm_setfont('cp437'))
    artfile = os.path.join(os.path.dirname(__file__), 'art', 'tetris.ans')
    echo_unbuffered(u'\r\n' * term.height)  # cls
    if os.path.exists(artfile):
        echo_unbuffered(from_cp437(open(artfile).read()).rstrip())

    def gotoxy(x, y):
        echo(term.move(y, x))

    def plotblock(color, lastcolor):
        if color:
            c = u'\u2588\u2588'  # '\xDB\xDB'
        else:  # both empty
            c = '  '
            color = 0
        # Output optimization
        if color % 8 == 0:
            color = color / 8
        if color == lastcolor:
            echo(c)
        else:
            if color:
                fg = str(30 + color % 8)
            else:
                fg = '37'
            if color >= 8:
                bg = ';%d' % (40 + color / 8)
            else:
                bg = ''
            echo('\x1b[0;' + fg + bg + 'm')
            echo(c)
            lastcolor = color
        return lastcolor

    def drawfield():
        lastcolor = ''
        for y in range(0, field_height, 2):
            # gotoxy(field_width,2+y/2)
            gotoxy(fieldx1 + 2, fieldy1 + 1 + y / 2)
            # Which block to show, full, half-up, half-down or empty.
            for x in range(field_width):
                color = field[y][x] + field[y + 1][x] * 8
                if field[y][x] and field[y + 1][x]:
                    c = u'\u2588'  # '\xDB'
                    if field[y][x] == field[y + 1][x]:
                        color = color % 8
                    else:
                        c = u'\u2580'  # '\xDF'
                elif field[y][x] and not field[y + 1][x]:
                    c = u'\u2580'  # '\xDF'
                elif not field[y][x] and field[y + 1][x]:
                    c = u'\u2584'  # '\xDC'
                else:  # both empty
                    c = ' '
                # Output optimization
                if color % 8 == 0:
                    color = color / 8
                if color == lastcolor:
                    echo(c)
                else:
                    if color:
                        fg = str(30 + color % 8)
                    else:
                        fg = '37'
                    if color >= 8:
                        bg = ';%d' % (40 + color / 8)
                    else:
                        bg = ''
                    echo('\x1b[0;' + fg + bg + 'm')
                    echo(c)
                    lastcolor = color
        echo(term.normal)

    layoutcolor = [7, 2, 7, 6, 3, 6, 3]
    # p    = -1  # Current piece type
    nextpiece = randint(0, len(layout) - 1)
    p = randint(0, len(layout) - 1)
    p = 1
    r = 0   # Current rotation
    xpos = 4   # X position
    # ypos = -2  # Y position
    ypos = -len(layout[p][0])
    level = 1
    score = 0
    lines = 0

    def flush():
        global charcache
        echo_unbuffered(charcache)
        charcache = u''

    def fillpiece(x, y, p, r, value):
        row = 0
        for line in layout[p][r]:
            col = 0
            for c in line:
                if c and (y + row) >= 0:
                    field[y + row][x + col] = value
                col += 1
            row += 1

    def showpiece(x, y, p, r):
        fillpiece(x, y, p, r, layoutcolor[p])

    def hidepiece():
        fillpiece(xpos, ypos, p, r, 0)

    def testpiece(x, y, newr):
        hidepiece()
        # Space at the new location?
        row = 0
        for line in layout[p][newr]:
            col = 0
            for c in line:
                try:
                    if c:
                        if ((y + row) >= 0 and field[y + row][x + col]
                                or (x + col) < 0 or (x + col) > 9):
                            return 0
                except IndexError:
                    return 0
                col += 1
            row += 1
        # Movement possible
        return 1

    def movepiece(x, y, newr):
        if testpiece(x, y, newr):
            # Build redraw rectangle
            rr.merge(xpos, ypos,
                     xpos + len(layout[p][0][0]), ypos + len(layout[p][0]))
            rr.merge(x, y,
                     x + len(layout[p][0][0]), y + len(layout[p][0]))
            showpiece(x, y, p, newr)
            return (x, y, newr, 1)
        else:
            showpiece(xpos, ypos, p, r)
            return (xpos, ypos, r, 0)

    def shownext(p):
        r = 0
        for y in range(4):
            gotoxy(26, 18 + y)
            echo(u' ' * 4)

        echo(term.color(layoutcolor[p]))

        yoffset = int(len(layout[p][r][0]) < 4)
        xoffset = int(len(layout[p][r]) < 3)
        for y in range(len(layout[p][r])):
            for x in range(len(layout[p][r][y])):
                val = layout[p][r][y][x]
                if val:
                    gotoxy(26 + x + xoffset, 18 + y + yoffset)
                    echo(u'\u2588\u2588')

    def drawstats():
        echo(term.move(scorey1, scorex1) + '%d' % level)
        echo(term.move(scorey1 + 2, scorex1) + '%d' % lines)
        echo(term.move(scorey1 + 3, scorex1) + '%d' % score)

    drawstats()
    ticksize = 0.4
    nexttick = time.time() + ticksize
    showpiece(xpos, ypos, p, r)
    gotoxy(26, 17)
    echo(term.blue_reverse('next'))
    shownext(nextpiece)

    # Full redraw first frame
    rr.merge(0, 0, field_width, field_height)

    buf = ''
    while True:
        drawfield()
        # gotoxy(0,0)
        # echo('\x1b[37mx: %d, y: %d, p: %d         '%(xpos,ypos,p))
        slice = nexttick - time.time()
        if slice < 0:
            slice = 0
        echo(buf)
        buf = ''
        flush()
        key = getch(slice + 0.01)
        now = time.time()
        # hidepiece()
        if key is not None:
            if key in (u'q', u'Q'):
                return (0, 0, 0)
            elif key in (term.KEY_LEFT, u'h',):
                xpos, ypos, r, m = movepiece(xpos - 1, ypos, r)
            elif key in (term.KEY_RIGHT, u'l',):
                xpos, ypos, r, m = movepiece(xpos + 1, ypos, r)
            elif key in (term.KEY_UP, u'k',):
                xpos, ypos, r, m = movepiece(
                    xpos, ypos, (r + 1) % len(layout[p]))
            elif key in (term.KEY_DOWN, u'j',):
                xpos, ypos, r, m = movepiece(xpos, ypos + 1, r)
            elif key in (' ',):
                m = True
                c = 0
                while m:
                    xpos, ypos, r, m = movepiece(xpos, ypos + 1, r)
                    if m:
                        c += 1
                if c:
                    nexttick = time.time() + ticksize
        # New tick?
        if now > nexttick:
            nexttick += ticksize
            # Move down piece
            xpos, ypos, r, moved = movepiece(xpos, ypos + 1, r)
            # Piece has touched down?
            if not moved:
                # Is the player dead?
                if ypos <= -len(layout[p][0]):
                    death_win = AnsiWindow(height=6, width=40,
                                           yloc=fieldy1 + 10 / 2, xloc=fieldx1 - 11)
                    death_win.colors['border'] = term.bold_black
                    echo_unbuffered(death_win.clear() + death_win.border())
                    echo_unbuffered(
                        term.move(fieldy1 + 10 / 2 + 1, fieldx1 - 11))
                    echo_unbuffered((
                                    u'!! gAME OVeR!! Score was: %i' % (score,)).center(40))
                    echo_unbuffered(
                        term.move(fieldy1 + 10 / 2 + 3, fieldx1 - 11))
                    echo_unbuffered(u'press RETURN'.center(40))
                    while True:
                        inp = getch()
                        if inp in (u'\r', term.KEY_ENTER):
                            break
                    return (score, level, lines)

                # Any complete rows to remove?
                complete = []
                for y in range(field_height):
                    x = 0
                    while x < field_width:
                        if field[y][x] == 0:
                            break
                        x += 1
                    if x == field_width:
                        complete.append(y)
                if len(complete) > 0:
                    # Add score
                    lines += len(complete)
                    score += len(complete) * len(complete) * 100
                    # Shrink field
                    for line in complete:
                        del field[line]
                        field.insert(0, [0] * field_width)

                    if lines >= level * 10:
                        level += 1
                        ticksize = 0.4 - level * 0.02
                    drawstats()

                    # Redraw complete field
                    rr.merge(0, 0, field_width, field_height)

                # Time for a new piece
                p = nextpiece
                nextpiece = randint(0, len(layout) - 1)
                r = 0
                xpos = 4
                ypos = -len(layout[p][0])
                showpiece(xpos, ypos, p, r)
                shownext(nextpiece)