📄 calc.py
字号:
last_op = None else: last_cell = self.walker.get_cell(i-1) x = last_cell.get_result() if x is not None and focus_cell.op is not None: x = OPERATORS[focus_cell.op]( x, focus_cell.get_value() ) focus_cell.set_result(x) for cell in self.content[i+1:]: if cell.op is None: x = None if x is not None: x = OPERATORS[cell.op]( x, cell.get_value() ) if cell.get_result() == x: return False cell.set_result(x) return True def create_child( self, letter ): """Return (parent cell,child column) or None,None on failure.""" f, (i, sub) = self.walker.get_focus() if sub != 0: # f is not an edit widget return None, None cell = self.walker.get_cell(i) if cell.child is not None: raise CalcEvent, E_new_col_cell_not_empty if cell.edit.edit_text: raise CalcEvent, E_new_col_cell_not_empty child = CellColumn( letter ) cell.become_parent( child, letter ) return cell, child def is_empty( self ): """Return True if this column is empty.""" return len(self.content)==1 and self.content[0].is_empty() def get_expression(self): """Return the expression as a printable string.""" l = [] for c in self.content: if c.op is not None: # only applies to first cell l.append(c.op) if c.child is not None: l.append("("+c.child.get_expression()+")") else: l.append("%d"%c.get_value()) return "".join(l) def get_result(self): """Return the result of the last cell in the column.""" return self.content[-1].get_result() class HelpColumn(urwid.BoxWidget): help_text = [ ('title', "Column Calculator"), "", [ "Numbers: ", ('key', "0"), "-", ('key', "9") ], "" , [ "Operators: ",('key', "+"), ", ", ('key', "-"), ", ", ('key', "*"), " and ", ('key', "/")], "", [ "Editing: ", ('key', "BACKSPACE"), " and ",('key', "DELETE")], "", [ "Movement: ", ('key', "UP"), ", ", ('key', "DOWN"), ", ", ('key', "LEFT"), ", ", ('key', "RIGHT"), ", ", ('key', "PAGE UP"), " and ", ('key', "PAGE DOWN") ], "", [ "Sub-expressions: ", ('key', "("), " and ", ('key', ")") ], "", [ "Columns: ", ('key', COLUMN_KEYS[0]), " and ", ('key',COLUMN_KEYS[1]), "-", ('key',COLUMN_KEYS[-1]) ], "", [ "Exit: ", ('key', "Q") ], "", "", ["Column Calculator does operations in the order they are ", "typed, not by following usual precedence rules. ", "If you want to calculate ", ('key', "12 - 2 * 3"), " with the multiplication happening before the ", "subtraction you must type ", ('key', "12 - (2 * 3)"), " instead."], ] def __init__(self): self.head = urwid.AttrWrap( urwid.Text(["Help Column ", ('key',"?")], layout = CALC_LAYOUT), 'help') self.foot = urwid.AttrWrap( urwid.Text(["[text continues.. press ", ('key',"?"), " then scroll]"]), 'helpnote' ) self.items = [urwid.Text(x) for x in self.help_text] self.listbox = urwid.ListBox(urwid.SimpleListWalker(self.items)) self.body = urwid.AttrWrap( self.listbox, 'help' ) self.frame = urwid.Frame( self.body, header=self.head) def render( self, (maxcol, maxrow), focus=False): head_rows = self.head.rows( (maxcol,) ) if "bottom" in self.listbox.ends_visible( (maxcol, maxrow-head_rows) ): self.frame.footer = None else: self.frame.footer = self.foot return self.frame.render( (maxcol, maxrow), focus) def keypress( self, size, key ): return self.frame.keypress( size, key ) class CalcDisplay: palette = [ ('body','white', 'dark blue'), ('edit','yellow', 'dark blue'), ('editfocus','yellow','dark cyan', 'bold'), ('key','dark cyan', 'light gray', ('standout','underline')), ('title', 'white', 'light gray', ('bold','standout')), ('help', 'black', 'light gray', 'standout'), ('helpnote', 'dark green', 'light gray'), ('colhead', 'black', 'light gray', 'standout'), ('event', 'light red', 'black', 'standout'), ('confirm', 'yellow', 'black', 'bold'), ] def __init__(self): self.columns = urwid.Columns([HelpColumn(), CellColumn("A")], 1) self.col_list = self.columns.widget_list self.columns.set_focus_column( 1 ) self.view = urwid.AttrWrap( self.columns, 'body' ) self.col_link = {} def main(self): self.ui = Screen() self.ui.register_palette( self.palette ) self.ui.run_wrapper( self.run ) # on exit write the formula and the result to the console expression, result = self.get_expression_result() print "Paste this expression into a new Column Calculator session to continue editing:" print expression print "Result:", result def run(self): """Update screen and accept user input.""" self.ui.set_mouse_tracking() size = self.ui.get_cols_rows() self.event = None while 1: # draw the screen view = self.view if self.event is not None: # show the event too view = urwid.Frame( view, footer=self.event.widget() ) canvas = view.render( size, focus=1 ) self.ui.draw_screen( size, canvas ) # wait until we get some input keys = None while not keys: # this call returns None when it times out keys = self.ui.get_input() # handle each key one at a time for k in keys: if urwid.is_mouse_event(k): event, button, col, row = k view.mouse_event( size, event, button, col, row, focus=True ) continue if k == 'window resize': # read the new screen size size = self.ui.get_cols_rows() continue elif k in ('q','Q'): # exit main loop return # handle other keystrokes try: self.wrap_keypress( size, k ) self.event = None except CalcEvent, e: self.event = e def wrap_keypress(self, size, key): """Handle confirmation and throw event on bad input.""" try: key = self.keypress(size, key) except ColumnDeleteEvent, e: if e.letter == COLUMN_KEYS[1]: # cannot delete the first column, ignore key return if not self.column_empty( e.letter ): # need to get two in a row, so check last event if not isinstance(self.event,ColumnDeleteEvent): # ask for confirmation raise e self.delete_column(e.letter) except UpdateParentEvent, e: self.update_parent_columns() return if key is None: return if self.columns.get_focus_column() == 0: if key not in ('up','down','page up','page down'): raise CalcEvent, E_invalid_in_help_col if key not in EDIT_KEYS and key not in MOVEMENT_KEYS: raise CalcEvent, E_invalid_key % key.upper() def keypress(self, size, key): """Handle a keystroke.""" # let the view try to handle it first key = self.view.keypress( size, key ) if key is None: return if key.upper() in COLUMN_KEYS: # column switch i = COLUMN_KEYS.index(key.upper()) if i >= len( self.col_list ): raise CalcEvent, E_no_such_column % key.upper() self.columns.set_focus_column( i ) return elif key == "(": # open a new column if len( self.col_list ) >= len(COLUMN_KEYS): raise CalcEvent, E_no_more_columns i = self.columns.get_focus_column() if i == 0: # makes no sense in help column return key col = self.col_list[i] new_letter = COLUMN_KEYS[len(self.col_list)] parent, child = col.create_child( new_letter ) if child is None: # something invalid in focus return key self.col_list.append(child) self.set_link( parent, col, child ) self.columns.set_focus_column(len(self.col_list)-1) elif key == ")": i = self.columns.get_focus_column() if i == 0: # makes no sense in help column return key col = self.col_list[i] parent, pcol = self.get_parent( col ) if parent is None: # column has no parent raise CalcEvent, E_no_parent_column new_i = self.col_list.index( pcol ) self.columns.set_focus_column( new_i ) else: return key def set_link( self, parent, pcol, child ): """Store the link between a parent cell and child column. parent -- parent Cell object pcol -- CellColumn where parent resides child -- child CellColumn object""" self.col_link[ child ] = parent, pcol def get_parent( self, child ): """Return the parent and parent column for a given column.""" return self.col_link.get( child, (None,None) ) def column_empty(self, letter): """Return True if the column passed is empty.""" i = COLUMN_KEYS.index(letter) col = self.col_list[i] return col.is_empty() def delete_column(self, letter): """Delete the column with the given letter.""" i = COLUMN_KEYS.index(letter) col = self.col_list[i] parent, pcol = self.get_parent( col ) f = self.columns.get_focus_column() if f == i: # move focus to the parent column f = self.col_list.index(pcol) self.columns.set_focus_column(f) parent.remove_child() pcol.update_results(parent) del self.col_list[i] # delete children of this column keep_right_cols = [] remove_cols = [col] for rcol in self.col_list[i:]: parent, pcol = self.get_parent( rcol ) if pcol in remove_cols: remove_cols.append( rcol ) else: keep_right_cols.append( rcol ) for rc in remove_cols: # remove the links del self.col_link[rc] # keep only the non-children self.col_list[i:] = keep_right_cols # fix the letter assigmnents for j in range(i, len(self.col_list)): col = self.col_list[j] # fix the column heading col.set_letter( COLUMN_KEYS[j] ) parent, pcol = self.get_parent( col ) # fix the parent cell parent.edit.set_letter( COLUMN_KEYS[j] ) def update_parent_columns(self): "Update the parent columns of the current focus column." f = self.columns.get_focus_column() col = self.col_list[f] while 1: parent, pcol = self.get_parent(col) if pcol is None: return changed = pcol.update_results( start_from = parent ) if not changed: return col = pcol def get_expression_result(self): """Return (expression, result) as strings.""" col = self.col_list[1] return col.get_expression(), "%d"%col.get_result() class CalcNumLayout(urwid.TextLayout): """ TextLayout class for bottom-right aligned numbers with a space on the last line for the cursor. """ def layout( self, text, width, align, wrap ): """ Return layout structure for calculator number display. """ lt = len(text) + 1 # extra space for cursor r = (lt) % width # remaining segment not full width wide linestarts = range( r, lt, width ) l = [] if linestarts: if r: # right-align the remaining segment on 1st line l.append( [(width-r,None),(r, 0, r)] ) # fill all but the last line for x in linestarts[:-1]: l.append( [(width, x, x+width)] ) s = linestarts[-1] # add the last line with a cursor hint l.append( [(width-1, s, lt-1), (0, lt-1)] ) elif lt-1: # all fits on one line, so right align the text # with a cursor hint at the end l.append( [(width-lt,None),(lt-1,0,lt-1), (0,lt-1)] ) else: # nothing on the line, right align a cursor hint l.append( [(width-1,None),(0,0)] ) return l def main(): """Launch Column Calculator.""" global CALC_LAYOUT CALC_LAYOUT = CalcNumLayout() urwid.web_display.set_preferences("Column Calculator") # try to handle short web requests quickly if urwid.web_display.handle_short_request(): return CalcDisplay().main()if '__main__'==__name__ or urwid.web_display.is_web_request(): main()
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -