def decreaseFontSize(self): curr_editor = self._get_current_editor() # FIXME curr_font = Font(curr_editor, curr_editor.cget("font")) curr_size = curr_font.cget('size') if curr_size > 1: new_size = curr_size-1 curr_font.configure(size=new_size)
def increaseFontSize(self): curr_editor = self._get_current_editor() # FIXME curr_font = Font(curr_editor, curr_editor.cget("font")) curr_size = curr_font.cget('size') new_size = curr_size+1 curr_font.configure(size=new_size) new_font = curr_font curr_editor.configure(font=new_font)
class DrtGlueDemo: def __init__(self, examples): # Set up the main window. self._top = Tk() self._top.title("DRT Glue Demo") # Set up key bindings. self._init_bindings() # Initialize the fonts.self._error = None self._init_fonts(self._top) self._examples = examples self._readingCache = [None for example in examples] # The user can hide the grammar. self._show_grammar = IntVar(self._top) self._show_grammar.set(1) # Set the data to None self._curExample = -1 self._readings = [] self._drs = None self._drsWidget = None self._error = None self._init_glue() # Create the basic frames. self._init_menubar(self._top) self._init_buttons(self._top) self._init_exampleListbox(self._top) self._init_readingListbox(self._top) self._init_canvas(self._top) # Resize callback self._canvas.bind("<Configure>", self._configure) ######################################### ## Initialization Helpers ######################################### def _init_glue(self): tagger = RegexpTagger([ ("^(David|Mary|John)$", "NNP"), ( "^(walks|sees|eats|chases|believes|gives|sleeps|chases|persuades|tries|seems|leaves)$", "VB", ), ("^(go|order|vanish|find|approach)$", "VB"), ("^(a)$", "ex_quant"), ("^(every)$", "univ_quant"), ("^(sandwich|man|dog|pizza|unicorn|cat|senator)$", "NN"), ("^(big|gray|former)$", "JJ"), ("^(him|himself)$", "PRP"), ]) depparser = MaltParser(tagger=tagger) self._glue = DrtGlue(depparser=depparser, remove_duplicates=False) def _init_fonts(self, root): # See: <http://www.astro.washington.edu/owen/ROTKFolklore.html> self._sysfont = Font(font=Button()["font"]) root.option_add("*Font", self._sysfont) # TWhat's our font size (default=same as sysfont) self._size = IntVar(root) self._size.set(self._sysfont.cget("size")) self._boldfont = Font(family="helvetica", weight="bold", size=self._size.get()) self._font = Font(family="helvetica", size=self._size.get()) if self._size.get() < 0: big = self._size.get() - 2 else: big = self._size.get() + 2 self._bigfont = Font(family="helvetica", weight="bold", size=big) def _init_exampleListbox(self, parent): self._exampleFrame = listframe = Frame(parent) self._exampleFrame.pack(fill="both", side="left", padx=2) self._exampleList_label = Label(self._exampleFrame, font=self._boldfont, text="Examples") self._exampleList_label.pack() self._exampleList = Listbox( self._exampleFrame, selectmode="single", relief="groove", background="white", foreground="#909090", font=self._font, selectforeground="#004040", selectbackground="#c0f0c0", ) self._exampleList.pack(side="right", fill="both", expand=1) for example in self._examples: self._exampleList.insert("end", (" %s" % example)) self._exampleList.config(height=min(len(self._examples), 25), width=40) # Add a scrollbar if there are more than 25 examples. if len(self._examples) > 25: listscroll = Scrollbar(self._exampleFrame, orient="vertical") self._exampleList.config(yscrollcommand=listscroll.set) listscroll.config(command=self._exampleList.yview) listscroll.pack(side="left", fill="y") # If they select a example, apply it. self._exampleList.bind("<<ListboxSelect>>", self._exampleList_select) def _init_readingListbox(self, parent): self._readingFrame = listframe = Frame(parent) self._readingFrame.pack(fill="both", side="left", padx=2) self._readingList_label = Label(self._readingFrame, font=self._boldfont, text="Readings") self._readingList_label.pack() self._readingList = Listbox( self._readingFrame, selectmode="single", relief="groove", background="white", foreground="#909090", font=self._font, selectforeground="#004040", selectbackground="#c0f0c0", ) self._readingList.pack(side="right", fill="both", expand=1) # Add a scrollbar if there are more than 25 examples. listscroll = Scrollbar(self._readingFrame, orient="vertical") self._readingList.config(yscrollcommand=listscroll.set) listscroll.config(command=self._readingList.yview) listscroll.pack(side="right", fill="y") self._populate_readingListbox() def _populate_readingListbox(self): # Populate the listbox with integers self._readingList.delete(0, "end") for i in range(len(self._readings)): self._readingList.insert("end", (" %s" % (i + 1))) self._readingList.config(height=min(len(self._readings), 25), width=5) # If they select a example, apply it. self._readingList.bind("<<ListboxSelect>>", self._readingList_select) def _init_bindings(self): # Key bindings are a good thing. self._top.bind("<Control-q>", self.destroy) self._top.bind("<Control-x>", self.destroy) self._top.bind("<Escape>", self.destroy) self._top.bind("n", self.next) self._top.bind("<space>", self.next) self._top.bind("p", self.prev) self._top.bind("<BackSpace>", self.prev) def _init_buttons(self, parent): # Set up the frames. self._buttonframe = buttonframe = Frame(parent) buttonframe.pack(fill="none", side="bottom", padx=3, pady=2) Button( buttonframe, text="Prev", background="#90c0d0", foreground="black", command=self.prev, ).pack(side="left") Button( buttonframe, text="Next", background="#90c0d0", foreground="black", command=self.next, ).pack(side="left") def _configure(self, event): self._autostep = 0 (x1, y1, x2, y2) = self._cframe.scrollregion() y2 = event.height - 6 self._canvas["scrollregion"] = "%d %d %d %d" % (x1, y1, x2, y2) self._redraw() def _init_canvas(self, parent): self._cframe = CanvasFrame( parent, background="white", # width=525, height=250, closeenough=10, border=2, relief="sunken", ) self._cframe.pack(expand=1, fill="both", side="top", pady=2) canvas = self._canvas = self._cframe.canvas() # Initially, there's no tree or text self._tree = None self._textwidgets = [] self._textline = None def _init_menubar(self, parent): menubar = Menu(parent) filemenu = Menu(menubar, tearoff=0) filemenu.add_command(label="Exit", underline=1, command=self.destroy, accelerator="q") menubar.add_cascade(label="File", underline=0, menu=filemenu) actionmenu = Menu(menubar, tearoff=0) actionmenu.add_command(label="Next", underline=0, command=self.next, accelerator="n, Space") actionmenu.add_command(label="Previous", underline=0, command=self.prev, accelerator="p, Backspace") menubar.add_cascade(label="Action", underline=0, menu=actionmenu) optionmenu = Menu(menubar, tearoff=0) optionmenu.add_checkbutton( label="Remove Duplicates", underline=0, variable=self._glue.remove_duplicates, command=self._toggle_remove_duplicates, accelerator="r", ) menubar.add_cascade(label="Options", underline=0, menu=optionmenu) viewmenu = Menu(menubar, tearoff=0) viewmenu.add_radiobutton( label="Tiny", variable=self._size, underline=0, value=10, command=self.resize, ) viewmenu.add_radiobutton( label="Small", variable=self._size, underline=0, value=12, command=self.resize, ) viewmenu.add_radiobutton( label="Medium", variable=self._size, underline=0, value=14, command=self.resize, ) viewmenu.add_radiobutton( label="Large", variable=self._size, underline=0, value=18, command=self.resize, ) viewmenu.add_radiobutton( label="Huge", variable=self._size, underline=0, value=24, command=self.resize, ) menubar.add_cascade(label="View", underline=0, menu=viewmenu) helpmenu = Menu(menubar, tearoff=0) helpmenu.add_command(label="About", underline=0, command=self.about) menubar.add_cascade(label="Help", underline=0, menu=helpmenu) parent.config(menu=menubar) ######################################### ## Main draw procedure ######################################### def _redraw(self): canvas = self._canvas # Delete the old DRS, widgets, etc. if self._drsWidget is not None: self._drsWidget.clear() if self._drs: self._drsWidget = DrsWidget(self._canvas, self._drs) self._drsWidget.draw() if self._error: self._drsWidget = DrsWidget(self._canvas, self._error) self._drsWidget.draw() ######################################### ## Button Callbacks ######################################### def destroy(self, *e): self._autostep = 0 if self._top is None: return self._top.destroy() self._top = None def prev(self, *e): selection = self._readingList.curselection() readingListSize = self._readingList.size() # there are readings if readingListSize > 0: # if one reading is currently selected if len(selection) == 1: index = int(selection[0]) # if it's on (or before) the first item if index <= 0: self._select_previous_example() else: self._readingList_store_selection(index - 1) else: # select its first reading self._readingList_store_selection(readingListSize - 1) else: self._select_previous_example() def _select_previous_example(self): # if the current example is not the first example if self._curExample > 0: self._exampleList_store_selection(self._curExample - 1) else: # go to the last example self._exampleList_store_selection(len(self._examples) - 1) def next(self, *e): selection = self._readingList.curselection() readingListSize = self._readingList.size() # if there are readings if readingListSize > 0: # if one reading is currently selected if len(selection) == 1: index = int(selection[0]) # if it's on (or past) the last item if index >= (readingListSize - 1): self._select_next_example() else: self._readingList_store_selection(index + 1) else: # select its first reading self._readingList_store_selection(0) else: self._select_next_example() def _select_next_example(self): # if the current example is not the last example if self._curExample < len(self._examples) - 1: self._exampleList_store_selection(self._curExample + 1) else: # go to the first example self._exampleList_store_selection(0) def about(self, *e): ABOUT = ( "NLTK Discourse Representation Theory (DRT) Glue Semantics Demo\n" + "Written by Daniel H. Garrette") TITLE = "About: NLTK DRT Glue Demo" try: from tkinter.messagebox import Message Message(message=ABOUT, title=TITLE).show() except: ShowText(self._top, TITLE, ABOUT) def postscript(self, *e): self._autostep = 0 self._cframe.print_to_file() def mainloop(self, *args, **kwargs): """ Enter the Tkinter mainloop. This function must be called if this demo is created from a non-interactive program (e.g. from a secript); otherwise, the demo will close as soon as the script completes. """ if in_idle(): return self._top.mainloop(*args, **kwargs) def resize(self, size=None): if size is not None: self._size.set(size) size = self._size.get() self._font.configure(size=-(abs(size))) self._boldfont.configure(size=-(abs(size))) self._sysfont.configure(size=-(abs(size))) self._bigfont.configure(size=-(abs(size + 2))) self._redraw() def _toggle_remove_duplicates(self): self._glue.remove_duplicates = not self._glue.remove_duplicates self._exampleList.selection_clear(0, "end") self._readings = [] self._populate_readingListbox() self._readingCache = [None for ex in self._examples] self._curExample = -1 self._error = None self._drs = None self._redraw() def _exampleList_select(self, event): selection = self._exampleList.curselection() if len(selection) != 1: return self._exampleList_store_selection(int(selection[0])) def _exampleList_store_selection(self, index): self._curExample = index example = self._examples[index] self._exampleList.selection_clear(0, "end") if example: cache = self._readingCache[index] if cache: if isinstance(cache, list): self._readings = cache self._error = None else: self._readings = [] self._error = cache else: try: self._readings = self._glue.parse_to_meaning(example) self._error = None self._readingCache[index] = self._readings except Exception as e: self._readings = [] self._error = DrtVariableExpression( Variable("Error: " + str(e))) self._readingCache[index] = self._error # add a star to the end of the example self._exampleList.delete(index) self._exampleList.insert(index, (" %s *" % example)) self._exampleList.config(height=min( len(self._examples), 25), width=40) self._populate_readingListbox() self._exampleList.selection_set(index) self._drs = None self._redraw() def _readingList_select(self, event): selection = self._readingList.curselection() if len(selection) != 1: return self._readingList_store_selection(int(selection[0])) def _readingList_store_selection(self, index): reading = self._readings[index] self._readingList.selection_clear(0, "end") if reading: self._readingList.selection_set(index) self._drs = reading.simplify().normalize().resolve_anaphora() self._redraw()
class TextEditor: def __init__(self, master): self.master = master self.font_dict = {'family': 'Arial', 'size': 10, 'weight': 'normal', 'slant': 'roman', 'underline': 0, 'overstrike': 0} self.font = Font(family = self.font_dict.get('family'), size = self.font_dict.get('size'), weight = self.font_dict.get('weight'), slant = self.font_dict.get('slant'), underline = self.font_dict.get('underline'), overstrike = self.font_dict.get('overstrike')) self.master.title('SB Text Editor') self.file_name = None self.bg = 'white' self.fg = 'black' # text box self.text = tk.Text(relief = tk.FLAT, undo = True, font = self.font) self.text.pack(fill=tk.BOTH, expand=True) self.text.focus() # main menu self.main_menu = tk.Menu() self.master.config(menu = self.main_menu) # file menu self.file_menu = tk.Menu(self.main_menu, tearoff = False) self.main_menu.add_cascade(label = 'File', menu = self.file_menu) self.file_menu.add_command(label = 'New', accelerator = 'Ctrl+N', command = self.new_file) self.file_menu.add_command(label = 'Open', accelerator = 'Ctrl+O', command = self.open_file) self.file_menu.add_separator() self.file_menu.add_command(label = 'Save', accelerator = 'Ctrl+S', command = self.save_file) self.file_menu.add_command(label = 'Save as', accelerator = 'Ctrl+Shift+S', command = self.save_as) self.file_menu.add_separator() self.file_menu.add_command(label = 'Quit', command = self.close_programe) # edit menu self.edit_menu = tk.Menu(self.main_menu, tearoff = False) self.main_menu.add_cascade(label = 'Edit', menu = self.edit_menu) self.edit_menu.add_command(label = 'Undo', accelerator = 'Ctrl+Z', command = self.text.edit_undo) self.edit_menu.add_command(label = 'Redo', accelerator = 'Ctrl+Y',command = self.text.edit_redo) self.edit_menu.add_separator() self.edit_menu.add_command(label = 'Copy', accelerator = 'Ctrl+C', command = self.copy) self.edit_menu.add_command(label = 'Cut', accelerator = 'Ctrl+X', command = self.cut) self.edit_menu.add_command(label = 'Paste', accelerator = 'Ctrl+V', command = self.paste) self.edit_menu.add_command(label = 'Delete', command = self.delete) # view menu self.view_menu = tk.Menu(self.main_menu, tearoff = False) self.main_menu.add_cascade(label = 'View', menu = self.view_menu) self.view_menu.add_command(label = 'Zoon in', command = self.zoom_in) self.view_menu.add_command(label = 'Zoom out', command = self.zoom_out) self.view_menu.add_separator() self.view_menu.add_command(label = 'Change font', command = self.change_font) # color menu self.color_menu = tk.Menu(self.view_menu, tearoff = False) self.view_menu.add_cascade(label = 'Change Colors', menu = self.color_menu) self.color_menu.add_command(label = 'Change background color', command = self.change_bg) self.color_menu.add_command(label = 'Change foreground color', command = self.change_fg) # shortcuts self.master.bind('<Control-n>', self.new_file) self.master.bind('<Control-N>', self.new_file) self.master.bind('<Control-o>', self.open_file) self.master.bind('<Control-O>', self.open_file) self.master.bind('<Control-s>', self.save_file) self.master.bind('<Control-S>', self.save_file) self.master.bind('<Shift-Control-s>', self.save_as) self.master.bind('<Shift-Control-S>', self.save_as) self.master.bind('<Control-plus>', self.zoom_in) self.master.bind('<Control-minus>', self.zoom_out) self.master.protocol('WM_DELETE_WINDOW', self.close_programe) def load(self): self.home = os.getenv('HOME') self.home = self.home if not os.path.isdir(os.path.join(self.home, '.SB_Text_Editor')): os.mkdir(os.path.join(self.home, '.SB_Text_Editor')) if os.path.isfile(os.path.join(self.home, '.SB_Text_Editor/settings.txt')): with open(os.path.join(self.home, '.SB_Text_Editor/settings.txt'), 'r') as settings: tmp = settings.readline().strip().split(';') if len(tmp) == 6: self.font_dict['family'] = tmp[0] self.font_dict['size'] = int(tmp[1]) self.font_dict['weight'] = tmp[2] self.font_dict['slant'] = tmp[3] self.font_dict['underline'] = int(tmp[4]) self.font_dict['overstrike'] = int(tmp[5]) self.font = Font(family = self.font_dict['family'], size = self.font_dict['size'], weight = self.font_dict['weight'], slant = self.font_dict['slant'], underline = self.font_dict['underline'], overstrike = self.font_dict['overstrike']) self.text.config(font = self.font) tmp = settings.readline().strip().split(';') if len(tmp) == 2: self.bg = tmp[0] self.fg = tmp[1] self.text.config(bg = self.bg, fg = self.fg) def new_file(self, event = None): if len(self.text.get(1.0, tk.END)) > 1: inp = messagebox.askyesnocancel('SB Text Editor', 'Do you want to save this file?') if inp == True: self.save_file() elif inp == None: return None self.file_name = None self.text.delete(1.0, tk.END) self.text.edit_reset() def open_file(self, event = None): file = filedialog.askopenfile(filetypes = [('Text file', '.txt'), ('All file', '*.*')]) if file != None: self.text.delete(1.0, tk.END) for line in file: self.text.insert(tk.INSERT, line) self.file_name = file.name def save_file(self, event = None): if self.file_name == None: self.save_as() else: with open(self.file_name, 'w') as file: file.write(self.text.get(1.0, tk.END)) def save_as(self, event = None): file = filedialog.asksaveasfile(mode='w', filetypes = [('Text file', '.txt'), ('All file', '*.*')], defaultextension = '.txt') if file != None: file.write(self.text.get(1.0, tk.END)) self.file_name = file.name file.close() def close_programe(self, event = None): if len(self.text.get(1.0, tk.END)) > 1: inp = messagebox.askyesnocancel('SB Text Editor', 'Do you want to save this file?') if inp == True: self.save_file() elif inp == None: return None self.master.quit() def copy(self, event = None): self.text.event_generate('<<Copy>>') def cut(self, event = None): self.text.event_generate('<<Cut>>') def paste(self, event = None): self.text.event_generate('<<Paste>>') def delete(self, event = None): try: i1 = self.text.index('sel.first') i2 = self.text.index('sel.last') self.text.delete(i1, i2) except: return None def zoom_in(self, event = None): size = self.font.cget('size') size += 1 if size > 30: size = 30 self.font_dict['size'] = size self.font.config(size = size) self.text.config(font = self.font) def zoom_out(self, event = None): size = self.font.cget('size') size -= 1 if size < 3: size = 3 self.font_dict['size'] = size self.font.config(size = size) self.text.config(font = self.font) def change_font(self, event = None): font_dict = tkfontchooser.askfont(**self.font_dict) if font_dict != '': self.font_dict = font_dict font_dict = list(font_dict.values()) font = Font(family = font_dict[0], size = font_dict[1], weight = font_dict[2], slant = font_dict[3], underline = font_dict[4], overstrike = font_dict[5]) self.font = font self.text.config(font = self.font) with open(os.path.join(self.home, '.SB_Text_Editor/settings.txt'), 'w') as settings: tmp = ';'.join(map(lambda item: str(item), list(self.font_dict.values()))) tmp += '\n'+self.bg+';'+self.fg settings.write(tmp) def change_bg(self, event = None): color = colorchooser.askcolor() if color[1] != None: self.bg = color[1] self.text.config(bg = self.bg) with open(os.path.join(self.home, '.SB_Text_Editor/settings.txt'), 'w') as settings: tmp = ';'.join(map(lambda item: str(item), list(self.font_dict.values()))) tmp += '\n' + self.bg + ';' + self.fg settings.write(tmp) def change_fg(self, event = None): color = colorchooser.askcolor() if color[1] != None: self.fg = color[1] self.text.config(fg = self.fg) with open(os.path.join(self.home, '.SB_Text_Editor/settings.txt'), 'w') as settings: tmp = ';'.join(map(lambda item: str(item), list(self.font_dict.values()))) tmp += '\n'+self.bg+';'+self.fg settings.write(tmp)
class DrtGlueDemo(object): def __init__(self, examples): # Set up the main window. self._top = Tk() self._top.title("DRT Glue Demo") # Set up key bindings. self._init_bindings() # Initialize the fonts.self._error = None self._init_fonts(self._top) self._examples = examples self._readingCache = [None for example in examples] # The user can hide the grammar. self._show_grammar = IntVar(self._top) self._show_grammar.set(1) # Set the data to None self._curExample = -1 self._readings = [] self._drs = None self._drsWidget = None self._error = None self._init_glue() # Create the basic frames. self._init_menubar(self._top) self._init_buttons(self._top) self._init_exampleListbox(self._top) self._init_readingListbox(self._top) self._init_canvas(self._top) # Resize callback self._canvas.bind("<Configure>", self._configure) ######################################### ## Initialization Helpers ######################################### def _init_glue(self): tagger = RegexpTagger( [ ("^(David|Mary|John)$", "NNP"), ("^(walks|sees|eats|chases|believes|gives|sleeps|chases|persuades|tries|seems|leaves)$", "VB"), ("^(go|order|vanish|find|approach)$", "VB"), ("^(a)$", "ex_quant"), ("^(every)$", "univ_quant"), ("^(sandwich|man|dog|pizza|unicorn|cat|senator)$", "NN"), ("^(big|gray|former)$", "JJ"), ("^(him|himself)$", "PRP"), ] ) depparser = MaltParser(tagger=tagger) self._glue = DrtGlue(depparser=depparser, remove_duplicates=False) def _init_fonts(self, root): # See: <http://www.astro.washington.edu/owen/ROTKFolklore.html> self._sysfont = Font(font=Button()["font"]) root.option_add("*Font", self._sysfont) # TWhat's our font size (default=same as sysfont) self._size = IntVar(root) self._size.set(self._sysfont.cget("size")) self._boldfont = Font(family="helvetica", weight="bold", size=self._size.get()) self._font = Font(family="helvetica", size=self._size.get()) if self._size.get() < 0: big = self._size.get() - 2 else: big = self._size.get() + 2 self._bigfont = Font(family="helvetica", weight="bold", size=big) def _init_exampleListbox(self, parent): self._exampleFrame = listframe = Frame(parent) self._exampleFrame.pack(fill="both", side="left", padx=2) self._exampleList_label = Label(self._exampleFrame, font=self._boldfont, text="Examples") self._exampleList_label.pack() self._exampleList = Listbox( self._exampleFrame, selectmode="single", relief="groove", background="white", foreground="#909090", font=self._font, selectforeground="#004040", selectbackground="#c0f0c0", ) self._exampleList.pack(side="right", fill="both", expand=1) for example in self._examples: self._exampleList.insert("end", (" %s" % example)) self._exampleList.config(height=min(len(self._examples), 25), width=40) # Add a scrollbar if there are more than 25 examples. if len(self._examples) > 25: listscroll = Scrollbar(self._exampleFrame, orient="vertical") self._exampleList.config(yscrollcommand=listscroll.set) listscroll.config(command=self._exampleList.yview) listscroll.pack(side="left", fill="y") # If they select a example, apply it. self._exampleList.bind("<<ListboxSelect>>", self._exampleList_select) def _init_readingListbox(self, parent): self._readingFrame = listframe = Frame(parent) self._readingFrame.pack(fill="both", side="left", padx=2) self._readingList_label = Label(self._readingFrame, font=self._boldfont, text="Readings") self._readingList_label.pack() self._readingList = Listbox( self._readingFrame, selectmode="single", relief="groove", background="white", foreground="#909090", font=self._font, selectforeground="#004040", selectbackground="#c0f0c0", ) self._readingList.pack(side="right", fill="both", expand=1) # Add a scrollbar if there are more than 25 examples. listscroll = Scrollbar(self._readingFrame, orient="vertical") self._readingList.config(yscrollcommand=listscroll.set) listscroll.config(command=self._readingList.yview) listscroll.pack(side="right", fill="y") self._populate_readingListbox() def _populate_readingListbox(self): # Populate the listbox with integers self._readingList.delete(0, "end") for i in range(len(self._readings)): self._readingList.insert("end", (" %s" % (i + 1))) self._readingList.config(height=min(len(self._readings), 25), width=5) # If they select a example, apply it. self._readingList.bind("<<ListboxSelect>>", self._readingList_select) def _init_bindings(self): # Key bindings are a good thing. self._top.bind("<Control-q>", self.destroy) self._top.bind("<Control-x>", self.destroy) self._top.bind("<Escape>", self.destroy) self._top.bind("n", self.next) self._top.bind("<space>", self.next) self._top.bind("p", self.prev) self._top.bind("<BackSpace>", self.prev) def _init_buttons(self, parent): # Set up the frames. self._buttonframe = buttonframe = Frame(parent) buttonframe.pack(fill="none", side="bottom", padx=3, pady=2) Button(buttonframe, text="Prev", background="#90c0d0", foreground="black", command=self.prev).pack(side="left") Button(buttonframe, text="Next", background="#90c0d0", foreground="black", command=self.next).pack(side="left") def _configure(self, event): self._autostep = 0 (x1, y1, x2, y2) = self._cframe.scrollregion() y2 = event.height - 6 self._canvas["scrollregion"] = "%d %d %d %d" % (x1, y1, x2, y2) self._redraw() def _init_canvas(self, parent): self._cframe = CanvasFrame( parent, background="white", # width=525, height=250, closeenough=10, border=2, relief="sunken", ) self._cframe.pack(expand=1, fill="both", side="top", pady=2) canvas = self._canvas = self._cframe.canvas() # Initially, there's no tree or text self._tree = None self._textwidgets = [] self._textline = None def _init_menubar(self, parent): menubar = Menu(parent) filemenu = Menu(menubar, tearoff=0) filemenu.add_command(label="Exit", underline=1, command=self.destroy, accelerator="q") menubar.add_cascade(label="File", underline=0, menu=filemenu) actionmenu = Menu(menubar, tearoff=0) actionmenu.add_command(label="Next", underline=0, command=self.next, accelerator="n, Space") actionmenu.add_command(label="Previous", underline=0, command=self.prev, accelerator="p, Backspace") menubar.add_cascade(label="Action", underline=0, menu=actionmenu) optionmenu = Menu(menubar, tearoff=0) optionmenu.add_checkbutton( label="Remove Duplicates", underline=0, variable=self._glue.remove_duplicates, command=self._toggle_remove_duplicates, accelerator="r", ) menubar.add_cascade(label="Options", underline=0, menu=optionmenu) viewmenu = Menu(menubar, tearoff=0) viewmenu.add_radiobutton(label="Tiny", variable=self._size, underline=0, value=10, command=self.resize) viewmenu.add_radiobutton(label="Small", variable=self._size, underline=0, value=12, command=self.resize) viewmenu.add_radiobutton(label="Medium", variable=self._size, underline=0, value=14, command=self.resize) viewmenu.add_radiobutton(label="Large", variable=self._size, underline=0, value=18, command=self.resize) viewmenu.add_radiobutton(label="Huge", variable=self._size, underline=0, value=24, command=self.resize) menubar.add_cascade(label="View", underline=0, menu=viewmenu) helpmenu = Menu(menubar, tearoff=0) helpmenu.add_command(label="About", underline=0, command=self.about) menubar.add_cascade(label="Help", underline=0, menu=helpmenu) parent.config(menu=menubar) ######################################### ## Main draw procedure ######################################### def _redraw(self): canvas = self._canvas # Delete the old DRS, widgets, etc. if self._drsWidget is not None: self._drsWidget.clear() if self._drs: self._drsWidget = DrsWidget(self._canvas, self._drs) self._drsWidget.draw() if self._error: self._drsWidget = DrsWidget(self._canvas, self._error) self._drsWidget.draw() ######################################### ## Button Callbacks ######################################### def destroy(self, *e): self._autostep = 0 if self._top is None: return self._top.destroy() self._top = None def prev(self, *e): selection = self._readingList.curselection() readingListSize = self._readingList.size() # there are readings if readingListSize > 0: # if one reading is currently selected if len(selection) == 1: index = int(selection[0]) # if it's on (or before) the first item if index <= 0: self._select_previous_example() else: self._readingList_store_selection(index - 1) else: # select its first reading self._readingList_store_selection(readingListSize - 1) else: self._select_previous_example() def _select_previous_example(self): # if the current example is not the first example if self._curExample > 0: self._exampleList_store_selection(self._curExample - 1) else: # go to the last example self._exampleList_store_selection(len(self._examples) - 1) def next(self, *e): selection = self._readingList.curselection() readingListSize = self._readingList.size() # if there are readings if readingListSize > 0: # if one reading is currently selected if len(selection) == 1: index = int(selection[0]) # if it's on (or past) the last item if index >= (readingListSize - 1): self._select_next_example() else: self._readingList_store_selection(index + 1) else: # select its first reading self._readingList_store_selection(0) else: self._select_next_example() def _select_next_example(self): # if the current example is not the last example if self._curExample < len(self._examples) - 1: self._exampleList_store_selection(self._curExample + 1) else: # go to the first example self._exampleList_store_selection(0) def about(self, *e): ABOUT = "NLTK Discourse Representation Theory (DRT) Glue Semantics Demo\n" + "Written by Daniel H. Garrette" TITLE = "About: NLTK DRT Glue Demo" try: from tkMessageBox import Message Message(message=ABOUT, title=TITLE).show() except: ShowText(self._top, TITLE, ABOUT) def postscript(self, *e): self._autostep = 0 self._cframe.print_to_file() def mainloop(self, *args, **kwargs): """ Enter the Tkinter mainloop. This function must be called if this demo is created from a non-interactive program (e.g. from a secript); otherwise, the demo will close as soon as the script completes. """ if in_idle(): return self._top.mainloop(*args, **kwargs) def resize(self, size=None): if size is not None: self._size.set(size) size = self._size.get() self._font.configure(size=-(abs(size))) self._boldfont.configure(size=-(abs(size))) self._sysfont.configure(size=-(abs(size))) self._bigfont.configure(size=-(abs(size + 2))) self._redraw() def _toggle_remove_duplicates(self): self._glue.remove_duplicates = not self._glue.remove_duplicates self._exampleList.selection_clear(0, "end") self._readings = [] self._populate_readingListbox() self._readingCache = [None for ex in self._examples] self._curExample = -1 self._error = None self._drs = None self._redraw() def _exampleList_select(self, event): selection = self._exampleList.curselection() if len(selection) != 1: return self._exampleList_store_selection(int(selection[0])) def _exampleList_store_selection(self, index): self._curExample = index example = self._examples[index] self._exampleList.selection_clear(0, "end") if example: cache = self._readingCache[index] if cache: if isinstance(cache, list): self._readings = cache self._error = None else: self._readings = [] self._error = cache else: try: self._readings = self._glue.parse_to_meaning(example) self._error = None self._readingCache[index] = self._readings except Exception as e: self._readings = [] self._error = DrtVariableExpression(Variable("Error: " + str(e))) self._readingCache[index] = self._error # add a star to the end of the example self._exampleList.delete(index) self._exampleList.insert(index, (" %s *" % example)) self._exampleList.config(height=min(len(self._examples), 25), width=40) self._populate_readingListbox() self._exampleList.selection_set(index) self._drs = None self._redraw() def _readingList_select(self, event): selection = self._readingList.curselection() if len(selection) != 1: return self._readingList_store_selection(int(selection[0])) def _readingList_store_selection(self, index): reading = self._readings[index] self._readingList.selection_clear(0, "end") if reading: self._readingList.selection_set(index) self._drs = reading.simplify().normalize().resolve_anaphora() self._redraw()
class ShiftReduceApp(object): """ A graphical tool for exploring the shift-reduce parser. The tool displays the parser's stack and the remaining text, and allows the customuser to control the parser's operation. In particular, the customuser can shift tokens onto the stack, and can perform reductions on the top elements of the stack. A "step" button simply steps through the parsing process, performing the operations that ``nltk.parse.ShiftReduceParser`` would use. """ def __init__(self, grammar, sent, trace=0): self._sent = sent self._parser = SteppingShiftReduceParser(grammar, trace) # Set up the main window. self._top = Tk() self._top.title("Shift Reduce Parser Application") # Animations. animating_lock is a lock to prevent the demo # from performing new operations while it's animating. self._animating_lock = 0 self._animate = IntVar(self._top) self._animate.set(10) # = medium # The customuser can hide the grammar. self._show_grammar = IntVar(self._top) self._show_grammar.set(1) # Initialize fonts. self._init_fonts(self._top) # Set up key bindings. self._init_bindings() # Create the basic frames. self._init_menubar(self._top) self._init_buttons(self._top) self._init_feedback(self._top) self._init_grammar(self._top) self._init_canvas(self._top) # A popup menu for reducing. self._reduce_menu = Menu(self._canvas, tearoff=0) # Reset the demo, and set the feedback frame to empty. self.reset() self._lastoper1["text"] = "" ######################################### ## Initialization Helpers ######################################### def _init_fonts(self, root): # See: <http://www.astro.washington.edu/owen/ROTKFolklore.html> self._sysfont = Font(font=Button()["font"]) root.option_add("*Font", self._sysfont) # TWhat's our font size (default=same as sysfont) self._size = IntVar(root) self._size.set(self._sysfont.cget("size")) self._boldfont = Font(family="helvetica", weight="bold", size=self._size.get()) self._font = Font(family="helvetica", size=self._size.get()) def _init_grammar(self, parent): # Grammar view. self._prodframe = listframe = Frame(parent) self._prodframe.pack(fill="both", side="left", padx=2) self._prodlist_label = Label( self._prodframe, font=self._boldfont, text="Available Reductions" ) self._prodlist_label.pack() self._prodlist = Listbox( self._prodframe, selectmode="single", relief="groove", background="white", foreground="#909090", font=self._font, selectforeground="#004040", selectbackground="#c0f0c0", ) self._prodlist.pack(side="right", fill="both", expand=1) self._productions = list(self._parser.grammar().productions()) for production in self._productions: self._prodlist.insert("end", (" %s" % production)) self._prodlist.config(height=min(len(self._productions), 25)) # Add a scrollbar if there are more than 25 productions. if 1: # len(self._productions) > 25: listscroll = Scrollbar(self._prodframe, orient="vertical") self._prodlist.config(yscrollcommand=listscroll.set) listscroll.config(command=self._prodlist.yview) listscroll.pack(side="left", fill="y") # If they select a production, apply it. self._prodlist.bind("<<ListboxSelect>>", self._prodlist_select) # When they hover over a production, highlight it. self._hover = -1 self._prodlist.bind("<Motion>", self._highlight_hover) self._prodlist.bind("<Leave>", self._clear_hover) def _init_bindings(self): # Quit self._top.bind("<Control-q>", self.destroy) self._top.bind("<Control-x>", self.destroy) self._top.bind("<Alt-q>", self.destroy) self._top.bind("<Alt-x>", self.destroy) # Ops (step, shift, reduce, undo) self._top.bind("<space>", self.step) self._top.bind("<s>", self.shift) self._top.bind("<Alt-s>", self.shift) self._top.bind("<Control-s>", self.shift) self._top.bind("<r>", self.reduce) self._top.bind("<Alt-r>", self.reduce) self._top.bind("<Control-r>", self.reduce) self._top.bind("<Delete>", self.reset) self._top.bind("<u>", self.undo) self._top.bind("<Alt-u>", self.undo) self._top.bind("<Control-u>", self.undo) self._top.bind("<Control-z>", self.undo) self._top.bind("<BackSpace>", self.undo) # Misc self._top.bind("<Control-p>", self.postscript) self._top.bind("<Control-h>", self.help) self._top.bind("<F1>", self.help) self._top.bind("<Control-g>", self.edit_grammar) self._top.bind("<Control-t>", self.edit_sentence) # Animation speed control self._top.bind("-", lambda e, a=self._animate: a.set(20)) self._top.bind("=", lambda e, a=self._animate: a.set(10)) self._top.bind("+", lambda e, a=self._animate: a.set(4)) def _init_buttons(self, parent): # Set up the frames. self._buttonframe = buttonframe = Frame(parent) buttonframe.pack(fill="none", side="bottom") Button( buttonframe, text="Step", background="#90c0d0", foreground="black", command=self.step, ).pack(side="left") Button( buttonframe, text="Shift", underline=0, background="#90f090", foreground="black", command=self.shift, ).pack(side="left") Button( buttonframe, text="Reduce", underline=0, background="#90f090", foreground="black", command=self.reduce, ).pack(side="left") Button( buttonframe, text="Undo", underline=0, background="#f0a0a0", foreground="black", command=self.undo, ).pack(side="left") def _init_menubar(self, parent): menubar = Menu(parent) filemenu = Menu(menubar, tearoff=0) filemenu.add_command( label="Reset Parser", underline=0, command=self.reset, accelerator="Del" ) filemenu.add_command( label="Print to Postscript", underline=0, command=self.postscript, accelerator="Ctrl-p", ) filemenu.add_command( label="Exit", underline=1, command=self.destroy, accelerator="Ctrl-x" ) menubar.add_cascade(label="File", underline=0, menu=filemenu) editmenu = Menu(menubar, tearoff=0) editmenu.add_command( label="Edit Grammar", underline=5, command=self.edit_grammar, accelerator="Ctrl-g", ) editmenu.add_command( label="Edit Text", underline=5, command=self.edit_sentence, accelerator="Ctrl-t", ) menubar.add_cascade(label="Edit", underline=0, menu=editmenu) rulemenu = Menu(menubar, tearoff=0) rulemenu.add_command( label="Step", underline=1, command=self.step, accelerator="Space" ) rulemenu.add_separator() rulemenu.add_command( label="Shift", underline=0, command=self.shift, accelerator="Ctrl-s" ) rulemenu.add_command( label="Reduce", underline=0, command=self.reduce, accelerator="Ctrl-r" ) rulemenu.add_separator() rulemenu.add_command( label="Undo", underline=0, command=self.undo, accelerator="Ctrl-u" ) menubar.add_cascade(label="Apply", underline=0, menu=rulemenu) viewmenu = Menu(menubar, tearoff=0) viewmenu.add_checkbutton( label="Show Grammar", underline=0, variable=self._show_grammar, command=self._toggle_grammar, ) viewmenu.add_separator() viewmenu.add_radiobutton( label="Tiny", variable=self._size, underline=0, value=10, command=self.resize, ) viewmenu.add_radiobutton( label="Small", variable=self._size, underline=0, value=12, command=self.resize, ) viewmenu.add_radiobutton( label="Medium", variable=self._size, underline=0, value=14, command=self.resize, ) viewmenu.add_radiobutton( label="Large", variable=self._size, underline=0, value=18, command=self.resize, ) viewmenu.add_radiobutton( label="Huge", variable=self._size, underline=0, value=24, command=self.resize, ) menubar.add_cascade(label="View", underline=0, menu=viewmenu) animatemenu = Menu(menubar, tearoff=0) animatemenu.add_radiobutton( label="No Animation", underline=0, variable=self._animate, value=0 ) animatemenu.add_radiobutton( label="Slow Animation", underline=0, variable=self._animate, value=20, accelerator="-", ) animatemenu.add_radiobutton( label="Normal Animation", underline=0, variable=self._animate, value=10, accelerator="=", ) animatemenu.add_radiobutton( label="Fast Animation", underline=0, variable=self._animate, value=4, accelerator="+", ) menubar.add_cascade(label="Animate", underline=1, menu=animatemenu) helpmenu = Menu(menubar, tearoff=0) helpmenu.add_command(label="About", underline=0, command=self.about) helpmenu.add_command( label="Instructions", underline=0, command=self.help, accelerator="F1" ) menubar.add_cascade(label="Help", underline=0, menu=helpmenu) parent.config(menu=menubar) def _init_feedback(self, parent): self._feedbackframe = feedbackframe = Frame(parent) feedbackframe.pack(fill="x", side="bottom", padx=3, pady=3) self._lastoper_label = Label( feedbackframe, text="Last Operation:", font=self._font ) self._lastoper_label.pack(side="left") lastoperframe = Frame(feedbackframe, relief="sunken", border=1) lastoperframe.pack(fill="x", side="right", expand=1, padx=5) self._lastoper1 = Label( lastoperframe, foreground="#007070", background="#f0f0f0", font=self._font ) self._lastoper2 = Label( lastoperframe, anchor="w", width=30, foreground="#004040", background="#f0f0f0", font=self._font, ) self._lastoper1.pack(side="left") self._lastoper2.pack(side="left", fill="x", expand=1) def _init_canvas(self, parent): self._cframe = CanvasFrame( parent, background="white", width=525, closeenough=10, border=2, relief="sunken", ) self._cframe.pack(expand=1, fill="both", side="top", pady=2) canvas = self._canvas = self._cframe.canvas() self._stackwidgets = [] self._rtextwidgets = [] self._titlebar = canvas.create_rectangle( 0, 0, 0, 0, fill="#c0f0f0", outline="black" ) self._exprline = canvas.create_line(0, 0, 0, 0, dash=".") self._stacktop = canvas.create_line(0, 0, 0, 0, fill="#408080") size = self._size.get() + 4 self._stacklabel = TextWidget( canvas, "Stack", color="#004040", font=self._boldfont ) self._rtextlabel = TextWidget( canvas, "Remaining Text", color="#004040", font=self._boldfont ) self._cframe.add_widget(self._stacklabel) self._cframe.add_widget(self._rtextlabel) ######################################### ## Main draw procedure ######################################### def _redraw(self): scrollregion = self._canvas["scrollregion"].split() (cx1, cy1, cx2, cy2) = [int(c) for c in scrollregion] # Delete the old stack & rtext widgets. for stackwidget in self._stackwidgets: self._cframe.destroy_widget(stackwidget) self._stackwidgets = [] for rtextwidget in self._rtextwidgets: self._cframe.destroy_widget(rtextwidget) self._rtextwidgets = [] # Position the titlebar & exprline (x1, y1, x2, y2) = self._stacklabel.bbox() y = y2 - y1 + 10 self._canvas.coords(self._titlebar, -5000, 0, 5000, y - 4) self._canvas.coords(self._exprline, 0, y * 2 - 10, 5000, y * 2 - 10) # Position the titlebar labels.. (x1, y1, x2, y2) = self._stacklabel.bbox() self._stacklabel.move(5 - x1, 3 - y1) (x1, y1, x2, y2) = self._rtextlabel.bbox() self._rtextlabel.move(cx2 - x2 - 5, 3 - y1) # Draw the stack. stackx = 5 for tok in self._parser.stack(): if isinstance(tok, Tree): attribs = { "tree_color": "#4080a0", "tree_width": 2, "node_font": self._boldfont, "node_color": "#006060", "leaf_color": "#006060", "leaf_font": self._font, } widget = tree_to_treesegment(self._canvas, tok, **attribs) widget.label()["color"] = "#000000" else: widget = TextWidget(self._canvas, tok, color="#000000", font=self._font) widget.bind_click(self._popup_reduce) self._stackwidgets.append(widget) self._cframe.add_widget(widget, stackx, y) stackx = widget.bbox()[2] + 10 # Draw the remaining text. rtextwidth = 0 for tok in self._parser.remaining_text(): widget = TextWidget(self._canvas, tok, color="#000000", font=self._font) self._rtextwidgets.append(widget) self._cframe.add_widget(widget, rtextwidth, y) rtextwidth = widget.bbox()[2] + 4 # Allow enough room to shift the next token (for animations) if len(self._rtextwidgets) > 0: stackx += self._rtextwidgets[0].width() # Move the remaining text to the correct location (keep it # right-justified, when possible); and move the remaining text # label, if necessary. stackx = max(stackx, self._stacklabel.width() + 25) rlabelwidth = self._rtextlabel.width() + 10 if stackx >= cx2 - max(rtextwidth, rlabelwidth): cx2 = stackx + max(rtextwidth, rlabelwidth) for rtextwidget in self._rtextwidgets: rtextwidget.move(4 + cx2 - rtextwidth, 0) self._rtextlabel.move(cx2 - self._rtextlabel.bbox()[2] - 5, 0) midx = (stackx + cx2 - max(rtextwidth, rlabelwidth)) / 2 self._canvas.coords(self._stacktop, midx, 0, midx, 5000) (x1, y1, x2, y2) = self._stacklabel.bbox() # Set up binding to allow them to shift a token by dragging it. if len(self._rtextwidgets) > 0: def drag_shift(widget, midx=midx, self=self): if widget.bbox()[0] < midx: self.shift() else: self._redraw() self._rtextwidgets[0].bind_drag(drag_shift) self._rtextwidgets[0].bind_click(self.shift) # Draw the stack top. self._highlight_productions() def _draw_stack_top(self, widget): # hack.. midx = widget.bbox()[2] + 50 self._canvas.coords(self._stacktop, midx, 0, midx, 5000) def _highlight_productions(self): # Highlight the productions that can be reduced. self._prodlist.selection_clear(0, "end") for prod in self._parser.reducible_productions(): index = self._productions.index(prod) self._prodlist.selection_set(index) ######################################### ## Button Callbacks ######################################### def destroy(self, *e): if self._top is None: return self._top.destroy() self._top = None def reset(self, *e): self._parser.initialize(self._sent) self._lastoper1["text"] = "Reset App" self._lastoper2["text"] = "" self._redraw() def step(self, *e): if self.reduce(): return True elif self.shift(): return True else: if list(self._parser.parses()): self._lastoper1["text"] = "Finished:" self._lastoper2["text"] = "Success" else: self._lastoper1["text"] = "Finished:" self._lastoper2["text"] = "Failure" def shift(self, *e): if self._animating_lock: return if self._parser.shift(): tok = self._parser.stack()[-1] self._lastoper1["text"] = "Shift:" self._lastoper2["text"] = "%r" % tok if self._animate.get(): self._animate_shift() else: self._redraw() return True return False def reduce(self, *e): if self._animating_lock: return production = self._parser.reduce() if production: self._lastoper1["text"] = "Reduce:" self._lastoper2["text"] = "%s" % production if self._animate.get(): self._animate_reduce() else: self._redraw() return production def undo(self, *e): if self._animating_lock: return if self._parser.undo(): self._redraw() def postscript(self, *e): self._cframe.print_to_file() def mainloop(self, *args, **kwargs): """ Enter the Tkinter mainloop. This function must be called if this demo is created from a non-interactive program (e.g. from a secript); otherwise, the demo will close as soon as the script completes. """ if in_idle(): return self._top.mainloop(*args, **kwargs) ######################################### ## Menubar callbacks ######################################### def resize(self, size=None): if size is not None: self._size.set(size) size = self._size.get() self._font.configure(size=-(abs(size))) self._boldfont.configure(size=-(abs(size))) self._sysfont.configure(size=-(abs(size))) # self._stacklabel['font'] = ('helvetica', -size-4, 'bold') # self._rtextlabel['font'] = ('helvetica', -size-4, 'bold') # self._lastoper_label['font'] = ('helvetica', -size) # self._lastoper1['font'] = ('helvetica', -size) # self._lastoper2['font'] = ('helvetica', -size) # self._prodlist['font'] = ('helvetica', -size) # self._prodlist_label['font'] = ('helvetica', -size-2, 'bold') self._redraw() def help(self, *e): # The default font's not very legible; try using 'fixed' instead. try: ShowText( self._top, "Help: Shift-Reduce Parser Application", (__doc__ or "").strip(), width=75, font="fixed", ) except: ShowText( self._top, "Help: Shift-Reduce Parser Application", (__doc__ or "").strip(), width=75, ) def about(self, *e): ABOUT = "NLTK Shift-Reduce Parser Application\n" + "Written by Edward Loper" TITLE = "About: Shift-Reduce Parser Application" try: from tkinter.messagebox import Message Message(message=ABOUT, title=TITLE).show() except: ShowText(self._top, TITLE, ABOUT) def edit_grammar(self, *e): CFGEditor(self._top, self._parser.grammar(), self.set_grammar) def set_grammar(self, grammar): self._parser.set_grammar(grammar) self._productions = list(grammar.productions()) self._prodlist.delete(0, "end") for production in self._productions: self._prodlist.insert("end", (" %s" % production)) def edit_sentence(self, *e): sentence = " ".join(self._sent) title = "Edit Text" instr = "Enter a new sentence to parse." EntryDialog(self._top, sentence, instr, self.set_sentence, title) def set_sentence(self, sent): self._sent = sent.split() # [XX] use tagged? self.reset() ######################################### ## Reduce Production Selection ######################################### def _toggle_grammar(self, *e): if self._show_grammar.get(): self._prodframe.pack( fill="both", side="left", padx=2, after=self._feedbackframe ) self._lastoper1["text"] = "Show Grammar" else: self._prodframe.pack_forget() self._lastoper1["text"] = "Hide Grammar" self._lastoper2["text"] = "" def _prodlist_select(self, event): selection = self._prodlist.curselection() if len(selection) != 1: return index = int(selection[0]) production = self._parser.reduce(self._productions[index]) if production: self._lastoper1["text"] = "Reduce:" self._lastoper2["text"] = "%s" % production if self._animate.get(): self._animate_reduce() else: self._redraw() else: # Reset the production selections. self._prodlist.selection_clear(0, "end") for prod in self._parser.reducible_productions(): index = self._productions.index(prod) self._prodlist.selection_set(index) def _popup_reduce(self, widget): # Remove old commands. productions = self._parser.reducible_productions() if len(productions) == 0: return self._reduce_menu.delete(0, "end") for production in productions: self._reduce_menu.add_command(label=str(production), command=self.reduce) self._reduce_menu.post( self._canvas.winfo_pointerx(), self._canvas.winfo_pointery() ) ######################################### ## Animations ######################################### def _animate_shift(self): # What widget are we shifting? widget = self._rtextwidgets[0] # Where are we shifting from & to? right = widget.bbox()[0] if len(self._stackwidgets) == 0: left = 5 else: left = self._stackwidgets[-1].bbox()[2] + 10 # Start animating. dt = self._animate.get() dx = (left - right) * 1.0 / dt self._animate_shift_frame(dt, widget, dx) def _animate_shift_frame(self, frame, widget, dx): if frame > 0: self._animating_lock = 1 widget.move(dx, 0) self._top.after(10, self._animate_shift_frame, frame - 1, widget, dx) else: # but: stacktop?? # Shift the widget to the stack. del self._rtextwidgets[0] self._stackwidgets.append(widget) self._animating_lock = 0 # Display the available productions. self._draw_stack_top(widget) self._highlight_productions() def _animate_reduce(self): # What widgets are we shifting? numwidgets = len(self._parser.stack()[-1]) # number of children widgets = self._stackwidgets[-numwidgets:] # How far are we moving? if isinstance(widgets[0], TreeSegmentWidget): ydist = 15 + widgets[0].label().height() else: ydist = 15 + widgets[0].height() # Start animating. dt = self._animate.get() dy = ydist * 2.0 / dt self._animate_reduce_frame(dt / 2, widgets, dy) def _animate_reduce_frame(self, frame, widgets, dy): if frame > 0: self._animating_lock = 1 for widget in widgets: widget.move(0, dy) self._top.after(10, self._animate_reduce_frame, frame - 1, widgets, dy) else: del self._stackwidgets[-len(widgets) :] for widget in widgets: self._cframe.remove_widget(widget) tok = self._parser.stack()[-1] if not isinstance(tok, Tree): raise ValueError() label = TextWidget( self._canvas, str(tok.label()), color="#006060", font=self._boldfont ) widget = TreeSegmentWidget(self._canvas, label, widgets, width=2) (x1, y1, x2, y2) = self._stacklabel.bbox() y = y2 - y1 + 10 if not self._stackwidgets: x = 5 else: x = self._stackwidgets[-1].bbox()[2] + 10 self._cframe.add_widget(widget, x, y) self._stackwidgets.append(widget) # Display the available productions. self._draw_stack_top(widget) self._highlight_productions() # # Delete the old widgets.. # del self._stackwidgets[-len(widgets):] # for widget in widgets: # self._cframe.destroy_widget(widget) # # # Make a new one. # tok = self._parser.stack()[-1] # if isinstance(tok, Tree): # attribs = {'tree_color': '#4080a0', 'tree_width': 2, # 'node_font': bold, 'node_color': '#006060', # 'leaf_color': '#006060', 'leaf_font':self._font} # widget = tree_to_treesegment(self._canvas, tok.type(), # **attribs) # widget.node()['color'] = '#000000' # else: # widget = TextWidget(self._canvas, tok.type(), # color='#000000', font=self._font) # widget.bind_click(self._popup_reduce) # (x1, y1, x2, y2) = self._stacklabel.bbox() # y = y2-y1+10 # if not self._stackwidgets: x = 5 # else: x = self._stackwidgets[-1].bbox()[2] + 10 # self._cframe.add_widget(widget, x, y) # self._stackwidgets.append(widget) # self._redraw() self._animating_lock = 0 ######################################### ## Hovering. ######################################### def _highlight_hover(self, event): # What production are we hovering over? index = self._prodlist.nearest(event.y) if self._hover == index: return # Clear any previous hover highlighting. self._clear_hover() # If the production corresponds to an available reduction, # highlight the stack. selection = [int(s) for s in self._prodlist.curselection()] if index in selection: rhslen = len(self._productions[index].rhs()) for stackwidget in self._stackwidgets[-rhslen:]: if isinstance(stackwidget, TreeSegmentWidget): stackwidget.label()["color"] = "#00a000" else: stackwidget["color"] = "#00a000" # Remember what production we're hovering over. self._hover = index def _clear_hover(self, *event): # Clear any previous hover highlighting. if self._hover == -1: return self._hover = -1 for stackwidget in self._stackwidgets: if isinstance(stackwidget, TreeSegmentWidget): stackwidget.label()["color"] = "black" else: stackwidget["color"] = "black"
class TextEditor: # initialize all the component. def __init__(self, master): self.master = master self.font_dict = { 'family': 'Arial', 'size': 10, 'weight': 'normal', 'slant': 'roman', 'underline': 0, 'overstrike': 0 } self.font = Font(family=self.font_dict.get('family'), size=self.font_dict.get('size'), weight=self.font_dict.get('weight'), slant=self.font_dict.get('slant'), underline=self.font_dict.get('underline'), overstrike=self.font_dict.get('overstrike')) self.master.title('SB Text Editor') self.file_name = None self.bg = 'white' self.fg = 'black' self.insert = 'red' self.insert_width = 2 # text box self.text = tk.Text(relief=tk.FLAT, undo=True, font=self.font) self.text.config(insertbackground=self.insert) self.text.config(insertwidth=self.insert_width) self.text.pack(fill=tk.BOTH, expand=True) self.text.focus() # main menu self.main_menu = tk.Menu() self.master.config(menu=self.main_menu) # file menu self.file_menu = tk.Menu(self.main_menu, tearoff=False) self.main_menu.add_cascade(label='File', menu=self.file_menu) self.file_menu.add_command(label='New', accelerator='Ctrl+N', command=self.new_file) self.file_menu.add_command(label='Open', accelerator='Ctrl+O', command=self.open_file) self.file_menu.add_separator() self.file_menu.add_command(label='Save', accelerator='Ctrl+S', command=self.save_file) self.file_menu.add_command(label='Save as', accelerator='Ctrl+Shift+S', command=self.save_as) self.file_menu.add_separator() self.file_menu.add_command(label='Quit', command=self.close_programe) # edit menu self.edit_menu = tk.Menu(self.main_menu, tearoff=False) self.main_menu.add_cascade(label='Edit', menu=self.edit_menu) self.edit_menu.add_command(label='Undo', accelerator='Ctrl+Z', command=self.text.edit_undo) self.edit_menu.add_command(label='Redo', accelerator='Ctrl+Y', command=self.text.edit_redo) self.edit_menu.add_separator() self.edit_menu.add_command(label='Copy', accelerator='Ctrl+C', command=self.copy) self.edit_menu.add_command(label='Cut', accelerator='Ctrl+X', command=self.cut) self.edit_menu.add_command(label='Paste', accelerator='Ctrl+V', command=self.paste) self.edit_menu.add_command(label='Delete', command=self.delete) # view menu self.view_menu = tk.Menu(self.main_menu, tearoff=False) self.main_menu.add_cascade(label='View', menu=self.view_menu) self.view_menu.add_command(label='Zoon in', command=self.zoom_in) self.view_menu.add_command(label='Zoom out', command=self.zoom_out) self.view_menu.add_separator() self.view_menu.add_command(label='Change font', command=self.change_font) # color menu self.color_menu = tk.Menu(self.view_menu, tearoff=False) self.view_menu.add_cascade(label='Change Colors', menu=self.color_menu) self.color_menu.add_command(label='Change background color', command=self.change_bg) self.color_menu.add_command(label='Change foreground color', command=self.change_fg) # cursor menu self.cursor_menu = tk.Menu(self.view_menu, tearoff=False) self.view_menu.add_cascade(label='Change cursor', menu=self.cursor_menu) self.cursor_menu.add_command(label='Change color', command=self.change_cursor_color) self.cursor_menu.add_command(label='Change width', command=self.change_cursor_width) # shortcuts self.master.bind('<Control-n>', self.new_file) self.master.bind('<Control-N>', self.new_file) self.master.bind('<Control-o>', self.open_file) self.master.bind('<Control-O>', self.open_file) self.master.bind('<Control-s>', self.save_file) self.master.bind('<Control-S>', self.save_file) self.master.bind('<Shift-Control-s>', self.save_as) self.master.bind('<Shift-Control-S>', self.save_as) self.master.bind('<Control-plus>', self.zoom_in) self.master.bind('<Control-minus>', self.zoom_out) self.master.protocol('WM_DELETE_WINDOW', self.close_programe) # load all the important data. def load(self): # get the home path self.home = os.getenv('HOMEPATH') self.home = 'C://' + self.home # create folder to store the config data if not os.path.isdir(os.path.join(self.home, '.SB_Text_Editor')): os.mkdir(os.path.join(self.home, '.SB_Text_Editor')) # create the setting file to store the setting data. if os.path.isfile( os.path.join(self.home, '.SB_Text_Editor/settings.txt')): with open(os.path.join(self.home, '.SB_Text_Editor/settings.txt'), 'r') as settings: # in the setting file first line contain the data about the font. tmp = settings.readline().strip().split(';') if len(tmp) == 6: # load the font self.font_dict['family'] = tmp[0] self.font_dict['size'] = int(tmp[1]) self.font_dict['weight'] = tmp[2] self.font_dict['slant'] = tmp[3] self.font_dict['underline'] = int(tmp[4]) self.font_dict['overstrike'] = int(tmp[5]) self.font = Font(family=self.font_dict['family'], size=self.font_dict['size'], weight=self.font_dict['weight'], slant=self.font_dict['slant'], underline=self.font_dict['underline'], overstrike=self.font_dict['overstrike']) self.text.config(font=self.font) # second line contain the information about background and foreground color. tmp = settings.readline().strip().split(';') # load the colors if len(tmp) == 2: self.bg = tmp[0] self.fg = tmp[1] self.text.config(bg=self.bg, fg=self.fg) # third line contain data about cursor color and width. tmp = settings.readline().strip().split(';') if len(tmp) == 2: self.insert = tmp[0] self.insert_width = tmp[1] self.text.config(insertbackground=self.insert, insertwidth=self.insert_width) # create new file def new_file(self, event=None): if len(self.text.get(1.0, tk.END)) > 1: inp = messagebox.askyesnocancel('SB Text Editor', 'Do you want to save this file?') if inp == True: self.save_file() elif inp == None: return None self.file_name = None self.text.delete(1.0, tk.END) self.text.edit_reset() # open any text file def open_file(self, event=None): file = filedialog.askopenfile(filetype=[('Text file', '.txt'), ('All file', '*.*')]) if file != None: self.text.delete(1.0, tk.END) for line in file: self.text.insert(tk.INSERT, line) self.file_name = file.name # save the file def save_file(self, event=None): if self.file_name == None: self.save_as() else: with open(self.file_name, 'w') as file: file.write(self.text.get(1.0, tk.END)) def save_as(self, event=None): file = filedialog.asksaveasfile(mode='w', filetypes=[('Text file', '.txt'), ('All file', '*.*')], defaultextension='.txt') if file != None: file.write(self.text.get(1.0, tk.END)) self.file_name = file.name file.close() # exit function def close_programe(self, event=None): if len(self.text.get(1.0, tk.END)) > 1: inp = messagebox.askyesnocancel('SB Text Editor', 'Do you want to save this file?') if inp == True: self.save_file() elif inp == None: return None self.master.quit() # copy function def copy(self, event=None): self.text.event_generate('<<Copy>>') # cut function def cut(self, event=None): self.text.event_generate('<<Cut>>') # paste function def paste(self, event=None): self.text.event_generate('<<Paste>>') # delete selected line def delete(self, event=None): try: i1 = self.text.index('sel.first') i2 = self.text.index('sel.last') self.text.delete(i1, i2) except: return None # zoom in function def zoom_in(self, event=None): size = self.font.cget('size') size += 1 if size > 30: size = 30 self.font_dict['size'] = size self.font.config(size=size) self.text.config(font=self.font) # zoom out function def zoom_out(self, event=None): size = self.font.cget('size') size -= 1 if size < 3: size = 3 self.font_dict['size'] = size self.font.config(size=size) self.text.config(font=self.font) # change font function def change_font(self, event=None): font_dict = tkfontchooser.askfont(**self.font_dict) if font_dict != '': self.font_dict = font_dict font_dict = list(font_dict.values()) font = Font(family=font_dict[0], size=font_dict[1], weight=font_dict[2], slant=font_dict[3], underline=font_dict[4], overstrike=font_dict[5]) self.font = font self.text.config(font=self.font) with open(os.path.join(self.home, '.SB_Text_Editor/settings.txt'), 'w') as settings: tmp = ';'.join( map(lambda item: str(item), list(self.font_dict.values()))) tmp += '\n' + self.bg + ';' + self.fg tmp += '\n' + self.insert + ';' + str(self.insert_width) settings.write(tmp) # change background color def change_bg(self, event=None): color = colorchooser.askcolor() if color[1] != None: self.bg = color[1] self.text.config(bg=self.bg) with open(os.path.join(self.home, '.SB_Text_Editor/settings.txt'), 'w') as settings: tmp = ';'.join( map(lambda item: str(item), list(self.font_dict.values()))) tmp += '\n' + self.bg + ';' + self.fg tmp += '\n' + self.insert + ';' + str(self.insert_width) settings.write(tmp) # change foreground color def change_fg(self, event=None): color = colorchooser.askcolor() if color[1] != None: self.fg = color[1] self.text.config(fg=self.fg) with open(os.path.join(self.home, '.SB_Text_Editor/settings.txt'), 'w') as settings: tmp = ';'.join( map(lambda item: str(item), list(self.font_dict.values()))) tmp += '\n' + self.bg + ';' + self.fg tmp += '\n' + self.insert + ';' + str(self.insert_width) settings.write(tmp) # change cursor color def change_cursor_color(self): color = colorchooser.askcolor() if color[1] != None: self.insert = color[1] self.text.config(insertbackground=self.insert) with open(os.path.join(self.home, '.SB_Text_Editor/settings.txt'), 'w') as settings: tmp = ';'.join( map(lambda item: str(item), list(self.font_dict.values()))) tmp += '\n' + self.bg + ';' + self.fg tmp += '\n' + self.insert + ';' + str(self.insert_width) settings.write(tmp) def make_small(self): self.insert_width = 1 self.text.config(insertwidth=self.insert_width) with open(os.path.join(self.home, '.SB_Text_Editor/settings.txt'), 'w') as settings: tmp = ';'.join( map(lambda item: str(item), list(self.font_dict.values()))) tmp += '\n' + self.bg + ';' + self.fg tmp += '\n' + self.insert + ';' + str(self.insert_width) settings.write(tmp) self.tmp_window.destroy() def make_medium(self): self.insert_width = 3 self.text.config(insertwidth=self.insert_width) with open(os.path.join(self.home, '.SB_Text_Editor/settings.txt'), 'w') as settings: tmp = ';'.join( map(lambda item: str(item), list(self.font_dict.values()))) tmp += '\n' + self.bg + ';' + self.fg tmp += '\n' + self.insert + ';' + str(self.insert_width) settings.write(tmp) self.tmp_window.destroy() def make_large(self): self.insert_width = 5 self.text.config(insertwidth=self.insert_width) with open(os.path.join(self.home, '.SB_Text_Editor/settings.txt'), 'w') as settings: tmp = ';'.join( map(lambda item: str(item), list(self.font_dict.values()))) tmp += '\n' + self.bg + ';' + self.fg tmp += '\n' + self.insert + ';' + str(self.insert_width) settings.write(tmp) self.tmp_window.destroy() def change_cursor_width(self): self.tmp_window = tk.Toplevel() self.tmp_window.title('Select size') self.tmp_window.resizable(False, False) button_1 = tk.Button(self.tmp_window, text='Small', command=self.make_small) button_1.pack(side=tk.LEFT) button_2 = tk.Button(self.tmp_window, text='Medium', command=self.make_medium) button_2.pack(side=tk.LEFT) button_3 = tk.Button(self.tmp_window, text='Large', command=self.make_large) button_3.pack(side=tk.LEFT)
class RecursiveDescentApp(object): """ A graphical tool for exploring the recursive descent parser. The tool displays the parser's tree and the remaining text, and allows the user to control the parser's operation. In particular, the user can expand subtrees on the frontier, match tokens on the frontier against the text, and backtrack. A "step" button simply steps through the parsing process, performing the operations that ``RecursiveDescentParser`` would use. """ def __init__(self, grammar, sent, trace=0): self._sent = sent self._parser = SteppingRecursiveDescentParser(grammar, trace) # Set up the main window. self._top = Tk() self._top.title("Recursive Descent Parser Application") # Set up key bindings. self._init_bindings() # Initialize the fonts. self._init_fonts(self._top) # Animations. animating_lock is a lock to prevent the demo # from performing new operations while it's animating. self._animation_frames = IntVar(self._top) self._animation_frames.set(5) self._animating_lock = 0 self._autostep = 0 # The user can hide the grammar. self._show_grammar = IntVar(self._top) self._show_grammar.set(1) # Create the basic frames. self._init_menubar(self._top) self._init_buttons(self._top) self._init_feedback(self._top) self._init_grammar(self._top) self._init_canvas(self._top) # Initialize the parser. self._parser.initialize(self._sent) # Resize callback self._canvas.bind("<Configure>", self._configure) ######################################### ## Initialization Helpers ######################################### def _init_fonts(self, root): # See: <http://www.astro.washington.edu/owen/ROTKFolklore.html> self._sysfont = Font(font=Button()["font"]) root.option_add("*Font", self._sysfont) # TWhat's our font size (default=same as sysfont) self._size = IntVar(root) self._size.set(self._sysfont.cget("size")) self._boldfont = Font(family="helvetica", weight="bold", size=self._size.get()) self._font = Font(family="helvetica", size=self._size.get()) if self._size.get() < 0: big = self._size.get() - 2 else: big = self._size.get() + 2 self._bigfont = Font(family="helvetica", weight="bold", size=big) def _init_grammar(self, parent): # Grammar view. self._prodframe = listframe = Frame(parent) self._prodframe.pack(fill="both", side="left", padx=2) self._prodlist_label = Label(self._prodframe, font=self._boldfont, text="Available Expansions") self._prodlist_label.pack() self._prodlist = Listbox( self._prodframe, selectmode="single", relief="groove", background="white", foreground="#909090", font=self._font, selectforeground="#004040", selectbackground="#c0f0c0", ) self._prodlist.pack(side="right", fill="both", expand=1) self._productions = list(self._parser.grammar().productions()) for production in self._productions: self._prodlist.insert("end", (" %s" % production)) self._prodlist.config(height=min(len(self._productions), 25)) # Add a scrollbar if there are more than 25 productions. if len(self._productions) > 25: listscroll = Scrollbar(self._prodframe, orient="vertical") self._prodlist.config(yscrollcommand=listscroll.set) listscroll.config(command=self._prodlist.yview) listscroll.pack(side="left", fill="y") # If they select a production, apply it. self._prodlist.bind("<<ListboxSelect>>", self._prodlist_select) def _init_bindings(self): # Key bindings are a good thing. self._top.bind("<Control-q>", self.destroy) self._top.bind("<Control-x>", self.destroy) self._top.bind("<Escape>", self.destroy) self._top.bind("e", self.expand) # self._top.bind('<Alt-e>', self.expand) # self._top.bind('<Control-e>', self.expand) self._top.bind("m", self.match) self._top.bind("<Alt-m>", self.match) self._top.bind("<Control-m>", self.match) self._top.bind("b", self.backtrack) self._top.bind("<Alt-b>", self.backtrack) self._top.bind("<Control-b>", self.backtrack) self._top.bind("<Control-z>", self.backtrack) self._top.bind("<BackSpace>", self.backtrack) self._top.bind("a", self.autostep) # self._top.bind('<Control-a>', self.autostep) self._top.bind("<Control-space>", self.autostep) self._top.bind("<Control-c>", self.cancel_autostep) self._top.bind("<space>", self.step) self._top.bind("<Delete>", self.reset) self._top.bind("<Control-p>", self.postscript) # self._top.bind('<h>', self.help) # self._top.bind('<Alt-h>', self.help) self._top.bind("<Control-h>", self.help) self._top.bind("<F1>", self.help) # self._top.bind('<g>', self.toggle_grammar) # self._top.bind('<Alt-g>', self.toggle_grammar) # self._top.bind('<Control-g>', self.toggle_grammar) self._top.bind("<Control-g>", self.edit_grammar) self._top.bind("<Control-t>", self.edit_sentence) def _init_buttons(self, parent): # Set up the frames. self._buttonframe = buttonframe = Frame(parent) buttonframe.pack(fill="none", side="bottom", padx=3, pady=2) Button( buttonframe, text="Step", background="#90c0d0", foreground="black", command=self.step, ).pack(side="left") Button( buttonframe, text="Autostep", background="#90c0d0", foreground="black", command=self.autostep, ).pack(side="left") Button( buttonframe, text="Expand", underline=0, background="#90f090", foreground="black", command=self.expand, ).pack(side="left") Button( buttonframe, text="Match", underline=0, background="#90f090", foreground="black", command=self.match, ).pack(side="left") Button( buttonframe, text="Backtrack", underline=0, background="#f0a0a0", foreground="black", command=self.backtrack, ).pack(side="left") # Replace autostep... # self._autostep_button = Button(buttonframe, text='Autostep', # underline=0, command=self.autostep) # self._autostep_button.pack(side='left') def _configure(self, event): self._autostep = 0 (x1, y1, x2, y2) = self._cframe.scrollregion() y2 = event.height - 6 self._canvas["scrollregion"] = "%d %d %d %d" % (x1, y1, x2, y2) self._redraw() def _init_feedback(self, parent): self._feedbackframe = feedbackframe = Frame(parent) feedbackframe.pack(fill="x", side="bottom", padx=3, pady=3) self._lastoper_label = Label(feedbackframe, text="Last Operation:", font=self._font) self._lastoper_label.pack(side="left") lastoperframe = Frame(feedbackframe, relief="sunken", border=1) lastoperframe.pack(fill="x", side="right", expand=1, padx=5) self._lastoper1 = Label(lastoperframe, foreground="#007070", background="#f0f0f0", font=self._font) self._lastoper2 = Label( lastoperframe, anchor="w", width=30, foreground="#004040", background="#f0f0f0", font=self._font, ) self._lastoper1.pack(side="left") self._lastoper2.pack(side="left", fill="x", expand=1) def _init_canvas(self, parent): self._cframe = CanvasFrame( parent, background="white", # width=525, height=250, closeenough=10, border=2, relief="sunken", ) self._cframe.pack(expand=1, fill="both", side="top", pady=2) canvas = self._canvas = self._cframe.canvas() # Initially, there's no tree or text self._tree = None self._textwidgets = [] self._textline = None def _init_menubar(self, parent): menubar = Menu(parent) filemenu = Menu(menubar, tearoff=0) filemenu.add_command(label="Reset Parser", underline=0, command=self.reset, accelerator="Del") filemenu.add_command( label="Print to Postscript", underline=0, command=self.postscript, accelerator="Ctrl-p", ) filemenu.add_command(label="Exit", underline=1, command=self.destroy, accelerator="Ctrl-x") menubar.add_cascade(label="File", underline=0, menu=filemenu) editmenu = Menu(menubar, tearoff=0) editmenu.add_command( label="Edit Grammar", underline=5, command=self.edit_grammar, accelerator="Ctrl-g", ) editmenu.add_command( label="Edit Text", underline=5, command=self.edit_sentence, accelerator="Ctrl-t", ) menubar.add_cascade(label="Edit", underline=0, menu=editmenu) rulemenu = Menu(menubar, tearoff=0) rulemenu.add_command(label="Step", underline=1, command=self.step, accelerator="Space") rulemenu.add_separator() rulemenu.add_command(label="Match", underline=0, command=self.match, accelerator="Ctrl-m") rulemenu.add_command(label="Expand", underline=0, command=self.expand, accelerator="Ctrl-e") rulemenu.add_separator() rulemenu.add_command(label="Backtrack", underline=0, command=self.backtrack, accelerator="Ctrl-b") menubar.add_cascade(label="Apply", underline=0, menu=rulemenu) viewmenu = Menu(menubar, tearoff=0) viewmenu.add_checkbutton( label="Show Grammar", underline=0, variable=self._show_grammar, command=self._toggle_grammar, ) viewmenu.add_separator() viewmenu.add_radiobutton( label="Tiny", variable=self._size, underline=0, value=10, command=self.resize, ) viewmenu.add_radiobutton( label="Small", variable=self._size, underline=0, value=12, command=self.resize, ) viewmenu.add_radiobutton( label="Medium", variable=self._size, underline=0, value=14, command=self.resize, ) viewmenu.add_radiobutton( label="Large", variable=self._size, underline=0, value=18, command=self.resize, ) viewmenu.add_radiobutton( label="Huge", variable=self._size, underline=0, value=24, command=self.resize, ) menubar.add_cascade(label="View", underline=0, menu=viewmenu) animatemenu = Menu(menubar, tearoff=0) animatemenu.add_radiobutton(label="No Animation", underline=0, variable=self._animation_frames, value=0) animatemenu.add_radiobutton( label="Slow Animation", underline=0, variable=self._animation_frames, value=10, accelerator="-", ) animatemenu.add_radiobutton( label="Normal Animation", underline=0, variable=self._animation_frames, value=5, accelerator="=", ) animatemenu.add_radiobutton( label="Fast Animation", underline=0, variable=self._animation_frames, value=2, accelerator="+", ) menubar.add_cascade(label="Animate", underline=1, menu=animatemenu) helpmenu = Menu(menubar, tearoff=0) helpmenu.add_command(label="About", underline=0, command=self.about) helpmenu.add_command(label="Instructions", underline=0, command=self.help, accelerator="F1") menubar.add_cascade(label="Help", underline=0, menu=helpmenu) parent.config(menu=menubar) ######################################### ## Helper ######################################### def _get(self, widget, treeloc): for i in treeloc: widget = widget.subtrees()[i] if isinstance(widget, TreeSegmentWidget): widget = widget.label() return widget ######################################### ## Main draw procedure ######################################### def _redraw(self): canvas = self._canvas # Delete the old tree, widgets, etc. if self._tree is not None: self._cframe.destroy_widget(self._tree) for twidget in self._textwidgets: self._cframe.destroy_widget(twidget) if self._textline is not None: self._canvas.delete(self._textline) # Draw the tree. helv = ("helvetica", -self._size.get()) bold = ("helvetica", -self._size.get(), "bold") attribs = { "tree_color": "#000000", "tree_width": 2, "node_font": bold, "leaf_font": helv, } tree = self._parser.tree() self._tree = tree_to_treesegment(canvas, tree, **attribs) self._cframe.add_widget(self._tree, 30, 5) # Draw the text. helv = ("helvetica", -self._size.get()) bottom = y = self._cframe.scrollregion()[3] self._textwidgets = [ TextWidget(canvas, word, font=self._font) for word in self._sent ] for twidget in self._textwidgets: self._cframe.add_widget(twidget, 0, 0) twidget.move(0, bottom - twidget.bbox()[3] - 5) y = min(y, twidget.bbox()[1]) # Draw a line over the text, to separate it from the tree. self._textline = canvas.create_line(-5000, y - 5, 5000, y - 5, dash=".") # Highlight appropriate nodes. self._highlight_nodes() self._highlight_prodlist() # Make sure the text lines up. self._position_text() def _redraw_quick(self): # This should be more-or-less sufficient after an animation. self._highlight_nodes() self._highlight_prodlist() self._position_text() def _highlight_nodes(self): # Highlight the list of nodes to be checked. bold = ("helvetica", -self._size.get(), "bold") for treeloc in self._parser.frontier()[:1]: self._get(self._tree, treeloc)["color"] = "#20a050" self._get(self._tree, treeloc)["font"] = bold for treeloc in self._parser.frontier()[1:]: self._get(self._tree, treeloc)["color"] = "#008080" def _highlight_prodlist(self): # Highlight the productions that can be expanded. # Boy, too bad tkinter doesn't implement Listbox.itemconfig; # that would be pretty useful here. self._prodlist.delete(0, "end") expandable = self._parser.expandable_productions() untried = self._parser.untried_expandable_productions() productions = self._productions for index in range(len(productions)): if productions[index] in expandable: if productions[index] in untried: self._prodlist.insert(index, " %s" % productions[index]) else: self._prodlist.insert(index, " %s (TRIED)" % productions[index]) self._prodlist.selection_set(index) else: self._prodlist.insert(index, " %s" % productions[index]) def _position_text(self): # Line up the text widgets that are matched against the tree numwords = len(self._sent) num_matched = numwords - len(self._parser.remaining_text()) leaves = self._tree_leaves()[:num_matched] xmax = self._tree.bbox()[0] for i in range(0, len(leaves)): widget = self._textwidgets[i] leaf = leaves[i] widget["color"] = "#006040" leaf["color"] = "#006040" widget.move(leaf.bbox()[0] - widget.bbox()[0], 0) xmax = widget.bbox()[2] + 10 # Line up the text widgets that are not matched against the tree. for i in range(len(leaves), numwords): widget = self._textwidgets[i] widget["color"] = "#a0a0a0" widget.move(xmax - widget.bbox()[0], 0) xmax = widget.bbox()[2] + 10 # If we have a complete parse, make everything green :) if self._parser.currently_complete(): for twidget in self._textwidgets: twidget["color"] = "#00a000" # Move the matched leaves down to the text. for i in range(0, len(leaves)): widget = self._textwidgets[i] leaf = leaves[i] dy = widget.bbox()[1] - leaf.bbox()[3] - 10.0 dy = max(dy, leaf.parent().label().bbox()[3] - leaf.bbox()[3] + 10) leaf.move(0, dy) def _tree_leaves(self, tree=None): if tree is None: tree = self._tree if isinstance(tree, TreeSegmentWidget): leaves = [] for child in tree.subtrees(): leaves += self._tree_leaves(child) return leaves else: return [tree] ######################################### ## Button Callbacks ######################################### def destroy(self, *e): self._autostep = 0 if self._top is None: return self._top.destroy() self._top = None def reset(self, *e): self._autostep = 0 self._parser.initialize(self._sent) self._lastoper1["text"] = "Reset Application" self._lastoper2["text"] = "" self._redraw() def autostep(self, *e): if self._animation_frames.get() == 0: self._animation_frames.set(2) if self._autostep: self._autostep = 0 else: self._autostep = 1 self._step() def cancel_autostep(self, *e): # self._autostep_button['text'] = 'Autostep' self._autostep = 0 # Make sure to stop auto-stepping if we get any user input. def step(self, *e): self._autostep = 0 self._step() def match(self, *e): self._autostep = 0 self._match() def expand(self, *e): self._autostep = 0 self._expand() def backtrack(self, *e): self._autostep = 0 self._backtrack() def _step(self): if self._animating_lock: return # Try expanding, matching, and backtracking (in that order) if self._expand(): pass elif self._parser.untried_match() and self._match(): pass elif self._backtrack(): pass else: self._lastoper1["text"] = "Finished" self._lastoper2["text"] = "" self._autostep = 0 # Check if we just completed a parse. if self._parser.currently_complete(): self._autostep = 0 self._lastoper2["text"] += " [COMPLETE PARSE]" def _expand(self, *e): if self._animating_lock: return old_frontier = self._parser.frontier() rv = self._parser.expand() if rv is not None: self._lastoper1["text"] = "Expand:" self._lastoper2["text"] = rv self._prodlist.selection_clear(0, "end") index = self._productions.index(rv) self._prodlist.selection_set(index) self._animate_expand(old_frontier[0]) return True else: self._lastoper1["text"] = "Expand:" self._lastoper2["text"] = "(all expansions tried)" return False def _match(self, *e): if self._animating_lock: return old_frontier = self._parser.frontier() rv = self._parser.match() if rv is not None: self._lastoper1["text"] = "Match:" self._lastoper2["text"] = rv self._animate_match(old_frontier[0]) return True else: self._lastoper1["text"] = "Match:" self._lastoper2["text"] = "(failed)" return False def _backtrack(self, *e): if self._animating_lock: return if self._parser.backtrack(): elt = self._parser.tree() for i in self._parser.frontier()[0]: elt = elt[i] self._lastoper1["text"] = "Backtrack" self._lastoper2["text"] = "" if isinstance(elt, Tree): self._animate_backtrack(self._parser.frontier()[0]) else: self._animate_match_backtrack(self._parser.frontier()[0]) return True else: self._autostep = 0 self._lastoper1["text"] = "Finished" self._lastoper2["text"] = "" return False def about(self, *e): ABOUT = ("NLTK Recursive Descent Parser Application\n" + "Written by Edward Loper") TITLE = "About: Recursive Descent Parser Application" try: from tkinter.messagebox import Message Message(message=ABOUT, title=TITLE).show() except: ShowText(self._top, TITLE, ABOUT) def help(self, *e): self._autostep = 0 # The default font's not very legible; try using 'fixed' instead. try: ShowText( self._top, "Help: Recursive Descent Parser Application", (__doc__ or "").strip(), width=75, font="fixed", ) except: ShowText( self._top, "Help: Recursive Descent Parser Application", (__doc__ or "").strip(), width=75, ) def postscript(self, *e): self._autostep = 0 self._cframe.print_to_file() def mainloop(self, *args, **kwargs): """ Enter the Tkinter mainloop. This function must be called if this demo is created from a non-interactive program (e.g. from a secript); otherwise, the demo will close as soon as the script completes. """ if in_idle(): return self._top.mainloop(*args, **kwargs) def resize(self, size=None): if size is not None: self._size.set(size) size = self._size.get() self._font.configure(size=-(abs(size))) self._boldfont.configure(size=-(abs(size))) self._sysfont.configure(size=-(abs(size))) self._bigfont.configure(size=-(abs(size + 2))) self._redraw() ######################################### ## Expand Production Selection ######################################### def _toggle_grammar(self, *e): if self._show_grammar.get(): self._prodframe.pack(fill="both", side="left", padx=2, after=self._feedbackframe) self._lastoper1["text"] = "Show Grammar" else: self._prodframe.pack_forget() self._lastoper1["text"] = "Hide Grammar" self._lastoper2["text"] = "" # def toggle_grammar(self, *e): # self._show_grammar = not self._show_grammar # if self._show_grammar: # self._prodframe.pack(fill='both', expand='y', side='left', # after=self._feedbackframe) # self._lastoper1['text'] = 'Show Grammar' # else: # self._prodframe.pack_forget() # self._lastoper1['text'] = 'Hide Grammar' # self._lastoper2['text'] = '' def _prodlist_select(self, event): selection = self._prodlist.curselection() if len(selection) != 1: return index = int(selection[0]) old_frontier = self._parser.frontier() production = self._parser.expand(self._productions[index]) if production: self._lastoper1["text"] = "Expand:" self._lastoper2["text"] = production self._prodlist.selection_clear(0, "end") self._prodlist.selection_set(index) self._animate_expand(old_frontier[0]) else: # Reset the production selections. self._prodlist.selection_clear(0, "end") for prod in self._parser.expandable_productions(): index = self._productions.index(prod) self._prodlist.selection_set(index) ######################################### ## Animation ######################################### def _animate_expand(self, treeloc): oldwidget = self._get(self._tree, treeloc) oldtree = oldwidget.parent() top = not isinstance(oldtree.parent(), TreeSegmentWidget) tree = self._parser.tree() for i in treeloc: tree = tree[i] widget = tree_to_treesegment( self._canvas, tree, node_font=self._boldfont, leaf_color="white", tree_width=2, tree_color="white", node_color="white", leaf_font=self._font, ) widget.label()["color"] = "#20a050" (oldx, oldy) = oldtree.label().bbox()[:2] (newx, newy) = widget.label().bbox()[:2] widget.move(oldx - newx, oldy - newy) if top: self._cframe.add_widget(widget, 0, 5) widget.move(30 - widget.label().bbox()[0], 0) self._tree = widget else: oldtree.parent().replace_child(oldtree, widget) # Move the children over so they don't overlap. # Line the children up in a strange way. if widget.subtrees(): dx = (oldx + widget.label().width() / 2 - widget.subtrees()[0].bbox()[0] / 2 - widget.subtrees()[0].bbox()[2] / 2) for subtree in widget.subtrees(): subtree.move(dx, 0) self._makeroom(widget) if top: self._cframe.destroy_widget(oldtree) else: oldtree.destroy() colors = [ "gray%d" % (10 * int(10 * x / self._animation_frames.get())) for x in range(self._animation_frames.get(), 0, -1) ] # Move the text string down, if necessary. dy = widget.bbox()[3] + 30 - self._canvas.coords(self._textline)[1] if dy > 0: for twidget in self._textwidgets: twidget.move(0, dy) self._canvas.move(self._textline, 0, dy) self._animate_expand_frame(widget, colors) def _makeroom(self, treeseg): """ Make sure that no sibling tree bbox's overlap. """ parent = treeseg.parent() if not isinstance(parent, TreeSegmentWidget): return index = parent.subtrees().index(treeseg) # Handle siblings to the right rsiblings = parent.subtrees()[index + 1:] if rsiblings: dx = treeseg.bbox()[2] - rsiblings[0].bbox()[0] + 10 for sibling in rsiblings: sibling.move(dx, 0) # Handle siblings to the left if index > 0: lsibling = parent.subtrees()[index - 1] dx = max(0, lsibling.bbox()[2] - treeseg.bbox()[0] + 10) treeseg.move(dx, 0) # Keep working up the tree. self._makeroom(parent) def _animate_expand_frame(self, widget, colors): if len(colors) > 0: self._animating_lock = 1 widget["color"] = colors[0] for subtree in widget.subtrees(): if isinstance(subtree, TreeSegmentWidget): subtree.label()["color"] = colors[0] else: subtree["color"] = colors[0] self._top.after(50, self._animate_expand_frame, widget, colors[1:]) else: widget["color"] = "black" for subtree in widget.subtrees(): if isinstance(subtree, TreeSegmentWidget): subtree.label()["color"] = "black" else: subtree["color"] = "black" self._redraw_quick() widget.label()["color"] = "black" self._animating_lock = 0 if self._autostep: self._step() def _animate_backtrack(self, treeloc): # Flash red first, if we're animating. if self._animation_frames.get() == 0: colors = [] else: colors = ["#a00000", "#000000", "#a00000"] colors += [ "gray%d" % (10 * int(10 * x / (self._animation_frames.get()))) for x in range(1, self._animation_frames.get() + 1) ] widgets = [self._get(self._tree, treeloc).parent()] for subtree in widgets[0].subtrees(): if isinstance(subtree, TreeSegmentWidget): widgets.append(subtree.label()) else: widgets.append(subtree) self._animate_backtrack_frame(widgets, colors) def _animate_backtrack_frame(self, widgets, colors): if len(colors) > 0: self._animating_lock = 1 for widget in widgets: widget["color"] = colors[0] self._top.after(50, self._animate_backtrack_frame, widgets, colors[1:]) else: for widget in widgets[0].subtrees(): widgets[0].remove_child(widget) widget.destroy() self._redraw_quick() self._animating_lock = 0 if self._autostep: self._step() def _animate_match_backtrack(self, treeloc): widget = self._get(self._tree, treeloc) node = widget.parent().label() dy = (node.bbox()[3] - widget.bbox()[1] + 14) / max( 1, self._animation_frames.get()) self._animate_match_backtrack_frame(self._animation_frames.get(), widget, dy) def _animate_match(self, treeloc): widget = self._get(self._tree, treeloc) dy = (self._textwidgets[0].bbox()[1] - widget.bbox()[3] - 10.0) / max( 1, self._animation_frames.get()) self._animate_match_frame(self._animation_frames.get(), widget, dy) def _animate_match_frame(self, frame, widget, dy): if frame > 0: self._animating_lock = 1 widget.move(0, dy) self._top.after(10, self._animate_match_frame, frame - 1, widget, dy) else: widget["color"] = "#006040" self._redraw_quick() self._animating_lock = 0 if self._autostep: self._step() def _animate_match_backtrack_frame(self, frame, widget, dy): if frame > 0: self._animating_lock = 1 widget.move(0, dy) self._top.after(10, self._animate_match_backtrack_frame, frame - 1, widget, dy) else: widget.parent().remove_child(widget) widget.destroy() self._animating_lock = 0 if self._autostep: self._step() def edit_grammar(self, *e): CFGEditor(self._top, self._parser.grammar(), self.set_grammar) def set_grammar(self, grammar): self._parser.set_grammar(grammar) self._productions = list(grammar.productions()) self._prodlist.delete(0, "end") for production in self._productions: self._prodlist.insert("end", (" %s" % production)) def edit_sentence(self, *e): sentence = " ".join(self._sent) title = "Edit Text" instr = "Enter a new sentence to parse." EntryDialog(self._top, sentence, instr, self.set_sentence, title) def set_sentence(self, sentence): self._sent = sentence.split() # [XX] use tagged? self.reset()
def openFile(root, text, dirToOpen=None): if dirToOpen == None: dirToOpen = askopenfilename(parent=root, title='Choose file to open', filetypes=(("Notecalc documents (*.nxc)", "*.nxc"), ("Text documents (*.txt)", "*.txt"), ("All files", "*.*"))) dirToOpen = toPath(dirToOpen) with open(dirToOpen, 'r', encoding='utf-8') as file: text.delete('1.0', 'end') fileText = file.read() if str(dirToOpen).endswith(".nxc") == True: fileText = literal_eval(fileText) final = "" for (key, value, index) in fileText: if key == "text": final += value text.insert('1.0', final) tagsInitIndexes = list() for (key, value, index) in fileText: if key == "tagon": tagsInitIndexes.append(index) elif key == "tagoff": tagInitIndex = tagsInitIndexes.pop(0) if len(value) < 14: size = globals.font.cget("size") size = str(size) if len(size) < 2: size = "0" + size sampleTag = "......." + size[0] + size[ 1] + globals.colorConfig["def"] size = int(size) if "bt" in value: sampleTag = replaceSubstring( sampleTag, ".", "n", globals.formsIndex["n"]) elif "stit" in value: sampleTag = replaceSubstring( sampleTag, ".", "i", globals.formsIndex["i"]) sizeSubTitulo = size + 2 sizeSubTitulo = str(sizeSubTitulo) if len(sizeSubTitulo) < 2: sizeSubTitulo = "0" + sizeSubTitulo sampleTag = replaceSubstring( sampleTag, sampleTag[globals.formsIndex["size"]], sizeSubTitulo[0], globals.formsIndex["size"]) sampleTag = replaceSubstring( sampleTag, sampleTag[globals.formsIndex["size"] + 1], sizeSubTitulo[1], globals.formsIndex["size"] + 1) elif "tit" in value: if (sampleTag[globals.formsIndex["n"]] != "n"): sampleTag = replaceSubstring( sampleTag, ".", "n", globals.formsIndex["n"]) sizeTitulo = size + 4 sizeTitulo = str(sizeTitulo) if len(sizeTitulo) < 2: sizeTitulo = "0" + sizeTitulo sampleTag = replaceSubstring( sampleTag, sampleTag[globals.formsIndex["size"]], sizeTitulo[0], globals.formsIndex["size"]) sampleTag = replaceSubstring( sampleTag, sampleTag[globals.formsIndex["size"] + 1], sizeTitulo[1], globals.formsIndex["size"] + 1) elif "it" in value: if (sampleTag[globals.formsIndex["i"]] != "i"): sampleTag = replaceSubstring( sampleTag, ".", "i", globals.formsIndex["i"]) elif "un" in value: sampleTag = replaceSubstring( sampleTag, ".", "s", globals.formsIndex["s"]) elif "tc" in value: sampleTag = replaceSubstring( sampleTag, ".", "t", globals.formsIndex["t"]) elif "cor" in value: cor = value[3::] sampleTag = "cor" + sampleTag[ globals.formsIndex["n"]:globals. formsIndex["hex"]] + cor # Pra manter a compatibilidade com os arquivos da antiga formatação elif value.startswith("#"): cor = value sampleTag = "cor" + sampleTag[ globals.formsIndex["n"]:globals. formsIndex["hex"]] + cor fontDaFormatacao = Font(text, text.cget("font")) fontSize = fontDaFormatacao.cget("size") if "n" in sampleTag[globals.formsIndex["n"]:]: fontDaFormatacao.config(weight="bold") if "i" in sampleTag[globals.formsIndex["n"]:]: fontDaFormatacao.config(slant="italic") if "t" in sampleTag[globals.formsIndex["n"]:]: fontDaFormatacao.config(overstrike=1) if "s" in sampleTag[globals.formsIndex["n"]:]: fontDaFormatacao.config(underline=1) if (len(sampleTag) == 14): size = sampleTag[5:7] elif (len(sampleTag) == 16): size = sampleTag[globals.formsIndex["size"]:globals .formsIndex["size"] + 2] fontDaFormatacao.config(size=int(size)) cor = globals.configCores["padrao"] prefixo = "..." if sampleTag[0] == "c": cor = sampleTag[globals.formsIndex["hex"]::] prefixo = "cor" elif globals.vsc == True: if "n" in sampleTag[globals. formsIndex["n"]:] and int( size) != fontSize + 4: cor = globals.configCores["negrito"] prefixo = "vbt" if "n" in sampleTag[globals. formsIndex["n"]:] and int( size) == fontSize + 4: cor = globals.configCores["titulo"] prefixo = "vtt" if "i" in sampleTag[globals. formsIndex["n"]:] and int( size) != fontSize + 2: cor = globals.configCores["italico"] prefixo = "vit" if "i" in sampleTag[globals. formsIndex["n"]:] and int( size) == fontSize + 2: cor = globals.configCores["subtitulo"] prefixo = "vst" if "s" in sampleTag[globals.formsIndex["n"]:]: cor = globals.configCores["sublinhado"] prefixo = "vtc" if "t" in sampleTag[globals.formsIndex["n"]:]: cor = globals.configCores["tachado"] prefixo = "vun" sampleTag = prefixo + sampleTag[ globals.formsIndex["n"]:globals. formsIndex["hex"]] + cor text.tag_config(sampleTag, font=fontDaFormatacao, foreground=cor) text.tag_add(sampleTag, f"{tagInitIndex}", f"{index}") elif len(value) >= 14: fontDaFormatacao = Font(text, text.cget("font")) fontSize = fontDaFormatacao.cget("size") if "n" in value[globals.formsIndex["n"]:]: fontDaFormatacao.config(weight="bold") if "i" in value[globals.formsIndex["n"]:]: fontDaFormatacao.config(slant="italic") if "t" in value[globals.formsIndex["n"]:]: fontDaFormatacao.config(overstrike=1) if "s" in value[globals.formsIndex["n"]:]: fontDaFormatacao.config(underline=1) if (len(value) == 14): size = value[5:7] elif (len(value) == 16): size = value[globals.formsIndex["size"]:globals. formsIndex["size"] + 2] fontDaFormatacao.config(size=int(size)) cor = globals.configCores["padrao"] if value[0] == "v" and globals.vsc == True: if value[:globals.formsIndex["n"]] == "vbt": cor = globals.configCores["negrito"] if value[:globals.formsIndex["n"]] == "vtt": cor = globals.configCores["titulo"] if value[:globals.formsIndex["n"]] == "vit": cor = globals.configCores["italico"] if value[:globals.formsIndex["n"]] == "vst": cor = globals.configCores["subtitulo"] if value[:globals.formsIndex["n"]] == "vun": cor = globals.configCores["sublinhado"] if value[:globals.formsIndex["n"]] == "vtc": cor = globals.configCores["tachado"] elif value[0] == "c": cor = value[globals.formsIndex["hex"]::] value = value[:globals.formsIndex["hex"]] + cor text.tag_config(value, font=fontDaFormatacao, foreground=cor) text.tag_add(value, f"{tagInitIndex}", f"{index}") text.edit_modified(False) globals.dirDeTrabalhoAtual = dirToOpen chdir(dirname(dirToOpen)) root.title("Lolicalc " + str(globals.dirDeTrabalhoAtual)) return True else: text.edit_modified(False) globals.dirDeTrabalhoAtual = dirToOpen chdir(dirname(dirToOpen)) root.title("Lolicalc " + str(globals.dirDeTrabalhoAtual)) text.insert('1.0', fileText) return True