diff options
author | Guido van Rossum <guido@python.org> | 1999-01-28 22:02:47 (GMT) |
---|---|---|
committer | Guido van Rossum <guido@python.org> | 1999-01-28 22:02:47 (GMT) |
commit | 07ec8967078a966365a44db301a9063f70c7f474 (patch) | |
tree | f97b034c2f3489958e47ae03a3cb41c5312a745c | |
parent | 85ef9dce9f4b1982c1f26daa0fe9f4af08e124a6 (diff) | |
download | cpython-07ec8967078a966365a44db301a9063f70c7f474.zip cpython-07ec8967078a966365a44db301a9063f70c7f474.tar.gz cpython-07ec8967078a966365a44db301a9063f70c7f474.tar.bz2 |
Move menu/key binding code from Bindings.py to EditorWindow.py,
with changed APIs -- it makes much more sense there.
Also add a new feature: if the first character of a menu label is
a '!', it gets a checkbox. Checkboxes are bound to Boolean Tcl variables
that can be accessed through the new getvar/setvar/getrawvar API;
the variable is named after the event to which the menu is bound.
-rw-r--r-- | Tools/idle/Bindings.py | 62 | ||||
-rw-r--r-- | Tools/idle/EditorWindow.py | 115 | ||||
-rw-r--r-- | Tools/idle/PyShell.py | 29 |
3 files changed, 127 insertions, 79 deletions
diff --git a/Tools/idle/Bindings.py b/Tools/idle/Bindings.py index e365032..e0a2570 100644 --- a/Tools/idle/Bindings.py +++ b/Tools/idle/Bindings.py @@ -7,7 +7,6 @@ import sys import string -import re from keydefs import * menudefs = [ @@ -42,9 +41,9 @@ menudefs = [ ]), ('debug', [ ('_Go to file/line', '<<goto-file-line>>'), - ('_Open stack viewer', '<<open-stack-viewer>>'), - ('_Debugger toggle', '<<toggle-debugger>>'), - ('_JIT Stack viewer toggle', '<<toggle-jit-stack-viewer>>' ), + ('_Stack viewer', '<<open-stack-viewer>>'), + ('!_Debugger', '<<toggle-debugger>>'), + ('!_Auto-open stack viewer', '<<toggle-jit-stack-viewer>>' ), ]), ('help', [ ('_Help...', '<<help>>'), @@ -53,62 +52,7 @@ menudefs = [ ]), ] -def prepstr(s): - # Helper to extract the underscore from a string, - # e.g. prepstr("Co_py") returns (2, "Copy"). - i = string.find(s, '_') - if i >= 0: - s = s[:i] + s[i+1:] - return i, s - -keynames = { - 'bracketleft': '[', - 'bracketright': ']', - 'slash': '/', -} - -def get_accelerator(keydefs, event): - keylist = keydefs.get(event) - if not keylist: - return "" - s = keylist[0] - s = re.sub(r"-[a-z]\b", lambda m: string.upper(m.group()), s) - s = re.sub(r"\b\w+\b", lambda m: keynames.get(m.group(), m.group()), s) - s = re.sub("Key-", "", s) - s = re.sub("Control-", "Ctrl-", s) - s = re.sub("-", "+", s) - s = re.sub("><", " ", s) - s = re.sub("<", "", s) - s = re.sub(">", "", s) - return s - if sys.platform == 'win32': default_keydefs = windows_keydefs else: default_keydefs = unix_keydefs - -def apply_bindings(text, keydefs=default_keydefs): - text.keydefs = keydefs - for event, keylist in keydefs.items(): - if keylist: - apply(text.event_add, (event,) + tuple(keylist)) - -def fill_menus(text, menudict, defs=menudefs, keydefs=default_keydefs): - # Fill the menus for the given text widget. The menudict argument is - # a dictionary containing the menus, keyed by their lowercased name. - # Menus that are absent or None are ignored. - for mname, itemlist in defs: - menu = menudict.get(mname) - if not menu: - continue - for item in itemlist: - if not item: - menu.add_separator() - else: - label, event = item - underline, label = prepstr(label) - accelerator = get_accelerator(keydefs, event) - def command(text=text, event=event): - text.event_generate(event) - menu.add_command(label=label, underline=underline, - command=command, accelerator=accelerator) diff --git a/Tools/idle/EditorWindow.py b/Tools/idle/EditorWindow.py index 96a56de..17f23ca 100644 --- a/Tools/idle/EditorWindow.py +++ b/Tools/idle/EditorWindow.py @@ -1,6 +1,7 @@ import sys import os import string +import re import imp from Tkinter import * import tkSimpleDialog @@ -93,7 +94,7 @@ class EditorWindow: background="white", wrap="none") self.createmenubar() - self.Bindings.apply_bindings(text) + self.apply_bindings() self.top.protocol("WM_DELETE_WINDOW", self.close) self.top.bind("<<close-window>>", self.close_event) @@ -172,15 +173,19 @@ class EditorWindow: def createmenubar(self): mbar = self.menubar - self.menudict = mdict = {} + self.menudict = menudict = {} for name, label in self.menu_specs: - underline, label = self.Bindings.prepstr(label) - mdict[name] = menu = Menu(mbar, name=name) + underline, label = prepstr(label) + menudict[name] = menu = Menu(mbar, name=name) mbar.add_cascade(label=label, menu=menu, underline=underline) - self.Bindings.fill_menus(self.text, mdict) + self.fill_menus() def postwindowsmenu(self): # Only called when Windows menu exists + # XXX Actually, this Just-In-Time updating interferes + # XXX badly with the tear-off feature. It would be better + # XXX to update all Windows menus whenever the list of windows + # XXX changes. menu = self.menudict['windows'] end = menu.index("end") if end is None: @@ -477,7 +482,7 @@ class EditorWindow: if hasattr(ins, kdname): keydefs.update(getattr(ins, kdname)) if keydefs: - self.Bindings.apply_bindings(self.text, keydefs) + self.apply_bindings(keydefs) for vevent in keydefs.keys(): methodname = string.replace(vevent, "-", "_") while methodname[:1] == '<': @@ -488,10 +493,104 @@ class EditorWindow: if hasattr(ins, methodname): self.text.bind(vevent, getattr(ins, methodname)) if hasattr(ins, "menudefs"): - self.Bindings.fill_menus(self.text, self. menudict, - ins.menudefs, keydefs) + self.fill_menus(ins.menudefs, keydefs) return ins + def apply_bindings(self, keydefs=None): + if keydefs is None: + keydefs = self.Bindings.default_keydefs + text = self.text + text.keydefs = keydefs + for event, keylist in keydefs.items(): + if keylist: + apply(text.event_add, (event,) + tuple(keylist)) + + def fill_menus(self, defs=None, keydefs=None): + # Fill the menus. + # Menus that are absent or None in self.menudict are ignored. + if defs is None: + defs = self.Bindings.menudefs + if keydefs is None: + keydefs = self.Bindings.default_keydefs + menudict = self.menudict + text = self.text + for mname, itemlist in defs: + menu = menudict.get(mname) + if not menu: + continue + for item in itemlist: + if not item: + menu.add_separator() + else: + label, event = item + checkbutton = (label[:1] == '!') + if checkbutton: + label = label[1:] + underline, label = prepstr(label) + accelerator = get_accelerator(keydefs, event) + def command(text=text, event=event): + text.event_generate(event) + if checkbutton: + var = self.getrawvar(event, BooleanVar) + menu.add_checkbutton(label=label, underline=underline, + command=command, accelerator=accelerator, + variable=var) + else: + menu.add_command(label=label, underline=underline, + command=command, accelerator=accelerator) + + def getvar(self, name): + var = self.getrawvar(name) + if var: + return var.get() + + def setvar(self, name, value, vartype=None): + var = self.getrawvar(name, vartype) + if var: + var.set(value) + + def getrawvar(self, name, vartype=None): + key = ".VARS." + vars = self.menudict.get(key) + if not vars and vartype: + self.menudict[key] = vars = {} + if vars is not None: + var = vars.get(name) + if not var and vartype: + vars[name] = var = vartype(self.text) + return var + + +def prepstr(s): + # Helper to extract the underscore from a string, + # e.g. prepstr("Co_py") returns (2, "Copy"). + i = string.find(s, '_') + if i >= 0: + s = s[:i] + s[i+1:] + return i, s + + +keynames = { + 'bracketleft': '[', + 'bracketright': ']', + 'slash': '/', +} + +def get_accelerator(keydefs, event): + keylist = keydefs.get(event) + if not keylist: + return "" + s = keylist[0] + s = re.sub(r"-[a-z]\b", lambda m: string.upper(m.group()), s) + s = re.sub(r"\b\w+\b", lambda m: keynames.get(m.group(), m.group()), s) + s = re.sub("Key-", "", s) + s = re.sub("Control-", "Ctrl-", s) + s = re.sub("-", "+", s) + s = re.sub("><", " ", s) + s = re.sub("<", "", s) + s = re.sub(">", "", s) + return s + def fixwordbreaks(root): # Make sure that Tk's double-click and next/previous word diff --git a/Tools/idle/PyShell.py b/Tools/idle/PyShell.py index f484fb8..115d96f 100644 --- a/Tools/idle/PyShell.py +++ b/Tools/idle/PyShell.py @@ -217,11 +217,11 @@ class ModifiedInterpreter(InteractiveInterpreter): raise else: self.showtraceback() - if self.tkconsole.jit_stack_view: + if self.tkconsole.getvar("<<toggle-jit-stack-viewer>>"): self.tkconsole.open_stack_viewer() except: self.showtraceback() - if self.tkconsole.jit_stack_view: + if self.tkconsole.getvar("<<toggle-jit-stack-viewer>>"): self.tkconsole.open_stack_viewer() finally: @@ -289,17 +289,20 @@ class PyShell(OutputWindow): tkMessageBox.showerror("Don't debug now", "You can only toggle the debugger when idle", master=self.text) + self.set_debugger_indicator() return "break" - db = self.interp.getdebugger() - if db: - self.close_debugger() else: - self.open_debugger() - - jit_stack_view = 0 - + db = self.interp.getdebugger() + if db: + self.close_debugger() + else: + self.open_debugger() + + def set_debugger_indicator(self): + db = self.interp.getdebugger() + self.setvar("<<toggle-debugger>>", not not db) def toggle_jit_stack_viewer( self, event=None): - self.jit_stack_view = not self.jit_stack_view + pass # All we need is the variable def close_debugger(self): db = self.interp.getdebugger() @@ -310,12 +313,14 @@ class PyShell(OutputWindow): self.console.write("[DEBUG OFF]\n") sys.ps1 = ">>> " self.showprompt() + self.set_debugger_indicator() def open_debugger(self): import Debugger self.interp.setdebugger(Debugger.Debugger(self)) sys.ps1 = "[DEBUG ON]\n>>> " self.showprompt() + self.set_debugger_indicator() def beginexecuting(self): # Helper for ModifiedInterpreter @@ -335,8 +340,8 @@ class PyShell(OutputWindow): if self.executing: # XXX Need to ask a question here if not tkMessageBox.askokcancel( - "Cancel?", - "The program is still running; do you want to cancel it?", + "Kill?", + "The program is still running; do you want to kill it?", default="ok", master=self.text): return "cancel" |