def draw_menu(self):
# Actually draws the menu and handles branching
request = ""
try:
while request is not "exit":
self.draw()
request = self.get_user_input()
self.handle_request(request)
self.__exit__()
# Also calls __exit__, but adds traceback after
except Exception as exception:
self.screen.clear()
self.screen.addstr(0, 0, "Enlarge terminal!", curses.A_NORMAL)
self.screen.refresh()
self.__exit__()
#traceback.print_exc()
python类A_NORMAL的实例源码
def refresh_line(self, line, *, no_refresh=False):
if self.invalidate:
self.refresh()
return
if len(self.logic.get_order()) == 0:
return
max_y, max_x = self.stdscr.getmaxyx()
row = line - self.top
if row < 0 or row >= max_y:
return
bit = self.logic.get_order()[line]
if hasattr(self.logic, "get_line"):
title = self.logic.get_line(bit, max_x - _INDICATOR_OFFSET * 2)
else:
title = bit[:max_x - _INDICATOR_OFFSET * 2]
if line == self.active:
self.stdscr.addstr(row, 0, "> ", curses.A_REVERSE)
self.stdscr.addstr(row, _INDICATOR_OFFSET, title, curses.A_REVERSE)
self.stdscr.chgat(row, 0, curses.A_REVERSE)
else:
self.stdscr.addstr(row, _INDICATOR_OFFSET, title)
self.stdscr.chgat(row, 0, curses.A_NORMAL)
if not no_refresh:
self.stdscr.refresh()
def tick(self, scr, steps):
height, width = scr.getmaxyx()
if self.advances(steps):
# if window was resized and char is out of bounds, reset
self.out_of_bounds_reset(width, height)
# make previous char curses.A_NORMAL
if USE_COLORS:
scr.addstr(self.y, self.x, self.char, curses.color_pair(COLOR_CHAR_NORMAL))
else:
scr.addstr(self.y, self.x, self.char, curses.A_NORMAL)
# choose new char and draw it A_REVERSE if not out of bounds
self.char = random.choice(FallingChar.matrixchr).encode(encoding)
self.y += 1
if not self.out_of_bounds_reset(width, height):
if USE_COLORS:
scr.addstr(self.y, self.x, self.char, curses.color_pair(COLOR_CHAR_HIGHLIGHT))
else:
scr.addstr(self.y, self.x, self.char, curses.A_REVERSE)
def status(self):
"""
Draw `Status` frame and `Hosts File` frame in the TUI window.
"""
screen = self._stdscr.subwin(11, 25, 10, 0)
screen.bkgd(' ', curses.color_pair(4))
# Set local variable
normal = curses.A_NORMAL
green = curses.color_pair(7)
red = curses.color_pair(9)
# Status info
for i, stat in enumerate(self.statusinfo):
screen.addstr(2 + i, 2, stat[0], normal)
stat_str = ''.join(['[', stat[1], ']']).ljust(9)
screen.addstr(2 + i, 15, stat_str,
green if stat[2] == "GREEN" else red)
# Hosts file info
i = 0
for key, info in self.hostsinfo.items():
screen.addstr(7 + i, 2, key, normal)
screen.addstr(7 + i, 15, info, normal)
i += 1
screen.refresh()
def sub_selection_dialog_items(self, pos, i_pos, screen):
"""
Draw items in `Selection Dialog`.
:param pos: Index of selected item in `Configure Setting` frame.
:type pos: int
:param i_pos: Index of selected item in `Selection Dialog`.
:type i_pos: int
:param screen: A **WindowObject** which represents the selection
dialog.
:type screen: WindowObject
"""
# Set local variable
normal = curses.A_NORMAL
select = normal + curses.A_BOLD
for p, item in enumerate(self.settings[pos][2]):
item_str = item if pos else item["tag"]
screen.addstr(1 + p, 2, item_str,
select if p == i_pos else normal)
screen.refresh()
def depict_fps(self):
w = self.fpsWindow
now = time.time()
elapsed = now - self.fpsSince
fps = self.fpsTicks / elapsed
if self.fpsGoal is not None:
seconds_of_work_per_frame = (elapsed / self.fpsTicks) - self.fpsDelay
desired_time_working_per_second = self.fpsGoal * seconds_of_work_per_frame
if desired_time_working_per_second < 1.0:
self.fpsDelay = (1.0 - desired_time_working_per_second) / fps
else:
self.fpsDelay = 0
w.addstr(1, 1, 'FPS:%3d' % fps, curses.A_NORMAL)
w.refresh()
self.fpsSince = now
self.fpsTicks = 0
self.fpsMeasured = fps
def depict_workspace_object(self, w, row, column, o, maxImportance, description_structures):
if maxImportance != 0.0 and o.relativeImportance == maxImportance:
attr = curses.A_BOLD
else:
attr = curses.A_NORMAL
w.addstr(row, column, str(o), attr)
column += len(str(o))
if o.descriptions:
w.addstr(row, column, ' (', curses.A_NORMAL)
column += 2
for i, d in enumerate(o.descriptions):
if i != 0:
w.addstr(row, column, ', ', curses.A_NORMAL)
column += 2
s, attr = self.slipnode_name_and_attr(d.descriptor)
if d not in description_structures:
s = '[%s]' % s
w.addstr(row, column, s, attr)
column += len(s)
w.addstr(row, column, ')', curses.A_NORMAL)
column += 1
return column
def tick(self, scr, steps, padding_rows, padding_cols, output_rows, output_cols):
height, width = scr.getmaxyx()
in_picture_frame = self.y >= padding_rows and self.y <= padding_rows + output_rows and self.x >= padding_cols and self.x <= padding_cols + output_cols
if self.advances(steps):
# if window was resized and char is out of bounds, reset
self.out_of_bounds_reset(width, height)
# make previous char curses.A_NORMAL
if not in_picture_frame:
if USE_COLORS:
scr.addstr(self.y, self.x, self.char, curses.color_pair(COLOR_CHAR_NORMAL))
else:
scr.addstr(self.y, self.x, self.char, curses.A_NORMAL)
# choose new char and draw it A_REVERSE if not out of bounds
self.char = random.choice(FallingChar.matrixchr).encode(encoding)
self.y += 1
in_picture_frame = self.y >= padding_rows and self.y <= padding_rows + output_rows and self.x >= padding_cols and self.x <= padding_cols + output_cols
if not self.out_of_bounds_reset(width, height) and not in_picture_frame:
if USE_COLORS:
scr.addstr(self.y, self.x, self.char, curses.color_pair(COLOR_CHAR_HIGHLIGHT))
else:
scr.addstr(self.y, self.x, self.char, curses.A_REVERSE)
def start_bottom_window(window, chat_sender):
window.bkgd(curses.A_NORMAL, curses.color_pair(2))
window.clear()
window.box()
window.refresh()
while True:
window.clear()
window.box()
window.refresh()
s = window.getstr(1, 1).decode('utf-8')
if s is not None and s != "":
chat_sender.send_string(s)
# need to do sleep here...
# if bottom window gets down to `window.getstr...` while top window is setting up,
# it registers a bunch of control characters as the user's input
time.sleep(0.005)
def deselect(self):
self.borderbox.bkgd(' ', curses.A_NORMAL)
self.textinpt.bkgd(' ', colors.get_colorpair(self.default_color))
self.refresh()
def deselect(self):
'''
Deselects this Textbox and turns off cursor visiblity.
'''
self.borderbox.bkgd(' ', curses.A_NORMAL)
self.textinpt.bkgd(' ', colors.get_colorpair(self.default_color))
curses.curs_set(0)
self.refresh()
def draw_state(stdscr, state, me):
"""
draw_state draws the state of a MineField onto a curses window.
"""
startx, starty = 1, 1
stdscr.erase()
xoffset = 0
players = state['players']
for idx, pname in enumerate(sorted(players.keys())):
player = players[pname]
field = player['minefield']
width, height = board_termsize(field['width'], field['height'])
namey = starty + height
middlefmt = "{{: ^{}}}"
disp_name = middlefmt.format(width).format(pname)[:width]
if pname == me:
attr = curses_colors.get_colorpair('green-black')
else:
attr = curses.A_NORMAL
for cell in field['cells']:
glyphs = display.assemble_glyphs(cell, player)
for g in glyphs:
stdscr.addstr(g.y + starty, g.x + startx + xoffset, g.strng,
g.attr)
# If a user has died, draw a big 'you're dead' message in the middle of
# their board
if not state['players'][pname]['living']:
dead = middlefmt.format(width).format('WASTED')
h = height // 2
stdscr.addstr(h, startx+xoffset, dead, curses_colors.get_colorpair('yellow-red'))
stdscr.addstr(namey, startx + xoffset, disp_name, attr)
xoffset += width
def __init__(self, this_plant, this_data):
'''Initialization'''
self.initialized = False
self.screen = curses.initscr()
curses.noecho()
curses.raw()
curses.start_color()
try:
curses.curs_set(0)
except curses.error:
# Not all terminals support this functionality.
# When the error is ignored the screen will look a little uglier, but that's not terrible
# So in order to keep botany as accesible as possible to everyone, it should be safe to ignore the error.
pass
self.screen.keypad(1)
self.plant = this_plant
self.user_data = this_data
self.plant_string = self.plant.parse_plant()
self.plant_ticks = str(self.plant.ticks)
self.exit = False
self.infotoggle = 0
self.maxy, self.maxx = self.screen.getmaxyx()
# Highlighted and Normal line definitions
self.define_colors()
self.highlighted = curses.color_pair(1)
self.normal = curses.A_NORMAL
# Threaded screen update for live changes
screen_thread = threading.Thread(target=self.update_plant_live, args=())
screen_thread.daemon = True
screen_thread.start()
self.screen.clear()
self.show(["water","look","garden","instructions"], title=' botany ', subtitle='options')
def draw(self):
# Draw the menu and lines
self.screen.refresh()
try:
self.draw_default()
self.screen.refresh()
except Exception as exception:
# Makes sure data is saved in event of a crash due to window resizing
self.screen.clear()
self.screen.addstr(0, 0, "Enlarge terminal!", curses.A_NORMAL)
self.screen.refresh()
self.__exit__()
traceback.print_exc()
def ascii_render(self, filename, ypos, xpos):
# Prints ASCII art from file at given coordinates
this_dir = os.path.join(os.path.dirname(os.path.realpath(__file__)),"art")
this_filename = os.path.join(this_dir,filename)
this_file = open(this_filename,"r")
this_string = this_file.readlines()
this_file.close()
for y, line in enumerate(this_string, 2):
self.screen.addstr(ypos+y, xpos, line, curses.A_NORMAL)
# self.screen.refresh()
def draw_default(self):
# draws default menu
clear_bar = " " * (int(self.maxx*2/3))
self.screen.addstr(2, 2, self.title, curses.A_STANDOUT) # Title for this menu
self.screen.addstr(4, 2, self.subtitle, curses.A_BOLD) #Subtitle for this menu
# clear menu on screen
for index in range(len(self.options)+1):
self.screen.addstr(5+index, 4, clear_bar, curses.A_NORMAL)
# display all the menu items, showing the 'pos' item highlighted
for index in range(len(self.options)):
textstyle = self.normal
if index == self.selected:
textstyle = self.highlighted
self.screen.addstr(5+index ,4, clear_bar, curses.A_NORMAL)
self.screen.addstr(5+index ,4, "%d - %s" % (index+1, self.options[index]), textstyle)
self.screen.addstr(11, 2, clear_bar, curses.A_NORMAL)
self.screen.addstr(12, 2, clear_bar, curses.A_NORMAL)
self.screen.addstr(11, 2, "plant: ", curses.A_DIM)
self.screen.addstr(11, 9, self.plant_string, curses.A_NORMAL)
self.screen.addstr(12, 2, "score: ", curses.A_DIM)
self.screen.addstr(12, 9, self.plant_ticks, curses.A_NORMAL)
# display fancy water gauge
if not self.plant.dead:
water_gauge_str = self.water_gauge()
self.screen.addstr(5,14, water_gauge_str, curses.A_NORMAL)
else:
self.screen.addstr(5,13, clear_bar, curses.A_NORMAL)
self.screen.addstr(5,13, " ( RIP )", curses.A_NORMAL)
# draw cute ascii from files
self.draw_plant_ascii(self.plant)
def clear_info_pane(self):
# Clears bottom part of screen
clear_bar = " " * (self.maxx-2) + "\n"
clear_block = clear_bar * (self.maxy - 15)
for y, line in enumerate(clear_block.splitlines(), 2):
self.screen.addstr(y+12, 2, line, curses.A_NORMAL)
self.screen.refresh()
def draw_info_text(self, info_text):
# print lines of text to info pane at bottom of screen
if type(info_text) is str:
info_text = info_text.splitlines()
for y, line in enumerate(info_text, 2):
self.screen.addstr(y+12, 2, line, curses.A_NORMAL)
self.screen.refresh()
def move(self, x = None):
if x is not None:
if x < self.x1 or x >= self.x2:
return
self.stdscr.chgat(self.y, self.cursor, 1, curses.A_NORMAL)
self.cursor = x
self.stdscr.chgat(self.y, self.cursor, 1, curses.A_REVERSE)
def display(self):
self.panel.top()
self.panel.show()
self.window.clear()
while True:
self.window.refresh()
curses.doupdate()
for index, item in enumerate(self.items):
if index == self.position:
mode = curses.A_REVERSE
else:
mode = curses.A_NORMAL
msg = '%d. %s' % (index, item[0])
self.window.addstr(1+index, 1, msg, mode)
key = self.window.getch()
if key in [curses.KEY_ENTER, ord('\n')]:
# Handle exit from menu
if self.position == len(self.items)-1 or str(self.items[self.position][1]) == "exit":
break
else:
if self.rootmenu.set_selection(self.items[self.position][1]):
break
elif key == curses.KEY_UP:
self.navigate(-1)
elif key == curses.KEY_DOWN:
self.navigate(1)
self.window.clear()
self.panel.hide()
panel.update_panels()
curses.doupdate()
def tick(self, scr, steps):
if self.step > WINDOW_SIZE:
#stop window animation after some steps
self.draw_frame(scr, self.x - self.step, self.y - self.step,
self.x + self.step, self.y + self.step,
curses.A_NORMAL)
return False
# clear all characters covered by the window frame
for i in range(WINDOW_ANIMATION_SPEED):
anistep = self.step + i
self.draw_frame(scr, self.x - anistep, self.y - anistep,
self.x + anistep, self.y + anistep,
curses.A_NORMAL, ' ')
#cancel last animation
self.draw_frame(scr, self.x - self.step, self.y - self.step,
self.x + self.step, self.y + self.step,
curses.A_NORMAL)
#next step
self.step += WINDOW_ANIMATION_SPEED
#draw outer frame
self.draw_frame(scr, self.x - self.step, self.y - self.step,
self.x + self.step, self.y + self.step,
curses.A_REVERSE)
return True
def banner(self):
"""
Draw the banner in the TUI window.
"""
screen = self._stdscr.subwin(2, 80, 0, 0)
screen.bkgd(' ', curses.color_pair(1))
# Set local variable
title = curses.A_NORMAL
title += curses.A_BOLD
normal = curses.color_pair(4)
# Print title
screen.addstr(0, 0, self.__title.center(79), title)
screen.addstr(1, 0, "Setup".center(10), normal)
screen.refresh()
def footer(self):
"""
Draw the footer in the TUI window.
"""
screen = self._stdscr.subwin(1, 80, 23, 0)
screen.bkgd(' ', curses.color_pair(1))
# Set local variable
normal = curses.A_NORMAL
# Copyright info
copyleft = self.__copyleft
screen.addstr(0, 0, copyleft.center(79), normal)
screen.refresh()
def configure_settings_frame(self, pos=None):
"""
Draw `Configure Setting` frame with a index number (`pos`) of the item
selected.
:param pos: Index of selected item in `Configure Setting` frame. The
default value of `pos` is `None`.
:type pos: int or None
.. note:: None of the items in `Configure Setting` frame would be
selected if pos is `None`.
"""
self._stdscr.keypad(1)
screen = self._stdscr.subwin(8, 25, 2, 0)
screen.bkgd(' ', curses.color_pair(4))
# Set local variable
normal = curses.A_NORMAL
select = curses.color_pair(5)
select += curses.A_BOLD
for p, item in enumerate(self.settings):
item_str = item[0].ljust(12)
screen.addstr(3 + p, 2, item_str, select if p == pos else normal)
if p:
choice = "[%s]" % item[2][item[1]]
else:
choice = "[%s]" % item[2][item[1]]["label"]
screen.addstr(3 + p, 15, ''.ljust(10), normal)
screen.addstr(3 + p, 15, choice, select if p == pos else normal)
screen.refresh()
def sub_selection_dialog(self, pos):
"""
Draw a `Selection Dialog` on screen used to make configurations.
:param pos: Index of selected item in `Configure Setting` frame.
:type pos: int
.. warning:: The value of `pos` MUST NOT be `None`.
:return: A **WindowObject** which represents the selection dialog.
:rtype: WindowObject
"""
i_len = len(self.settings[pos][2])
# Draw Shadow
shadow = curses.newwin(i_len + 2, 18, 13 - i_len / 2, 31)
shadow.bkgd(' ', curses.color_pair(8))
shadow.refresh()
# Draw Subwindow
screen = curses.newwin(i_len + 2, 18, 12 - i_len / 2, 30)
screen.box()
screen.bkgd(' ', curses.color_pair(1))
screen.keypad(1)
# Set local variable
normal = curses.A_NORMAL
# Title of Subwindow
screen.addstr(0, 3, self.settings[pos][0].center(12), normal)
return screen
def cpprint(self, print_string, finish=False, reverse=False):
if self.use_curses:
try:
attr = curses.A_NORMAL
if reverse:
attr = curses.A_REVERSE
if self.start:
self.scrn.erase()
self.start = False
hw = self.scrn.getmaxyx()
pos = self.scrn.getyx()
if pos[0] < hw[0] and pos[1] == 0:
print_string = print_string[:hw[1] - 1]
self.scrn.addstr(print_string, attr)
if pos[0] + 1 < hw[0]:
self.scrn.move(pos[0] + 1, 0)
if finish:
self.scrn.refresh()
self.start = True
except curses.CursesError as e:
# show curses errors at top of screen for easier debugging
self.scrn.move(0, 0)
self.scrn.addstr("{} {} {} {}\n".format(type(e), e, pos, hw),
attr)
self.scrn.addstr(print_string + "\n", attr)
else:
print print_string
def addstr(self, y, x, s, attr=curses.A_NORMAL):
try:
self.w.addstr(y, x, s, attr)
except Exception as e:
if str(e) != 'addstr() returned ERR':
raise
def slipnode_name_and_attr(self, slipnode):
if slipnode.activation == 100:
return (slipnode.name.upper(), curses.A_STANDOUT)
if slipnode.activation > 50:
return (slipnode.name.upper(), curses.A_BOLD)
else:
return (slipnode.name.lower(), curses.A_NORMAL)
def depict_bond(self, w, row, column, bond):
slipnet = bond.ctx.slipnet
if bond.directionCategory == slipnet.right:
s = '-- %s -->' % bond.category.name
elif bond.directionCategory == slipnet.left:
s = '<-- %s --' % bond.category.name
elif bond.directionCategory is None:
s = '<-- %s -->' % bond.category.name
if isinstance(bond.leftObject, Group):
s = 'G' + s
if isinstance(bond.rightObject, Group):
s = s + 'G'
w.addstr(row, column, s, curses.A_NORMAL)
return column + len(s)
def ignore_error_add_str(win, y, x, s, attr=curses.A_NORMAL):
"""???????????????????????????????????????"""
try:
win.addstr(y, x, s, attr)
except curses.error:
pass