def main(): with FullscreenWindow() as window: print('Press escape to exit') with Input() as input_generator: a = FSArray(window.height, window.width) for c in input_generator: if c == '<ESC>': break elif c == '<SPACE>': a = FSArray(window.height, window.width) else: row = random.choice(range(window.height)) column = random.choice(range(window.width - len(repr(c)))) a[row, column:column + len(repr(c))] = [repr(c)] window.render_to_terminal(a)
def __init__(self, width, height, players): self.width = width self.height = height self.grid = FSArray(height, width) self.players = players self.numplayers = len(self.players)
def render(self): a = FSArray(self.height, self.width) for row, col in self.snake_parts: a[row, col] = 'x' a[self.apple[0], self.apple[1]] = 'o' return a
def render_partial(self, w_fsa, x_offset=0, y_offset=0): assert self.height is not None assert self.width is not None c_fsa = FSArray(self.height, self.width) blit(c_fsa, w_fsa, x=x_offset, y=y_offset) self.render_into_rect(c_fsa) blit(w_fsa, c_fsa, x=-x_offset, y=-y_offset)
def fmtfsa(fsa, **kwargs): o_fsa = FSArray(fsa.height, fsa.width) for y in range(fsa.height): raw = map( lambda x: fmtstr(x.new_with_atts_removed(xforms.keys()), **kwargs), fsa[y:y + 1, 0:fsa.width]) o_fsa[y:y + 1, 0:o_fsa.width] = raw return o_fsa
def __init__(self, window, input_generator, finder): self._window = window self._input = input_generator self._finder = finder self.current_match = None self._search_text = "" self._output = FSArray(2, window.width) self._prompt_start_line = 1 self._init_prompt()
def render(self, isDead): if not isDead: a = FSArray(self.height, self.width) for seg in self.snake_segments: a[seg[0], seg[1]] = blue('X') return a else: a = self.deathSequence() return a
def deathSequence(self): a = FSArray(self.height, self.width) a[10, 10] = red('X') a[10, 14] = red('X') a[12, 10] = red('_') a[12, 11] = red('_') a[12, 12] = red('_') a[12, 13] = red('_') a[12, 14] = red('_') return a
def main(host, port): # Create a socket client = socket.socket() # Connect client.connect((host, port)) # Set socket not to block? client.setblocking(False) # Create connection object conn = Connection(client) # Store keypresses keypresses = [] with FullscreenWindow() as window: # Input() is from curtsies with Input() as input_generator: while True: # red is stuff at bottom, blue status at top, green 'window' with output # red at bottom a = FSArray(10, 80) in_text = ''.join(keypresses)[:80] a[9:10, 0:len(in_text)] = [red(in_text)] # render does the page in green for i, line in zip(reversed(range(2, 7)), reversed(conn.render())): a[i:i + 1, 0:len(line)] = [line] # Top line text = 'connected to %s:%d' % (host if len(host) < 50 else host[:50] + '...', port) a[0:1, 0:len(text)] = [blue(text)] window.render_to_terminal(a) ready_to_read, _, _ = select.select([conn, input_generator], [], []) for r in ready_to_read: if r is conn: r.on_read() else: e = input_generator.send(0) if e == '<ESC>': return elif e == '<Ctrl-j>': keypresses.append('\n') client.send( (''.join(keypresses)).encode('latin-1')) keypresses = [] elif e == '<SPACE>': keypresses.append(' ') elif e in ('<DELETE>', '<BACKSPACE>'): keypresses = keypresses[:-1] elif e is not None: keypresses.append(e)
def main(): counter = FrameCounter() with FullscreenWindow() as window: print('Press escape to exit') with Input() as input_generator: a = FSArray(window.height, window.width) c = None for framenum in itertools.count(0): t0 = time.time() while True: t = time.time() temp_c = input_generator.send( max(0, t - (t0 + time_per_frame))) if temp_c is not None: c = temp_c if c is None: pass elif c == '<ESC>': return elif c == '<SPACE>': a = FSArray(window.height, window.width) else: row = random.choice(range(window.height)) column = random.choice(range(window.width - len(c))) a[row:row + 1, column:column + len(c)] = [c] c = None if time_per_frame < t - t0: break row = random.choice(range(window.height)) column = random.choice(range(window.width)) a[row:row + 1, column:column + 1] = [random.choice(".,-'`~")] fps = 'FPS: %.1f' % counter.fps() a[0:1, 0:len(fps)] = [fps] window.render_to_terminal(a) counter.frame()
def wrap(text, width, height=None, text_fmt=lambda x: x): lines = textwrap.wrap(text, width) if height is None: height = len(lines) fsa = FSArray(height, width) if height > len(lines): height = len(lines) fsa[0:height, 0:width] = map(text_fmt, lines[0:height]) return fsa
def prompt(msg): with CursorAwareWindow(out_stream=sys.stderr, extra_bytes_callback=lambda x:x, hide_cursor=False) as window: left = window.width//3 -1 prompt = textwrap.wrap(msg, left) + [''] p_lines = len(prompt) right = window.width - max(len(line) for line in prompt) - 1 left = window.width - right - 1 document = Document() view = FSArray(p_lines, window.width) view[0:p_lines, 0:left] = [bold(line) for line in prompt] window.render_to_terminal(view, (0, left+1)) with Input() as keys: for key in keys: if key == '<Ctrl-j>': # return window.render_to_terminal([], (0,0)) return str(document) if key == '<Esc+Ctrl-J>': # alt-return document.handle('<Ctrl-j>') elif key == '<LEFT>': document.move_cursor(Dir.LEFT) elif key == '<RIGHT>': document.move_cursor(Dir.RIGHT) elif key == '<UP>': document.move_cursor(Dir.UP) elif key == '<DOWN>': document.move_cursor(Dir.DOWN) elif key == '<Ctrl-LEFT>': document.move_word(Dir.LEFT) elif key == '<Ctrl-RIGHT>': document.move_word(Dir.RIGHT) elif key == '<Ctrl-w>': document.move_word(Dir.LEFT, delete=True) elif key == '<Ctrl-DELETE>': document.move_word(Dir.RIGHT, delete=True) elif key in ('<Ctrl-a>', '<HOME>'): document.end_line(0) elif key in ('<Ctrl-e>', '<END>'): document.end_line(1) elif isinstance(key, PasteEvent): for c in key.events: document.handle(c) else: document.handle(key) # Add an extra blank line to force clearing of trailing text text = document.lines + [' '] lines, cursor = _wrap(text, document.cursor, right) rows = list(lines) # Replace the right column with input text view[0:len(rows), left+1:window.width] = rows window.render_to_terminal(view, (cursor.row, cursor.column+left+1))
def paint_infobox( rows, columns, matches, funcprops, arg_pos, match, docstring, config, match_format, ): """Returns painted completions, funcprops, match, docstring etc.""" if not (rows and columns): return FSArray(0, 0) width = columns - 4 from_argspec = (formatted_argspec(funcprops, arg_pos, width, config) if funcprops else []) from_doc = (formatted_docstring(docstring, width, config) if docstring else []) from_matches = (matches_lines( max(1, rows - len(from_argspec) - 2), width, matches, match, config, match_format, ) if matches else []) lines = from_argspec + from_matches + from_doc def add_border(line): """Add colored borders left and right to a line.""" new_line = border_color(config.left_border + " ") new_line += line.ljust(width)[:width] new_line += border_color(" " + config.right_border) return new_line border_color = func_for_letter(config.color_scheme["main"]) top_line = border_color(config.left_top_corner + config.top_border * (width + 2) + config.right_top_corner) bottom_line = border_color(config.left_bottom_corner + config.bottom_border * (width + 2) + config.right_bottom_corner) output_lines = list( itertools.chain((top_line, ), map(add_border, lines), (bottom_line, ))) r = fsarray(output_lines[:min(rows - 1, len(output_lines) - 1)] + output_lines[-1:]) return r
def render(self, max_width, max_height): if self.height is None: actual_height = max_height else: actual_height = min(self.height, max_height) if self.width is None: actual_width = max_width else: actual_width = min(self.width, max_width) w_fsa = FSArray(actual_height, actual_width) self.render_into_rect(w_fsa) return w_fsa
def render_into_rect(self, w_fsa): width = w_fsa.width height = w_fsa.height if self.border: c_fsa = FSArray(height - 2, width - 2) if not self.opaque: c_fsa[0:height - 2, 0:width - 2] = w_fsa[1:height - 1, 1:width - 1] self.widget_lm.render_into_rect(c_fsa) # TODO box via decorator w_fsa[0:height, 0:width] = box(c_fsa, title=self.title, border_fmt=self.decorator.str_formatter()) else: if self.title: c_fsa = FSArray(height - 1, width) if not self.opaque: c_fsa[0:height - 1, 0:width] = w_fsa[1:height, 0:width] self.widget_lm.render_into_rect(c_fsa) w_fsa[1:height, 0:width] = c_fsa # TODO title via decorator w_fsa[0:1, 0:width] = [ self.decorator.format_str(center(self.title, width)) ] else: if not self.opaque: self.widget_lm.render_into_rect(w_fsa) else: c_fsa = FSArray(height, width) self.widget_lm.render_into_rect(c_fsa) w_fsa[0:height, 0:width] = c_fsa
def render(self): if self.owner is None: width = self.window.width height = self.window.height else: width = self.owner.width height = self.owner.height lm_fsa = FSArray(height, width) self.render_into_rect(lm_fsa) if self.owner is None: self.window.render_to_terminal(lm_fsa) return lm_fsa
def main(host, port): client = socket.socket() client.connect((host, port)) client.setblocking(False) conn = Connection(client) keypresses = [] with FullscreenWindow() as window: with Input() as input_generator: while True: a = FSArray(10, 80) in_text = ''.join(keypresses)[:80] a[9:10, 0:len(in_text)] = [red(in_text)] for i, line in zip(reversed(range(2, 7)), reversed(conn.render())): a[i:i + 1, 0:len(line)] = [line] text = 'connected to %s:%d' % (host if len(host) < 50 else host[:50] + '...', port) a[0:1, 0:len(text)] = [blue(text)] window.render_to_terminal(a) ready_to_read, _, _ = select.select([conn, input_generator], [], []) for r in ready_to_read: if r is conn: r.on_read() else: e = input_generator.send(0) if e == '<ESC>': return elif e == '<Ctrl-j>': keypresses.append('\n') client.send( (''.join(keypresses)).encode('latin-1')) keypresses = [] elif e == '<SPACE>': keypresses.append(' ') elif e in ('<DELETE>', '<BACKSPACE>'): keypresses = keypresses[:-1] elif e is not None: keypresses.append(e)
def _string_to_fsarray(self, msg): if not self._inside_window_context: raise RuntimeError( 'Calling _string_to_fsarray outside of window context') rows, columns = self._window_context.get_term_hw() msg = fmtstr(msg) arr = FSArray(0, columns) i = 0 lines = msg.split('\n') if '\n' in str(msg) else [msg] for line in lines: for j in xrange(len(line)): c = line[j] if i >= rows * columns: return arr else: arr[i // arr.width, i % arr.width] = [c] i += 1 i = ((i // columns) + 1) * columns if len(arr) == 0: return fsarray(['']) return arr
def __init__(self, window: FullscreenWindow): # save game window, plus window size info self.window = window self.max_rows = window.height self.max_cols = window.width # initialize reactor system + schedule first tick self.reactor = Input() self.schedule_tick = self.reactor.scheduled_event_trigger(Tick) self.schedule_tick(when=time.time()) self.last_event: Optional[str] = None # initialize game state self.field: Optional[Field] = None self.menu: Optional[str] = None self.menu_opened_at: Optional[pendulum.DateTime] = None # initialize game display + add borders and header self.chars = FSArray(self.max_rows, self.max_cols) self.draw_game_border() self.draw_header()
def do_introduction(window): h, w = window.height, window.width messages = [ "two player tron", fmtstr("player 1:", "on_blue", "cyan") + " wasd", fmtstr("player 2:", "on_red", "yellow") + " arrow keys", ] billboard = FSArray(h, w) msg_row = h // 2 - 2 for msg in messages: billboard[msg_row, w // 2 - len(msg) // 2:w // 2 + len(msg) // 2 + 1] = fsarray([msg]) msg_row += 1 window.render_to_terminal(billboard) # countdown msg for i in range(3, 0, -1): billboard[msg_row, w // 2] = fmtstr(str(i), "red") window.render_to_terminal(billboard) time.sleep(1)
def box(c_fsa, spacing=0, v_bar=light_vertical, h_bar=light_horizontal, ul_corner=light_down_and_right, ur_corner=light_down_and_left, ll_corner=light_up_and_right, lr_corner=light_up_and_left, left=u'[', right=u']', title=None, border_fmt=lambda x: x): w = c_fsa.width h = c_fsa.height bw = w + 2 * spacing + 2 bh = h + 2 * spacing + 2 b_fsa = FSArray(bh, bw) b_fsa[0, 0] = border_fmt(ul_corner) b_fsa[bh - 1, 0] = border_fmt(ll_corner) b_fsa[0, bw - 1] = border_fmt(ur_corner) b_fsa[bh - 1, bw - 1] = border_fmt(lr_corner) b_fsa[1:bh - 1, 0:1] = map(border_fmt, v_repeat(v_bar, bh - 2)) b_fsa[1:bh - 1, bw - 1:bw] = map(border_fmt, v_repeat(v_bar, bh - 2)) b_fsa[0:1, 1:bw - 1] = [border_fmt(repeat(h_bar, bw - 2))] b_fsa[bh - 1:bh, 1:bw - 1] = [border_fmt(repeat(h_bar, bw - 2))] if title is not None: b_fsa[0:1, 1:bw - 1] = [ border_fmt(header(title, bw - 2, bar=h_bar, left=left, right=right)) ] blit(b_fsa, c_fsa, 1 + spacing, 1 + spacing, w, h) return b_fsa
def get_array(self): a = FSArray(self.height, self.width) for entity in self.entities: a[self.height - 1 - entity.y, entity.x] = entity.display return a
from __future__ import unicode_literals # convenient for Python 2 import random from curtsies import FullscreenWindow, Input, FSArray from curtsies.fmtfuncs import red, bold, green, on_blue, yellow print(yellow('this prints normally, not to the alternate screen')) with FullscreenWindow() as window: with Input() as input_generator: msg = red(on_blue(bold('Press escape to exit'))) a = FSArray(window.height, window.width) a[0:1, 0:msg.width] = [msg] window.render_to_terminal(a) for c in input_generator: if c == '<ESC>': break elif c == '<SPACE>': a = FSArray(window.height, window.width) else: s = repr(c) row = random.choice(range(window.height)) column = random.choice(range(window.width-len(s))) color = random.choice([red, green, on_blue, yellow]) a[row, column:column+len(s)] = [color(s)] window.render_to_terminal(a)
def loop(self): if self.history_file: with open(self.history_file, 'a+') as f: f.seek(0) self.history = f.read().split('\n') + self.history self.new_history = len(self.history) self.wait_completion = False self.line = 0 self.column = 0 with FullscreenWindow() as window: with Input() as input_generator: self.a = FSArray(window.height, window.width) intro_lines = self.intro.split('\n') for i, line in enumerate(intro_lines): self.write_xy(i, 0, line) self.write_xy(self.line + 1, 0, self.prompt) window.render_to_terminal(self.a) # intro and prompt text = '' begin_line = self.line begin_column = self.column in_history = False for c in input_generator: if self.wait_completion: self.wait_completion = False # print(c) # continue if c == '<Ctrl-j>': if in_history: text = self.history[history_index] in_history = False if self.read_until in [CR, NL]: self.history.append(text) self.print_result(self.evaluate(text)) self.write_xy(self.line + 1, 0, self.prompt) elif self.complete_on in [CR, NL]: self.offer_completions(text) else: text += '\n' #tokens.append(token) self.write_xy(self.line + 1, 0, self.prompt) begin_line = self.line begin_column = self.column elif c == '<UP>': if not in_history: history_index = len(self.history) - 1 in_history = True self.write_xy( begin_line, begin_column, self.highlight_text(self.history[history_index])) if history_index > 0: history_index -= 1 elif c == '<DOWN>': if in_history: history_index += 1 if history_index > len(self.history) - 1: in_history = False self.write_xy(begin_line, begin_column, self.highlight_text(text)) else: self.write_xy( begin_line, begin_column, self.highlight_text( self.history[history_index])) elif c == '<LEFT>': if self.column > len(self.prompt): self.column -= 1 elif c == '<RIGHT>': if self.column < len(self.prompt) + len(text): self.column += 1 elif c == '<BACKSPACE>': if self.column > len(self.prompt): text = text[:-1] self.write_xy(begin_line, begin_column, self.highlight_text(text)) elif c == '<Ctrl-D>': if self.history_file: with open(self.history_file, 'a+') as f: f.write('\n'.join( self.history[self.new_history:]) + '\n') exit(0) elif c in ['<SPACE>', '<TAB>'] or len(c) == 1: if in_history: text = self.history[history_index] in_history = False if self.complete_on == c: self.offer_completions(text + c) elif self.read_until == c: self.history.append(text) self.print_result(self.evaluate(text)) self.write_xy(self.line + 1, 0, self.prompt) begin_line = self.line begin_column = self.column else: text += c if len(c) == 1 else { '<SPACE>': ' ', '<TAB>': '\t' }[c] if c[0].isalnum(): self.write_xy(self.line, self.column, c) else: self.write_xy(begin_line, begin_column, self.highlight_text(text)) window.render_to_terminal(self.a)
def _resize_output(self, number_of_rows): old_output = self._output self._output = FSArray(number_of_rows, self._window.width) for (lineno, line) in enumerate(islice(old_output, number_of_rows)): self._output[lineno] = line