def __init__(self, parent, title=None, content=""): Toplevel.__init__(self, parent) self.transient(parent) self.log = logging.getLogger(__name__) if title: self.title(title) self.parent = parent self.body = Frame(self) self.fill_body(content) self.body.pack(padx=5, pady=5) self.create_buttonbox() self.grab_set() self.protocol("WM_DELETE_WINDOW", self.ok) self.geometry("+%d+%d" % (parent.winfo_rootx() + 50, parent.winfo_rooty() + 50)) self.focus_set() self.wait_window(self)
def __init__(self, message, value=None, **extra): self._prevent_execution_with_timeouts() self._parent = self._get_parent() Toplevel.__init__(self, self._parent) self._initialize_dialog() self._create_body(message, value, **extra) self._create_buttons() self._result = None
def __init__(self, sms): Toplevel.__init__(self) self._sms = sms self.title("SMS from %s" % sms["address"]) v = SMSView(sms, self) v.pack(fill=BOTH, expand=True)
def __init__(self, parent, cfg=None, set_cfg_callback=None): self._parent = parent if cfg is not None: self._cfg = cfg else: self._cfg = CFG(Nonterminal('S'), []) self._set_cfg_callback = set_cfg_callback self._highlight_matching_nonterminals = 1 # Create the top-level window. self._top = Toplevel(parent) self._init_bindings() self._init_startframe() self._startframe.pack(side='top', fill='x', expand=0) self._init_prodframe() self._prodframe.pack(side='top', fill='both', expand=1) self._init_buttons() self._buttonframe.pack(side='bottom', fill='x', expand=0) self._textwidget.focus()
def title(self, value = None): if value is None: return self.var or Toplevel.title(self) if not isinstance(value, variables): # anything else, e.g. `str` if self.var: self.var.set(value) else: Toplevel.title(self, value) return if value is self.var: return if self.var is not None: self.var.trace_vdelete("w", self.observer_name) self.var = value self.observer_name = value.trace_variable( "w", self.on_var_changed ) self.on_var_changed()
def __create_content(self): self.__rootFrame = TKTk() self.__rootFrame.withdraw() self.__top = TKToplevel(self.__rootFrame) self.__top.title("Login") self.__top.protocol("WM_DELETE_WINDOW", self.__rootFrame.destroy) self.__top.bind('<Return>', self.__enter_action) self.__top.update_idletasks() width = self.__top.winfo_width() height = self.__top.winfo_height() x = (self.__top.winfo_screenwidth() // 2) - (width // 2) y = (self.__top.winfo_screenheight() // 2) - (height // 2) self.__top.geometry("+%d+%d" % (x, y)) row = 0 expLabel = TKLabel(self.__top, text='Login to host:') expLabel.grid(row=row, column=0, columnspan=4, padx=5, pady=2) row = row + 1 urlLabel = TKLabel(self.__top, text=self.__host) urlLabel.grid(row=row, column=0, columnspan=4, padx=5, pady=2) row = row + 1 usrLabel = TKLabel(self.__top, text='User') usrLabel.grid(row=row, column=0, columnspan=2, padx=20, pady=5) self.__usrEntry = TKEntry(self.__top, width=20) self.__usrEntry.grid(row=row, column=2, columnspan=2, padx=5, pady=5) row = row + 1 pwdLabel = TKLabel(self.__top, text='Password') pwdLabel.grid(row=row, column=0, columnspan=2, padx=20, pady=5) self.__pwdEntry = TKEntry(self.__top, width=20, show="*") self.__pwdEntry.grid(row=row, column=2, columnspan=2, padx=5, pady=5) row = row + 1 cancelButton = TKButton(self.__top, text='Cancel', command=self.__cancel_action) cancelButton.grid(row=row, column=1, padx=5, pady=5) loginButton = TKButton(self.__top, text='Login', command=self.__login_action) loginButton.grid(row=row, column=2, padx=5, pady=5)
def __create_content(self): self.__rootFrame = TKTk() self.__rootFrame.withdraw() self.__top = TKToplevel(self.__rootFrame) self.__top.title("Login") self.__top.protocol("WM_DELETE_WINDOW", self.__rootFrame.destroy) self.__top.bind('<Return>', self.__enter_action) self.__top.update_idletasks() width = self.__top.winfo_width() height = self.__top.winfo_height() x = (self.__top.winfo_screenwidth() // 2) - (width // 2) y = (self.__top.winfo_screenheight() // 2) - (height // 2) self.__top.geometry("+%d+%d" % (x, y)) row = 0 expLabel = TKLabel(self.__top, text='Login to host:') expLabel.grid(row=row, column=0, columnspan=4, padx=5, pady=2) row = row+1 urlLabel = TKLabel(self.__top, text=self.__host) urlLabel.grid(row=row, column=0, columnspan=4, padx=5, pady=2) row = row+1 usrLabel = TKLabel(self.__top, text='User') usrLabel.grid(row=row, column=0, columnspan=2, padx=20, pady=5) self.__usrEntry = TKEntry(self.__top, width=20) self.__usrEntry.grid(row=row, column=2, columnspan=2, padx=5, pady=5) row = row+1 pwdLabel = TKLabel(self.__top, text='Password') pwdLabel.grid(row=row, column=0, columnspan=2, padx=20, pady=5) self.__pwdEntry = TKEntry(self.__top, width=20, show="*") self.__pwdEntry.grid(row=row, column=2, columnspan=2, padx=5, pady=5) row = row+1 cancelButton = TKButton(self.__top, text='Cancel', command=self.__cancel_action) cancelButton.grid(row=row, column=1, padx=5, pady=5) loginButton = TKButton(self.__top, text='Login', command=self.__login_action) loginButton.grid(row=row, column=2, padx=5, pady=5)
class TkWindowNode(BaseWindowNode): '''The base class of all the Window Node in the WaveSyn Object Model. Properties: tk_object: The underlying Tk Toplevel object; node_path: The path of this node on the WaveSyn Object Model Tree. Properties inherited from ModelNode: root_node: The root node of the WaveSyn Object Model Tree. ''' window_name = '' _xmlrpcexport_ = ['close'] def __init__(self, *args, **kwargs): super(TkWindowNode, self).__init__(*args, **kwargs) self.__tk_object = Toplevel() self.__tk_object.title(eval_format('{self.window_name} id={id(self)}')) self.__tk_object.protocol('WM_DELETE_WINDOW', self.on_close) method_name_map = { 'update':'update', 'set_window_attributes':'wm_attributes' } for method_name in method_name_map: locals()[method_name] = MethodDelegator('tk_object', method_name_map[method_name]) @Scripting.printable def close(self): Scripting.root_node.on_window_quit(self) # For Toplevel objects, use destroy rather than quit. self.__tk_object.destroy() def on_close(self): with code_printer: self.close() @property def node_path(self): if isinstance(self.parent_node, WindowDict): return eval_format('{self.parent_node.node_path}[{id(self)}]') else: return ModelNode.node_path.__get__(self) @property def tk_object(self): return self.__tk_object
class LoginDialog(object): def __init__(self, host): self.__interna_init() self.__host = host self.__create_content() def __interna_init(self): self.__rootFrame = None self.__top = None self.__usrEntry = None self.__pwdEntry = None self.__accepted = False self.__host = None self.__usr = None self.__pwd = None def __cancel_action(self): self.__accepted = False self.__rootFrame.destroy() def __login_action(self): self.__accepted = True self.__usr = self.__usrEntry.get() self.__pwd = self.__pwdEntry.get() self.__rootFrame.destroy() def __enter_action(self, event): self.__login_action() def __create_content(self): self.__rootFrame = TKTk() self.__rootFrame.withdraw() self.__top = TKToplevel(self.__rootFrame) self.__top.title("Login") self.__top.protocol("WM_DELETE_WINDOW", self.__rootFrame.destroy) self.__top.bind('<Return>', self.__enter_action) self.__top.update_idletasks() width = self.__top.winfo_width() height = self.__top.winfo_height() x = (self.__top.winfo_screenwidth() // 2) - (width // 2) y = (self.__top.winfo_screenheight() // 2) - (height // 2) self.__top.geometry("+%d+%d" % (x, y)) row = 0 expLabel = TKLabel(self.__top, text='Login to host:') expLabel.grid(row=row, column=0, columnspan=4, padx=5, pady=2) row = row+1 urlLabel = TKLabel(self.__top, text=self.__host) urlLabel.grid(row=row, column=0, columnspan=4, padx=5, pady=2) row = row+1 usrLabel = TKLabel(self.__top, text='User') usrLabel.grid(row=row, column=0, columnspan=2, padx=20, pady=5) self.__usrEntry = TKEntry(self.__top, width=20) self.__usrEntry.grid(row=row, column=2, columnspan=2, padx=5, pady=5) row = row+1 pwdLabel = TKLabel(self.__top, text='Password') pwdLabel.grid(row=row, column=0, columnspan=2, padx=20, pady=5) self.__pwdEntry = TKEntry(self.__top, width=20, show="*") self.__pwdEntry.grid(row=row, column=2, columnspan=2, padx=5, pady=5) row = row+1 cancelButton = TKButton(self.__top, text='Cancel', command=self.__cancel_action) cancelButton.grid(row=row, column=1, padx=5, pady=5) loginButton = TKButton(self.__top, text='Login', command=self.__login_action) loginButton.grid(row=row, column=2, padx=5, pady=5) def show_login(self): self.__usrEntry.focus_set() self.__rootFrame.mainloop() def is_accepted(self): return self.__accepted def get_user(self): return self.__usr def get_password(self): return self.__pwd
class CFGEditor(object): """ A dialog window for creating and editing context free grammars. ``CFGEditor`` imposes the following restrictions: - All nonterminals must be strings consisting of word characters. - All terminals must be strings consisting of word characters and space characters. """ # Regular expressions used by _analyze_line. Precompile them, so # we can process the text faster. ARROW = SymbolWidget.SYMBOLS['rightarrow'] _LHS_RE = re.compile(r"(^\s*\w+\s*)(->|("+ARROW+"))") _ARROW_RE = re.compile("\s*(->|("+ARROW+"))\s*") _PRODUCTION_RE = re.compile(r"(^\s*\w+\s*)" + # LHS "(->|("+ARROW+"))\s*" + # arrow r"((\w+|'[\w ]*'|\"[\w ]*\"|\|)\s*)*$") # RHS _TOKEN_RE = re.compile("\\w+|->|'[\\w ]+'|\"[\\w ]+\"|("+ARROW+")") _BOLD = ('helvetica', -12, 'bold') def __init__(self, parent, cfg=None, set_cfg_callback=None): self._parent = parent if cfg is not None: self._cfg = cfg else: self._cfg = CFG(Nonterminal('S'), []) self._set_cfg_callback = set_cfg_callback self._highlight_matching_nonterminals = 1 # Create the top-level window. self._top = Toplevel(parent) self._init_bindings() self._init_startframe() self._startframe.pack(side='top', fill='x', expand=0) self._init_prodframe() self._prodframe.pack(side='top', fill='both', expand=1) self._init_buttons() self._buttonframe.pack(side='bottom', fill='x', expand=0) self._textwidget.focus() def _init_startframe(self): frame = self._startframe = Frame(self._top) self._start = Entry(frame) self._start.pack(side='right') Label(frame, text='Start Symbol:').pack(side='right') Label(frame, text='Productions:').pack(side='left') self._start.insert(0, self._cfg.start().symbol()) def _init_buttons(self): frame = self._buttonframe = Frame(self._top) Button(frame, text='Ok', command=self._ok, underline=0, takefocus=0).pack(side='left') Button(frame, text='Apply', command=self._apply, underline=0, takefocus=0).pack(side='left') Button(frame, text='Reset', command=self._reset, underline=0, takefocus=0,).pack(side='left') Button(frame, text='Cancel', command=self._cancel, underline=0, takefocus=0).pack(side='left') Button(frame, text='Help', command=self._help, underline=0, takefocus=0).pack(side='right') def _init_bindings(self): self._top.title('CFG Editor') self._top.bind('<Control-q>', self._cancel) self._top.bind('<Alt-q>', self._cancel) self._top.bind('<Control-d>', self._cancel) #self._top.bind('<Control-x>', self._cancel) self._top.bind('<Alt-x>', self._cancel) self._top.bind('<Escape>', self._cancel) #self._top.bind('<Control-c>', self._cancel) self._top.bind('<Alt-c>', self._cancel) self._top.bind('<Control-o>', self._ok) self._top.bind('<Alt-o>', self._ok) self._top.bind('<Control-a>', self._apply) self._top.bind('<Alt-a>', self._apply) self._top.bind('<Control-r>', self._reset) self._top.bind('<Alt-r>', self._reset) self._top.bind('<Control-h>', self._help) self._top.bind('<Alt-h>', self._help) self._top.bind('<F1>', self._help) def _init_prodframe(self): self._prodframe = Frame(self._top) # Create the basic Text widget & scrollbar. self._textwidget = Text(self._prodframe, background='#e0e0e0', exportselection=1) self._textscroll = Scrollbar(self._prodframe, takefocus=0, orient='vertical') self._textwidget.config(yscrollcommand = self._textscroll.set) self._textscroll.config(command=self._textwidget.yview) self._textscroll.pack(side='right', fill='y') self._textwidget.pack(expand=1, fill='both', side='left') # Initialize the colorization tags. Each nonterminal gets its # own tag, so they aren't listed here. self._textwidget.tag_config('terminal', foreground='#006000') self._textwidget.tag_config('arrow', font='symbol') self._textwidget.tag_config('error', background='red') # Keep track of what line they're on. We use that to remember # to re-analyze a line whenever they leave it. self._linenum = 0 # Expand "->" to an arrow. self._top.bind('>', self._replace_arrows) # Re-colorize lines when appropriate. self._top.bind('<<Paste>>', self._analyze) self._top.bind('<KeyPress>', self._check_analyze) self._top.bind('<ButtonPress>', self._check_analyze) # Tab cycles focus. (why doesn't this work??) def cycle(e, textwidget=self._textwidget): textwidget.tk_focusNext().focus() self._textwidget.bind('<Tab>', cycle) prod_tuples = [(p.lhs(),[p.rhs()]) for p in self._cfg.productions()] for i in range(len(prod_tuples)-1,0,-1): if (prod_tuples[i][0] == prod_tuples[i-1][0]): if () in prod_tuples[i][1]: continue if () in prod_tuples[i-1][1]: continue print(prod_tuples[i-1][1]) print(prod_tuples[i][1]) prod_tuples[i-1][1].extend(prod_tuples[i][1]) del prod_tuples[i] for lhs, rhss in prod_tuples: print(lhs, rhss) s = '%s ->' % lhs for rhs in rhss: for elt in rhs: if isinstance(elt, Nonterminal): s += ' %s' % elt else: s += ' %r' % elt s += ' |' s = s[:-2] + '\n' self._textwidget.insert('end', s) self._analyze() # # Add the producitons to the text widget, and colorize them. # prod_by_lhs = {} # for prod in self._cfg.productions(): # if len(prod.rhs()) > 0: # prod_by_lhs.setdefault(prod.lhs(),[]).append(prod) # for (lhs, prods) in prod_by_lhs.items(): # self._textwidget.insert('end', '%s ->' % lhs) # self._textwidget.insert('end', self._rhs(prods[0])) # for prod in prods[1:]: # print '\t|'+self._rhs(prod), # self._textwidget.insert('end', '\t|'+self._rhs(prod)) # print # self._textwidget.insert('end', '\n') # for prod in self._cfg.productions(): # if len(prod.rhs()) == 0: # self._textwidget.insert('end', '%s' % prod) # self._analyze() # def _rhs(self, prod): # s = '' # for elt in prod.rhs(): # if isinstance(elt, Nonterminal): s += ' %s' % elt.symbol() # else: s += ' %r' % elt # return s def _clear_tags(self, linenum): """ Remove all tags (except ``arrow`` and ``sel``) from the given line of the text widget used for editing the productions. """ start = '%d.0'%linenum end = '%d.end'%linenum for tag in self._textwidget.tag_names(): if tag not in ('arrow', 'sel'): self._textwidget.tag_remove(tag, start, end) def _check_analyze(self, *e): """ Check if we've moved to a new line. If we have, then remove all colorization from the line we moved to, and re-colorize the line that we moved from. """ linenum = int(self._textwidget.index('insert').split('.')[0]) if linenum != self._linenum: self._clear_tags(linenum) self._analyze_line(self._linenum) self._linenum = linenum def _replace_arrows(self, *e): """ Replace any ``'->'`` text strings with arrows (char \\256, in symbol font). This searches the whole buffer, but is fast enough to be done anytime they press '>'. """ arrow = '1.0' while True: arrow = self._textwidget.search('->', arrow, 'end+1char') if arrow == '': break self._textwidget.delete(arrow, arrow+'+2char') self._textwidget.insert(arrow, self.ARROW, 'arrow') self._textwidget.insert(arrow, '\t') arrow = '1.0' while True: arrow = self._textwidget.search(self.ARROW, arrow+'+1char', 'end+1char') if arrow == '': break self._textwidget.tag_add('arrow', arrow, arrow+'+1char') def _analyze_token(self, match, linenum): """ Given a line number and a regexp match for a token on that line, colorize the token. Note that the regexp match gives us the token's text, start index (on the line), and end index (on the line). """ # What type of token is it? if match.group()[0] in "'\"": tag = 'terminal' elif match.group() in ('->', self.ARROW): tag = 'arrow' else: # If it's a nonterminal, then set up new bindings, so we # can highlight all instances of that nonterminal when we # put the mouse over it. tag = 'nonterminal_'+match.group() if tag not in self._textwidget.tag_names(): self._init_nonterminal_tag(tag) start = '%d.%d' % (linenum, match.start()) end = '%d.%d' % (linenum, match.end()) self._textwidget.tag_add(tag, start, end) def _init_nonterminal_tag(self, tag, foreground='blue'): self._textwidget.tag_config(tag, foreground=foreground, font=CFGEditor._BOLD) if not self._highlight_matching_nonterminals: return def enter(e, textwidget=self._textwidget, tag=tag): textwidget.tag_config(tag, background='#80ff80') def leave(e, textwidget=self._textwidget, tag=tag): textwidget.tag_config(tag, background='') self._textwidget.tag_bind(tag, '<Enter>', enter) self._textwidget.tag_bind(tag, '<Leave>', leave) def _analyze_line(self, linenum): """ Colorize a given line. """ # Get rid of any tags that were previously on the line. self._clear_tags(linenum) # Get the line line's text string. line = self._textwidget.get(repr(linenum)+'.0', repr(linenum)+'.end') # If it's a valid production, then colorize each token. if CFGEditor._PRODUCTION_RE.match(line): # It's valid; Use _TOKEN_RE to tokenize the production, # and call analyze_token on each token. def analyze_token(match, self=self, linenum=linenum): self._analyze_token(match, linenum) return '' CFGEditor._TOKEN_RE.sub(analyze_token, line) elif line.strip() != '': # It's invalid; show the user where the error is. self._mark_error(linenum, line) def _mark_error(self, linenum, line): """ Mark the location of an error in a line. """ arrowmatch = CFGEditor._ARROW_RE.search(line) if not arrowmatch: # If there's no arrow at all, highlight the whole line. start = '%d.0' % linenum end = '%d.end' % linenum elif not CFGEditor._LHS_RE.match(line): # Otherwise, if the LHS is bad, highlight it. start = '%d.0' % linenum end = '%d.%d' % (linenum, arrowmatch.start()) else: # Otherwise, highlight the RHS. start = '%d.%d' % (linenum, arrowmatch.end()) end = '%d.end' % linenum # If we're highlighting 0 chars, highlight the whole line. if self._textwidget.compare(start, '==', end): start = '%d.0' % linenum end = '%d.end' % linenum self._textwidget.tag_add('error', start, end) def _analyze(self, *e): """ Replace ``->`` with arrows, and colorize the entire buffer. """ self._replace_arrows() numlines = int(self._textwidget.index('end').split('.')[0]) for linenum in range(1, numlines+1): # line numbers start at 1. self._analyze_line(linenum) def _parse_productions(self): """ Parse the current contents of the textwidget buffer, to create a list of productions. """ productions = [] # Get the text, normalize it, and split it into lines. text = self._textwidget.get('1.0', 'end') text = re.sub(self.ARROW, '->', text) text = re.sub('\t', ' ', text) lines = text.split('\n') # Convert each line to a CFG production for line in lines: line = line.strip() if line=='': continue productions += _read_cfg_production(line) #if line.strip() == '': continue #if not CFGEditor._PRODUCTION_RE.match(line): # raise ValueError('Bad production string %r' % line) # #(lhs_str, rhs_str) = line.split('->') #lhs = Nonterminal(lhs_str.strip()) #rhs = [] #def parse_token(match, rhs=rhs): # token = match.group() # if token[0] in "'\"": rhs.append(token[1:-1]) # else: rhs.append(Nonterminal(token)) # return '' #CFGEditor._TOKEN_RE.sub(parse_token, rhs_str) # #productions.append(Production(lhs, *rhs)) return productions def _destroy(self, *e): if self._top is None: return self._top.destroy() self._top = None def _ok(self, *e): self._apply() self._destroy() def _apply(self, *e): productions = self._parse_productions() start = Nonterminal(self._start.get()) cfg = CFG(start, productions) if self._set_cfg_callback is not None: self._set_cfg_callback(cfg) def _reset(self, *e): self._textwidget.delete('1.0', 'end') for production in self._cfg.productions(): self._textwidget.insert('end', '%s\n' % production) self._analyze() if self._set_cfg_callback is not None: self._set_cfg_callback(self._cfg) def _cancel(self, *e): try: self._reset() except: pass self._destroy() def _help(self, *e): # The default font's not very legible; try using 'fixed' instead. try: ShowText(self._parent, 'Help: Chart Parser Demo', (_CFGEditor_HELP).strip(), width=75, font='fixed') except: ShowText(self._parent, 'Help: Chart Parser Demo', (_CFGEditor_HELP).strip(), width=75)
def __init__(self, *args, **kw): self.var = None Toplevel.__init__(self, *args, **kw)
class LoginDialog(object): def __init__(self, host): self.__interna_init() self.__host = host self.__initialized = False if TKTk is not None: self.__create_content() self.__initialized = True def __interna_init(self): self.__rootFrame = None self.__top = None self.__usrEntry = None self.__pwdEntry = None self.__accepted = False self.__host = None self.__usr = None self.__pwd = None def __cancel_action(self): self.__accepted = False self.__rootFrame.destroy() def __login_action(self): self.__accepted = True self.__usr = self.__usrEntry.get() self.__pwd = self.__pwdEntry.get() self.__rootFrame.destroy() def __enter_action(self, event): self.__login_action() def __create_content(self): self.__rootFrame = TKTk() self.__rootFrame.withdraw() self.__top = TKToplevel(self.__rootFrame) self.__top.title("Login") self.__top.protocol("WM_DELETE_WINDOW", self.__rootFrame.destroy) self.__top.bind('<Return>', self.__enter_action) self.__top.update_idletasks() width = self.__top.winfo_width() height = self.__top.winfo_height() x = (self.__top.winfo_screenwidth() // 2) - (width // 2) y = (self.__top.winfo_screenheight() // 2) - (height // 2) self.__top.geometry("+%d+%d" % (x, y)) row = 0 expLabel = TKLabel(self.__top, text='Login to host:') expLabel.grid(row=row, column=0, columnspan=4, padx=5, pady=2) row = row + 1 urlLabel = TKLabel(self.__top, text=self.__host) urlLabel.grid(row=row, column=0, columnspan=4, padx=5, pady=2) row = row + 1 usrLabel = TKLabel(self.__top, text='User') usrLabel.grid(row=row, column=0, columnspan=2, padx=20, pady=5) self.__usrEntry = TKEntry(self.__top, width=20) self.__usrEntry.grid(row=row, column=2, columnspan=2, padx=5, pady=5) row = row + 1 pwdLabel = TKLabel(self.__top, text='Password') pwdLabel.grid(row=row, column=0, columnspan=2, padx=20, pady=5) self.__pwdEntry = TKEntry(self.__top, width=20, show="*") self.__pwdEntry.grid(row=row, column=2, columnspan=2, padx=5, pady=5) row = row + 1 cancelButton = TKButton(self.__top, text='Cancel', command=self.__cancel_action) cancelButton.grid(row=row, column=1, padx=5, pady=5) loginButton = TKButton(self.__top, text='Login', command=self.__login_action) loginButton.grid(row=row, column=2, padx=5, pady=5) def show_login(self): if self.__initialized: self.__usrEntry.focus_set() self.__rootFrame.mainloop() else: print("tkinter python module is not available.\n\ Please, install tkinter module or use command line login utility.") def is_accepted(self): return self.__accepted def get_user(self): return self.__usr def get_password(self): return self.__pwd
def on_var_changed(self, *_): Toplevel.title(self, self.var.get())
class CFGEditor(object): """ A dialog window for creating and editing context free grammars. ``CFGEditor`` imposes the following restrictions: - All nonterminals must be strings consisting of word characters. - All terminals must be strings consisting of word characters and space characters. """ # Regular expressions used by _analyze_line. Precompile them, so # we can process the text faster. ARROW = SymbolWidget.SYMBOLS['rightarrow'] _LHS_RE = re.compile(r"(^\s*\w+\s*)(->|(" + ARROW + "))") _ARROW_RE = re.compile("\s*(->|(" + ARROW + "))\s*") _PRODUCTION_RE = re.compile( r"(^\s*\w+\s*)" + "(->|(" # LHS + ARROW + "))\s*" + r"((\w+|'[\w ]*'|\"[\w ]*\"|\|)\s*)*$" # arrow ) # RHS _TOKEN_RE = re.compile("\\w+|->|'[\\w ]+'|\"[\\w ]+\"|(" + ARROW + ")") _BOLD = ('helvetica', -12, 'bold') def __init__(self, parent, cfg=None, set_cfg_callback=None): self._parent = parent if cfg is not None: self._cfg = cfg else: self._cfg = CFG(Nonterminal('S'), []) self._set_cfg_callback = set_cfg_callback self._highlight_matching_nonterminals = 1 # Create the top-level window. self._top = Toplevel(parent) self._init_bindings() self._init_startframe() self._startframe.pack(side='top', fill='x', expand=0) self._init_prodframe() self._prodframe.pack(side='top', fill='both', expand=1) self._init_buttons() self._buttonframe.pack(side='bottom', fill='x', expand=0) self._textwidget.focus() def _init_startframe(self): frame = self._startframe = Frame(self._top) self._start = Entry(frame) self._start.pack(side='right') Label(frame, text='Start Symbol:').pack(side='right') Label(frame, text='Productions:').pack(side='left') self._start.insert(0, self._cfg.start().symbol()) def _init_buttons(self): frame = self._buttonframe = Frame(self._top) Button(frame, text='Ok', command=self._ok, underline=0, takefocus=0).pack( side='left' ) Button(frame, text='Apply', command=self._apply, underline=0, takefocus=0).pack( side='left' ) Button(frame, text='Reset', command=self._reset, underline=0, takefocus=0).pack( side='left' ) Button( frame, text='Cancel', command=self._cancel, underline=0, takefocus=0 ).pack(side='left') Button(frame, text='Help', command=self._help, underline=0, takefocus=0).pack( side='right' ) def _init_bindings(self): self._top.title('CFG Editor') self._top.bind('<Control-q>', self._cancel) self._top.bind('<Alt-q>', self._cancel) self._top.bind('<Control-d>', self._cancel) # self._top.bind('<Control-x>', self._cancel) self._top.bind('<Alt-x>', self._cancel) self._top.bind('<Escape>', self._cancel) # self._top.bind('<Control-c>', self._cancel) self._top.bind('<Alt-c>', self._cancel) self._top.bind('<Control-o>', self._ok) self._top.bind('<Alt-o>', self._ok) self._top.bind('<Control-a>', self._apply) self._top.bind('<Alt-a>', self._apply) self._top.bind('<Control-r>', self._reset) self._top.bind('<Alt-r>', self._reset) self._top.bind('<Control-h>', self._help) self._top.bind('<Alt-h>', self._help) self._top.bind('<F1>', self._help) def _init_prodframe(self): self._prodframe = Frame(self._top) # Create the basic Text widget & scrollbar. self._textwidget = Text( self._prodframe, background='#e0e0e0', exportselection=1 ) self._textscroll = Scrollbar(self._prodframe, takefocus=0, orient='vertical') self._textwidget.config(yscrollcommand=self._textscroll.set) self._textscroll.config(command=self._textwidget.yview) self._textscroll.pack(side='right', fill='y') self._textwidget.pack(expand=1, fill='both', side='left') # Initialize the colorization tags. Each nonterminal gets its # own tag, so they aren't listed here. self._textwidget.tag_config('terminal', foreground='#006000') self._textwidget.tag_config('arrow', font='symbol') self._textwidget.tag_config('error', background='red') # Keep track of what line they're on. We use that to remember # to re-analyze a line whenever they leave it. self._linenum = 0 # Expand "->" to an arrow. self._top.bind('>', self._replace_arrows) # Re-colorize lines when appropriate. self._top.bind('<<Paste>>', self._analyze) self._top.bind('<KeyPress>', self._check_analyze) self._top.bind('<ButtonPress>', self._check_analyze) # Tab cycles focus. (why doesn't this work??) def cycle(e, textwidget=self._textwidget): textwidget.tk_focusNext().focus() self._textwidget.bind('<Tab>', cycle) prod_tuples = [(p.lhs(), [p.rhs()]) for p in self._cfg.productions()] for i in range(len(prod_tuples) - 1, 0, -1): if prod_tuples[i][0] == prod_tuples[i - 1][0]: if () in prod_tuples[i][1]: continue if () in prod_tuples[i - 1][1]: continue print(prod_tuples[i - 1][1]) print(prod_tuples[i][1]) prod_tuples[i - 1][1].extend(prod_tuples[i][1]) del prod_tuples[i] for lhs, rhss in prod_tuples: print(lhs, rhss) s = '%s ->' % lhs for rhs in rhss: for elt in rhs: if isinstance(elt, Nonterminal): s += ' %s' % elt else: s += ' %r' % elt s += ' |' s = s[:-2] + '\n' self._textwidget.insert('end', s) self._analyze() # # Add the producitons to the text widget, and colorize them. # prod_by_lhs = {} # for prod in self._cfg.productions(): # if len(prod.rhs()) > 0: # prod_by_lhs.setdefault(prod.lhs(),[]).append(prod) # for (lhs, prods) in prod_by_lhs.items(): # self._textwidget.insert('end', '%s ->' % lhs) # self._textwidget.insert('end', self._rhs(prods[0])) # for prod in prods[1:]: # print '\t|'+self._rhs(prod), # self._textwidget.insert('end', '\t|'+self._rhs(prod)) # print # self._textwidget.insert('end', '\n') # for prod in self._cfg.productions(): # if len(prod.rhs()) == 0: # self._textwidget.insert('end', '%s' % prod) # self._analyze() # def _rhs(self, prod): # s = '' # for elt in prod.rhs(): # if isinstance(elt, Nonterminal): s += ' %s' % elt.symbol() # else: s += ' %r' % elt # return s def _clear_tags(self, linenum): """ Remove all tags (except ``arrow`` and ``sel``) from the given line of the text widget used for editing the productions. """ start = '%d.0' % linenum end = '%d.end' % linenum for tag in self._textwidget.tag_names(): if tag not in ('arrow', 'sel'): self._textwidget.tag_remove(tag, start, end) def _check_analyze(self, *e): """ Check if we've moved to a new line. If we have, then remove all colorization from the line we moved to, and re-colorize the line that we moved from. """ linenum = int(self._textwidget.index('insert').split('.')[0]) if linenum != self._linenum: self._clear_tags(linenum) self._analyze_line(self._linenum) self._linenum = linenum def _replace_arrows(self, *e): """ Replace any ``'->'`` text strings with arrows (char \\256, in symbol font). This searches the whole buffer, but is fast enough to be done anytime they press '>'. """ arrow = '1.0' while True: arrow = self._textwidget.search('->', arrow, 'end+1char') if arrow == '': break self._textwidget.delete(arrow, arrow + '+2char') self._textwidget.insert(arrow, self.ARROW, 'arrow') self._textwidget.insert(arrow, '\t') arrow = '1.0' while True: arrow = self._textwidget.search(self.ARROW, arrow + '+1char', 'end+1char') if arrow == '': break self._textwidget.tag_add('arrow', arrow, arrow + '+1char') def _analyze_token(self, match, linenum): """ Given a line number and a regexp match for a token on that line, colorize the token. Note that the regexp match gives us the token's text, start index (on the line), and end index (on the line). """ # What type of token is it? if match.group()[0] in "'\"": tag = 'terminal' elif match.group() in ('->', self.ARROW): tag = 'arrow' else: # If it's a nonterminal, then set up new bindings, so we # can highlight all instances of that nonterminal when we # put the mouse over it. tag = 'nonterminal_' + match.group() if tag not in self._textwidget.tag_names(): self._init_nonterminal_tag(tag) start = '%d.%d' % (linenum, match.start()) end = '%d.%d' % (linenum, match.end()) self._textwidget.tag_add(tag, start, end) def _init_nonterminal_tag(self, tag, foreground='blue'): self._textwidget.tag_config(tag, foreground=foreground, font=CFGEditor._BOLD) if not self._highlight_matching_nonterminals: return def enter(e, textwidget=self._textwidget, tag=tag): textwidget.tag_config(tag, background='#80ff80') def leave(e, textwidget=self._textwidget, tag=tag): textwidget.tag_config(tag, background='') self._textwidget.tag_bind(tag, '<Enter>', enter) self._textwidget.tag_bind(tag, '<Leave>', leave) def _analyze_line(self, linenum): """ Colorize a given line. """ # Get rid of any tags that were previously on the line. self._clear_tags(linenum) # Get the line line's text string. line = self._textwidget.get(repr(linenum) + '.0', repr(linenum) + '.end') # If it's a valid production, then colorize each token. if CFGEditor._PRODUCTION_RE.match(line): # It's valid; Use _TOKEN_RE to tokenize the production, # and call analyze_token on each token. def analyze_token(match, self=self, linenum=linenum): self._analyze_token(match, linenum) return '' CFGEditor._TOKEN_RE.sub(analyze_token, line) elif line.strip() != '': # It's invalid; show the user where the error is. self._mark_error(linenum, line) def _mark_error(self, linenum, line): """ Mark the location of an error in a line. """ arrowmatch = CFGEditor._ARROW_RE.search(line) if not arrowmatch: # If there's no arrow at all, highlight the whole line. start = '%d.0' % linenum end = '%d.end' % linenum elif not CFGEditor._LHS_RE.match(line): # Otherwise, if the LHS is bad, highlight it. start = '%d.0' % linenum end = '%d.%d' % (linenum, arrowmatch.start()) else: # Otherwise, highlight the RHS. start = '%d.%d' % (linenum, arrowmatch.end()) end = '%d.end' % linenum # If we're highlighting 0 chars, highlight the whole line. if self._textwidget.compare(start, '==', end): start = '%d.0' % linenum end = '%d.end' % linenum self._textwidget.tag_add('error', start, end) def _analyze(self, *e): """ Replace ``->`` with arrows, and colorize the entire buffer. """ self._replace_arrows() numlines = int(self._textwidget.index('end').split('.')[0]) for linenum in range(1, numlines + 1): # line numbers start at 1. self._analyze_line(linenum) def _parse_productions(self): """ Parse the current contents of the textwidget buffer, to create a list of productions. """ productions = [] # Get the text, normalize it, and split it into lines. text = self._textwidget.get('1.0', 'end') text = re.sub(self.ARROW, '->', text) text = re.sub('\t', ' ', text) lines = text.split('\n') # Convert each line to a CFG production for line in lines: line = line.strip() if line == '': continue productions += _read_cfg_production(line) # if line.strip() == '': continue # if not CFGEditor._PRODUCTION_RE.match(line): # raise ValueError('Bad production string %r' % line) # # (lhs_str, rhs_str) = line.split('->') # lhs = Nonterminal(lhs_str.strip()) # rhs = [] # def parse_token(match, rhs=rhs): # token = match.group() # if token[0] in "'\"": rhs.append(token[1:-1]) # else: rhs.append(Nonterminal(token)) # return '' # CFGEditor._TOKEN_RE.sub(parse_token, rhs_str) # # productions.append(Production(lhs, *rhs)) return productions def _destroy(self, *e): if self._top is None: return self._top.destroy() self._top = None def _ok(self, *e): self._apply() self._destroy() def _apply(self, *e): productions = self._parse_productions() start = Nonterminal(self._start.get()) cfg = CFG(start, productions) if self._set_cfg_callback is not None: self._set_cfg_callback(cfg) def _reset(self, *e): self._textwidget.delete('1.0', 'end') for production in self._cfg.productions(): self._textwidget.insert('end', '%s\n' % production) self._analyze() if self._set_cfg_callback is not None: self._set_cfg_callback(self._cfg) def _cancel(self, *e): try: self._reset() except: pass self._destroy() def _help(self, *e): # The default font's not very legible; try using 'fixed' instead. try: ShowText( self._parent, 'Help: Chart Parser Demo', (_CFGEditor_HELP).strip(), width=75, font='fixed', ) except: ShowText( self._parent, 'Help: Chart Parser Demo', (_CFGEditor_HELP).strip(), width=75, )
def __init__(self, *args, **kwargs): super(TkWindowNode, self).__init__(*args, **kwargs) self.__tk_object = Toplevel() self.__tk_object.title(eval_format('{self.window_name} id={id(self)}')) self.__tk_object.protocol('WM_DELETE_WINDOW', self.on_close)
class Task(Frame): def __init__(self, master=None, work=WORK_TM, rest=REST_TM, server=HOST, port=PORT, mode='fascist'): """create the task widget and get things started""" self.lid_state = "open" self.lid_time = time.time() self.interrupt_count = 0 self.then = 0.0 self.old_work = 0.0 self.state = "working" self.cancel_rest = 0 self.log = logging.getLogger(__name__) Frame.__init__(*(self, master)) self.mode = StringVar() self.mode.set(mode) # "fascist" or "friendly" # create main interactor window self.workmeter = Meter(self, background="grey50") self.workmeter.pack() self.work_frame = Frame(self) self.work_frame.pack() self.work_label = Label(self.work_frame, text="Work time:") self.work_label.pack(side=LEFT) self.work_scl = Scale(self.work_frame, orient=HORIZONTAL, from_=1, to=max(45, work), command=self.reset_duration) self.work_scl.set(work) self.work_scl.pack(side=LEFT) self.rest_frame = Frame(self) self.rest_frame.pack() self.rest_label = Label(self.rest_frame, text="Rest time:") self.rest_label.pack(side=LEFT) self.rest_scl = Scale(self.rest_frame, orient=HORIZONTAL, from_=1, to=max(15, rest), command=self.reset_duration) self.rest_scl.set(rest) self.rest_scl.pack(side=LEFT) self.radio_frame = Frame(self) self.radio_frame.pack() self.dictator = Radiobutton(self.radio_frame, text="Fascist", variable=self.mode, value="fascist") self.friend = Radiobutton(self.radio_frame, text="Friendly", variable=self.mode, value="friendly") self.dictator.pack(side=LEFT) self.friend.pack(side=LEFT) self.button_frame = Frame(self) self.button_frame.pack() self.restb = Button(self.button_frame, text="Rest", command=self.rest) self.restb.pack(side=LEFT) self.stopb = Button(self.button_frame, text="Quit", command=self.quit) self.stopb.pack(side=LEFT) self.helpb = Button(self.button_frame, text="Help", command=self.help) self.helpb.pack(side=LEFT) # create the cover window self.cover = Toplevel(background="black") self.cover.withdraw() # user can't resize it self.cover.resizable(0, 0) # when displayed, it should cover all displays (w, h) = (self.winfo_vrootwidth(), self.winfo_vrootheight()) if self.log.getEffectiveLevel() <= logging.DEBUG: # but we reduce it while debugging w, h = (w / 5, h / 5) self.cover.geometry("%dx%d+0+0" % (w, h)) # and it's undecorated self.cover.overrideredirect(1) # cover contains a frame with rest message and meter f = Frame(self.cover, background="black") self.restnote = Label(f, background="black", foreground="white") self.restmeter = Meter(f, background="grey50", height=10, width=200) self.restnote.pack(pady=2) self.restmeter.pack(fill="x", expand=1, pady=2) self.cancel_button = Button(f, text="Cancel Rest", command=self.cancel) f.pack() # initialize interrupt information self.linux_interrupts = 0 # used by the default activity checker self.mouse = None self.setup_server(server, port) # self.last_int is the last time the server was alerted to activity # self.now is the server's notion of the current time # idle time is therefore max(0, self.now-self.last_int) (self.last_int, _w_time, _r_time, self.now) = self.server.get() self.idle = max(0, self.now - self.last_int) self.bgcolor = self["background"] # start the ball rolling self.after(CHK_INT, self.tick) self.work() def setup_server(self, server, port): if server is None: self.server = collector.Collector() self.log.debug("using private Collector()") return self.server = xmlrpc_client.ServerProxy("http://%s:%d" % (server, port)) try: self.server.get() self.log.debug("found existing server") except socket.error: if server in ["", "localhost", "127.0.0.1"]: cmd = "watch-server.py" args = ["-p", "%d" % port] pid = os.spawnvp(os.P_NOWAIT, cmd, args) # wait briefly for server to start time.sleep(0.2) self.server = xmlrpc_client.ServerProxy("http://%s:%d" % (server, port), allow_none=True) # try connecting for _i in range(10): try: self.server.get() atexit.register(os.kill, pid, signal.SIGHUP) self.log.debug("spawned server") return except socket.error: time.sleep(0.1) # nothing else worked, so fall back to an embedded collector self.server = collector.Collector() self.log.debug("using private Collector()") def reset_duration(self, _dummy=None): """reset work/rest interval lengths to current scale values""" wtime = self.work_scl.get() self.workmeter.set_range(self.workmeter.min_val, self.workmeter.min_val + wtime * 60) self.restmeter.set_range( self.restmeter.min_val, self.restmeter.min_val + self.rest_scl.get() * 60) # only time the user can fiddle the work/rest meters is during # the work phase, so the only scale change that matters for extending # or contracting the end of the interval is the work scale try: delta = wtime - self.old_work except AttributeError: delta = 0 self.log.debug(__("then: {} delta: {}m", hhmm(self.then), delta)) self.then = self.then + delta * 60 self.old_work = wtime self.server.put(self.work_scl.get(), self.rest_scl.get()) def work(self): """start the work period""" self.reset_warning() self.restmeter.reset() self.state = "working" self.then = self.now + self.work_scl.get() * 60 self.log.debug(__("work: then: {}", hhmm(self.then))) self.workmeter.set_range(self.now, self.then) self.workmeter.reset() self.cover.withdraw() def warn_work_end(self): """alert user that work period is almost up""" self.set_background("yellow") def reset_warning(self): """back to plain old grey bg""" self.set_background(self.bgcolor) def set_background(self, color): for w in (self, self.work_scl, self.rest_scl, self.dictator, self.friend, self.button_frame, self.stopb, self.restb, self.helpb, self.work_frame, self.rest_frame, self.radio_frame, self.work_label, self.rest_label): w["background"] = color def rest(self): """overlay the screen with a window, preventing typing""" self.cancel_rest = 0 self.workmeter.reset() self.state = "resting" # the user may not have been typing or mousing right up to the # work/rest threshold - give credit for whatever rest time has # already been accumulated resttime = self.rest_scl.get() * 60 - (self.now - self.last_int) if resttime < 0: self.work() return mins, secs = divmod(resttime, 60) self.then = self.now + resttime self.cover.deiconify() self.cover.tkraise() resttext = ("Rest for %dm%02ds please..." % (mins, secs)) self.restnote.configure(text=resttext) self.restmeter.set_range(self.now, self.then) self.restmeter.reset() if self.mode.get() == "friendly": self.cancel_button.pack(pady=2) else: self.cancel_button.pack_forget() self.log.debug( __("rest: state: {} now: {} then: {} active? {}", self.state, hhmm(self.now), hhmm(self.then), self.check_activity())) def help(self): Dialog(self.master, title="Help", content=usageText()) ### ---- define activity checkers here ---- ### # keyed by sys.platform or "default" to return a method that checks # for mouse/keyboard activity _dispatch = {} def check_activity(self): """check mouse/keyboard activity info where possible, call platform-dependent routine to get mouse and keyboard info, otherwise, just return mouse info in all cases, the value returned should evaluate to False if no activity was detected. """ active = False if self.lid_state == "open": dflt = self._dispatch["default"] checker = self._dispatch.get(sys.platform, dflt) active = checker(self) if active: self.server.tick() return active def check_mouse(self): """default checker, just compares current w/ saved mouse pos""" mouse = self.winfo_pointerxy() try: return mouse != self.mouse finally: self.mouse = mouse _dispatch["default"] = check_mouse def get_linux_interrupts(self): count = 0 # Can't seem to find mouse interrupts, so for now, just watch # keyboard and mix add get_mouseinfo() output as a substitute for # mouse interrupts. last_count = self.interrupt_count for line in open("/proc/interrupts"): fields = line.split() if fields[0] == "1:": count = sum(int(fields[n]) for n in range(1, 8)) self.interrupt_count = count break return self.check_mouse() or self.interrupt_count > last_count _dispatch["linux"] = get_linux_interrupts def check_lid_state(self): if os.path.exists(LID_STATE): for line in open(LID_STATE): fields = line.strip().split() if fields[0] == "state:": return self.maybe_change_lid_state(fields[1]) else: self.lid_state = "open" return 0 def maybe_change_lid_state(self, state): """Take necessary action when lid state changes. Return True if lid state changed. """ idle = 0 if state != self.lid_state: self.log.info(__("lid state changed: {}", state)) lid_time = time.time() if state == "open": idle = lid_time - self.lid_time self.log.info(__("idle for {}s", idle)) self.lid_state = state self.lid_time = lid_time return idle def tick(self): """perform periodic checks for activity or state switch""" try: self._tick() finally: self.after(CHK_INT, self.tick) def _tick(self): (self.last_int, work_time, rest_time, self.now) = self.server.get() # check for mouse or keyboard activity idle_time = self.check_lid_state() if idle_time > rest_time * 60: self.log.info( __("The lid is up! Back to work: {}", hhmm(idle_time))) self.work() return active = self.check_activity() idle = max(0, self.now - self.last_int) # check to see if the work/rest scales got adjusted by another # watch instance if (self.work_scl.get() != work_time or self.rest_scl.get() != rest_time): self.work_scl.set(work_time) self.rest_scl.set(rest_time) self.log.debug( __("work: state: {} now: {} then: {} active? {}", self.state, hhmm(self.now), hhmm(self.then), active)) if self.state == "resting": # user explicitly cancelled the rest or the idle period # exceeded the desired rest time if self.cancel_rest or idle > rest_time * 60: self.work() return # make sure the rest window is as far up the window stack as # possible self.cover.tkraise() if idle <= self.idle: # user moved something - extend rest by a second self.then += 1 self.restmeter.set_range(self.restmeter.min_val, self.then) self.restmeter.set(self.now) self.idle = idle # update message to reflect rest time remaining timeleft = int(round(self.then - self.now)) minleft, secleft = divmod(timeleft, 60) resttext = ("Rest for %dm%02ds please..." % (minleft, secleft)) self.restnote.configure(text=resttext) else: # if it's been at least the length of the rest interval # since last interrupt, reset the work interval if idle >= rest_time * 60: self.work() return self.idle = idle if self.now > self.then: # work period expired self.rest() return if self.now + 60 > self.then: # work period nearly expired - warn user self.warn_work_end() else: self.reset_warning() self.restmeter.set(self.now) self.workmeter.set(self.now) def cancel(self): self.cancel_rest = 1
def __init__(self, master=None, work=WORK_TM, rest=REST_TM, server=HOST, port=PORT, mode='fascist'): """create the task widget and get things started""" self.lid_state = "open" self.lid_time = time.time() self.interrupt_count = 0 self.then = 0.0 self.old_work = 0.0 self.state = "working" self.cancel_rest = 0 self.log = logging.getLogger(__name__) Frame.__init__(*(self, master)) self.mode = StringVar() self.mode.set(mode) # "fascist" or "friendly" # create main interactor window self.workmeter = Meter(self, background="grey50") self.workmeter.pack() self.work_frame = Frame(self) self.work_frame.pack() self.work_label = Label(self.work_frame, text="Work time:") self.work_label.pack(side=LEFT) self.work_scl = Scale(self.work_frame, orient=HORIZONTAL, from_=1, to=max(45, work), command=self.reset_duration) self.work_scl.set(work) self.work_scl.pack(side=LEFT) self.rest_frame = Frame(self) self.rest_frame.pack() self.rest_label = Label(self.rest_frame, text="Rest time:") self.rest_label.pack(side=LEFT) self.rest_scl = Scale(self.rest_frame, orient=HORIZONTAL, from_=1, to=max(15, rest), command=self.reset_duration) self.rest_scl.set(rest) self.rest_scl.pack(side=LEFT) self.radio_frame = Frame(self) self.radio_frame.pack() self.dictator = Radiobutton(self.radio_frame, text="Fascist", variable=self.mode, value="fascist") self.friend = Radiobutton(self.radio_frame, text="Friendly", variable=self.mode, value="friendly") self.dictator.pack(side=LEFT) self.friend.pack(side=LEFT) self.button_frame = Frame(self) self.button_frame.pack() self.restb = Button(self.button_frame, text="Rest", command=self.rest) self.restb.pack(side=LEFT) self.stopb = Button(self.button_frame, text="Quit", command=self.quit) self.stopb.pack(side=LEFT) self.helpb = Button(self.button_frame, text="Help", command=self.help) self.helpb.pack(side=LEFT) # create the cover window self.cover = Toplevel(background="black") self.cover.withdraw() # user can't resize it self.cover.resizable(0, 0) # when displayed, it should cover all displays (w, h) = (self.winfo_vrootwidth(), self.winfo_vrootheight()) if self.log.getEffectiveLevel() <= logging.DEBUG: # but we reduce it while debugging w, h = (w / 5, h / 5) self.cover.geometry("%dx%d+0+0" % (w, h)) # and it's undecorated self.cover.overrideredirect(1) # cover contains a frame with rest message and meter f = Frame(self.cover, background="black") self.restnote = Label(f, background="black", foreground="white") self.restmeter = Meter(f, background="grey50", height=10, width=200) self.restnote.pack(pady=2) self.restmeter.pack(fill="x", expand=1, pady=2) self.cancel_button = Button(f, text="Cancel Rest", command=self.cancel) f.pack() # initialize interrupt information self.linux_interrupts = 0 # used by the default activity checker self.mouse = None self.setup_server(server, port) # self.last_int is the last time the server was alerted to activity # self.now is the server's notion of the current time # idle time is therefore max(0, self.now-self.last_int) (self.last_int, _w_time, _r_time, self.now) = self.server.get() self.idle = max(0, self.now - self.last_int) self.bgcolor = self["background"] # start the ball rolling self.after(CHK_INT, self.tick) self.work()