def __init__(self, cfg, gui=None): self.cfg = cfg if gui is None: self.standalone_run = True else: self.gui = gui self.standalone_run = False self.machine_api = self.cfg.machine_api if self.standalone_run: self.root = tkinter.Tk(className="EDITOR") self.root.geometry("+%d+%d" % ( self.root.winfo_screenwidth() * 0.1, self.root.winfo_screenheight() * 0.1 )) else: # As sub window in DragonPy Emulator self.root = tkinter.Toplevel(self.gui.root) self.root.geometry("+%d+%d" % ( self.gui.root.winfo_rootx() + self.gui.root.winfo_width(), self.gui.root.winfo_y() # FIXME: Different on linux. )) self.root.columnconfigure(0, weight=1) self.root.rowconfigure(0, weight=1) self.base_title = "%s - BASIC Editor" % self.cfg.MACHINE_NAME self.root.title(self.base_title) self.text = ScrolledText( master=self.root, height=30, width=80 ) self.text.config( background="#ffffff", foreground="#000000", highlightthickness=0, font=('courier', 11), ) self.text.grid(row=0, column=0, sticky=tkinter.NSEW) self.highlighting = TkTextHighlighting(self) self.highlight_currentline = TkTextHighlightCurrentLine(self) #self.auto_shift = True # use invert shift for letters? self.menubar = tkinter.Menu(self.root) filemenu = tkinter.Menu(self.menubar, tearoff=0) filemenu.add_command(label="Load", command=self.command_load_file) filemenu.add_command(label="Save", command=self.command_save_file) if self.standalone_run: filemenu.add_command(label="Exit", command=self.root.quit) self.menubar.add_cascade(label="File", menu=filemenu) editmenu = tkinter.Menu(self.menubar, tearoff=0) editmenu.add_command(label="renum", command=self.renumber_listing) editmenu.add_command(label="reformat", command=self.reformat_listing) editmenu.add_command(label="display tokens", command=self.debug_display_tokens) self.menubar.add_cascade(label="tools", menu=editmenu) # help menu helpmenu = tkinter.Menu(self.menubar, tearoff=0) # helpmenu.add_command(label="help", command=self.menu_event_help) # helpmenu.add_command(label="about", command=self.menu_event_about) self.menubar.add_cascade(label="help", menu=helpmenu) # startup directory for file open/save self.current_dir = os.path.abspath( os.path.join( os.path.dirname(dragonlib.__file__), "..", "BASIC examples", ) ) self.set_status_bar() # Create widget, add bindings and after_idle() update self.text.bind("<Key>", self.event_text_key) # self.text.bind("<space>", self.event_syntax_check) # display the menu self.root.config(menu=self.menubar) self.root.update()
def __init__(self, cfg, gui=None): self.cfg = cfg if gui is None: self.standalone_run = True else: self.gui = gui self.standalone_run = False self.machine_api = self.cfg.machine_api if self.standalone_run: self.root = tkinter.Tk(className="EDITOR") self.root.geometry("+%d+%d" % (self.root.winfo_screenwidth() * 0.1, self.root.winfo_screenheight() * 0.1)) else: # As sub window in DragonPy Emulator self.root = tkinter.Toplevel(self.gui.root) self.root.geometry("+%d+%d" % ( self.gui.root.winfo_rootx() + self.gui.root.winfo_width(), self.gui.root.winfo_y() # FIXME: Different on linux. )) self.root.columnconfigure(0, weight=1) self.root.rowconfigure(0, weight=1) self.base_title = "%s - BASIC Editor" % self.cfg.MACHINE_NAME self.root.title(self.base_title) self.text = ScrolledText(master=self.root, height=30, width=80) self.text.config( background="#ffffff", foreground="#000000", highlightthickness=0, font=('courier', 11), ) self.text.grid(row=0, column=0, sticky=tkinter.NSEW) self.highlighting = TkTextHighlighting(self) self.highlight_currentline = TkTextHighlightCurrentLine(self) #self.auto_shift = True # use invert shift for letters? self.menubar = tkinter.Menu(self.root) filemenu = tkinter.Menu(self.menubar, tearoff=0) filemenu.add_command(label="Load", command=self.command_load_file) filemenu.add_command(label="Save", command=self.command_save_file) if self.standalone_run: filemenu.add_command(label="Exit", command=self.root.quit) self.menubar.add_cascade(label="File", menu=filemenu) editmenu = tkinter.Menu(self.menubar, tearoff=0) editmenu.add_command(label="renum", command=self.renumber_listing) editmenu.add_command(label="reformat", command=self.reformat_listing) editmenu.add_command(label="display tokens", command=self.debug_display_tokens) self.menubar.add_cascade(label="tools", menu=editmenu) # help menu helpmenu = tkinter.Menu(self.menubar, tearoff=0) # helpmenu.add_command(label="help", command=self.menu_event_help) # helpmenu.add_command(label="about", command=self.menu_event_about) self.menubar.add_cascade(label="help", menu=helpmenu) # startup directory for file open/save self.current_dir = os.path.abspath( os.path.join( os.path.dirname(dragonlib.__file__), "..", "BASIC examples", )) self.set_status_bar( ) # Create widget, add bindings and after_idle() update self.text.bind("<Key>", self.event_text_key) # self.text.bind("<space>", self.event_syntax_check) # display the menu self.root.config(menu=self.menubar) self.root.update()
class EditorWindow(object): FILETYPES = [# For filedialog ("BASIC Listings", "*.bas", "TEXT"), ("Text files", "*.txt", "TEXT"), ("All files", "*"), ] DEFAULTEXTENSION = "*.bas" def __init__(self, cfg, gui=None): self.cfg = cfg if gui is None: self.standalone_run = True else: self.gui = gui self.standalone_run = False self.machine_api = self.cfg.machine_api if self.standalone_run: self.root = tkinter.Tk(className="EDITOR") self.root.geometry("+%d+%d" % ( self.root.winfo_screenwidth() * 0.1, self.root.winfo_screenheight() * 0.1 )) else: # As sub window in DragonPy Emulator self.root = tkinter.Toplevel(self.gui.root) self.root.geometry("+%d+%d" % ( self.gui.root.winfo_rootx() + self.gui.root.winfo_width(), self.gui.root.winfo_y() # FIXME: Different on linux. )) self.root.columnconfigure(0, weight=1) self.root.rowconfigure(0, weight=1) self.base_title = "%s - BASIC Editor" % self.cfg.MACHINE_NAME self.root.title(self.base_title) self.text = ScrolledText( master=self.root, height=30, width=80 ) self.text.config( background="#ffffff", foreground="#000000", highlightthickness=0, font=('courier', 11), ) self.text.grid(row=0, column=0, sticky=tkinter.NSEW) self.highlighting = TkTextHighlighting(self) self.highlight_currentline = TkTextHighlightCurrentLine(self) #self.auto_shift = True # use invert shift for letters? self.menubar = tkinter.Menu(self.root) filemenu = tkinter.Menu(self.menubar, tearoff=0) filemenu.add_command(label="Load", command=self.command_load_file) filemenu.add_command(label="Save", command=self.command_save_file) if self.standalone_run: filemenu.add_command(label="Exit", command=self.root.quit) self.menubar.add_cascade(label="File", menu=filemenu) editmenu = tkinter.Menu(self.menubar, tearoff=0) editmenu.add_command(label="renum", command=self.renumber_listing) editmenu.add_command(label="reformat", command=self.reformat_listing) editmenu.add_command(label="display tokens", command=self.debug_display_tokens) self.menubar.add_cascade(label="tools", menu=editmenu) # help menu helpmenu = tkinter.Menu(self.menubar, tearoff=0) # helpmenu.add_command(label="help", command=self.menu_event_help) # helpmenu.add_command(label="about", command=self.menu_event_about) self.menubar.add_cascade(label="help", menu=helpmenu) # startup directory for file open/save self.current_dir = os.path.abspath( os.path.join( os.path.dirname(dragonlib.__file__), "..", "BASIC examples", ) ) self.set_status_bar() # Create widget, add bindings and after_idle() update self.text.bind("<Key>", self.event_text_key) # self.text.bind("<space>", self.event_syntax_check) # display the menu self.root.config(menu=self.menubar) self.root.update() ########################################################################### # Status bar def set_status_bar(self): self.status_bar = MultiStatusBar(self.root) if sys.platform == "darwin": # Insert some padding to avoid obscuring some of the statusbar # by the resize widget. self.status_bar.set_label('_padding1', ' ', side=tkinter.RIGHT) self.status_bar.grid(row=1, column=0) self.text.bind("<<set-line-and-column>>", self.set_line_and_column) self.text.event_add("<<set-line-and-column>>", "<KeyRelease>", "<ButtonRelease>") self.text.after_idle(self.set_line_and_column) def set_line_and_column(self, event=None): line, column = self.text.index(tkinter.INSERT).split('.') self.status_bar.set_label('column', 'Column: %s' % column) self.status_bar.set_label('line', 'Line: %s' % line) ########################################################################### def event_text_key(self, event): """ So a "invert shift" for user inputs: Convert all lowercase letters to uppercase and vice versa. """ char = event.char if not char or char not in string.ascii_letters: # ignore all non letter inputs return converted_char = invert_shift(char) log.debug("convert keycode %s - char %s to %s", event.keycode, repr(char), converted_char) # self.text.delete(Tkinter.INSERT + "-1c") # Delete last input char self.text.insert(tkinter.INSERT, converted_char) # Insert converted char return "break" # def event_syntax_check(self, event): # index = self.text.search(r'\s', "insert", backwards=True, regexp=True) # if index == "": # index ="1.0" # else: # index = self.text.index("%s+1c" % index) # word = self.text.get(index, "insert") # log.critical("inserted word: %r", word) # print self.machine_api.parse_ascii_listing(word) def setup_filepath(self, filepath): log.critical(filepath) self.filepath = os.path.normpath(os.path.abspath(filepath)) self.current_dir, self.filename = os.path.split(self.filepath) self.root.title("%s - %s" % (self.base_title, repr(self.filename))) def command_load_file(self): infile = filedialog.askopenfile( parent=self.root, mode="r", title="Select a BASIC file to load", filetypes=self.FILETYPES, initialdir=self.current_dir, ) if infile is not None: content = infile.read() infile.close() content = content.strip() listing_ascii = content.splitlines() self.set_content(listing_ascii) self.setup_filepath(infile.name) def command_save_file(self): outfile = filedialog.asksaveasfile( parent=self.root, mode="w", filetypes=self.FILETYPES, defaultextension=self.DEFAULTEXTENSION, initialdir=self.current_dir, ) if outfile is not None: content = self.get_content() outfile.write(content) outfile.close() self.setup_filepath(outfile.name) def debug_display_tokens(self): content = self.get_content() self.token_window = TokenWindow(self.cfg, self.root) self.token_window.display_listing(content) def renumber_listing(self): # save text cursor and scroll position self.text.save_position() # renumer the content content = self.get_content() content = self.machine_api.renum_ascii_listing(content) self.set_content(content) # restore text cursor and scroll position self.text.restore_position() def reformat_listing(self): # save text cursor and scroll position self.text.save_position() # renumer the content content = self.get_content() content = self.machine_api.reformat_ascii_listing(content) self.set_content(content) # restore text cursor and scroll position self.text.restore_position() def get_content(self): content = self.text.get("1.0", tkinter.END) content = content.strip() return content def set_content(self, listing_ascii): # self.text.config(state=Tkinter.NORMAL) self.text.delete("1.0", tkinter.END) log.critical("insert listing:") if not isinstance(listing_ascii, (list, tuple)): listing_ascii = listing_ascii.splitlines() for line in listing_ascii: line = "%s\n" % line # use os.sep ?!? log.debug("\t%s", repr(line)) self.text.insert(tkinter.END, line) # self.text.config(state=Tkinter.DISABLED) self.text.mark_set(tkinter.INSERT, '1.0') # Set cursor at start self.focus_text() self.highlight_currentline.update(force=True) self.highlighting.update(force=True) def focus_text(self): if not self.standalone_run: # see: # http://www.python-forum.de/viewtopic.php?f=18&t=34643 (de) # http://bugs.python.org/issue11571 # http://bugs.python.org/issue9384 self.root.attributes('-topmost', True) self.root.attributes('-topmost', False) self.root.focus_force() self.root.lift(aboveThis=self.gui.root) self.text.focus() def mainloop(self): """ for standalone usage """ self.root.mainloop()
class EditorWindow(object): FILETYPES = [ # For filedialog ("BASIC Listings", "*.bas", "TEXT"), ("Text files", "*.txt", "TEXT"), ("All files", "*"), ] DEFAULTEXTENSION = "*.bas" def __init__(self, cfg, gui=None): self.cfg = cfg if gui is None: self.standalone_run = True else: self.gui = gui self.standalone_run = False self.machine_api = self.cfg.machine_api if self.standalone_run: self.root = tkinter.Tk(className="EDITOR") self.root.geometry("+%d+%d" % (self.root.winfo_screenwidth() * 0.1, self.root.winfo_screenheight() * 0.1)) else: # As sub window in DragonPy Emulator self.root = tkinter.Toplevel(self.gui.root) self.root.geometry("+%d+%d" % ( self.gui.root.winfo_rootx() + self.gui.root.winfo_width(), self.gui.root.winfo_y() # FIXME: Different on linux. )) self.root.columnconfigure(0, weight=1) self.root.rowconfigure(0, weight=1) self.base_title = "%s - BASIC Editor" % self.cfg.MACHINE_NAME self.root.title(self.base_title) self.text = ScrolledText(master=self.root, height=30, width=80) self.text.config( background="#ffffff", foreground="#000000", highlightthickness=0, font=('courier', 11), ) self.text.grid(row=0, column=0, sticky=tkinter.NSEW) self.highlighting = TkTextHighlighting(self) self.highlight_currentline = TkTextHighlightCurrentLine(self) #self.auto_shift = True # use invert shift for letters? self.menubar = tkinter.Menu(self.root) filemenu = tkinter.Menu(self.menubar, tearoff=0) filemenu.add_command(label="Load", command=self.command_load_file) filemenu.add_command(label="Save", command=self.command_save_file) if self.standalone_run: filemenu.add_command(label="Exit", command=self.root.quit) self.menubar.add_cascade(label="File", menu=filemenu) editmenu = tkinter.Menu(self.menubar, tearoff=0) editmenu.add_command(label="renum", command=self.renumber_listing) editmenu.add_command(label="reformat", command=self.reformat_listing) editmenu.add_command(label="display tokens", command=self.debug_display_tokens) self.menubar.add_cascade(label="tools", menu=editmenu) # help menu helpmenu = tkinter.Menu(self.menubar, tearoff=0) # helpmenu.add_command(label="help", command=self.menu_event_help) # helpmenu.add_command(label="about", command=self.menu_event_about) self.menubar.add_cascade(label="help", menu=helpmenu) # startup directory for file open/save self.current_dir = os.path.abspath( os.path.join( os.path.dirname(dragonlib.__file__), "..", "BASIC examples", )) self.set_status_bar( ) # Create widget, add bindings and after_idle() update self.text.bind("<Key>", self.event_text_key) # self.text.bind("<space>", self.event_syntax_check) # display the menu self.root.config(menu=self.menubar) self.root.update() ########################################################################### # Status bar def set_status_bar(self): self.status_bar = MultiStatusBar(self.root) if sys.platform == "darwin": # Insert some padding to avoid obscuring some of the statusbar # by the resize widget. self.status_bar.set_label('_padding1', ' ', side=tkinter.RIGHT) self.status_bar.grid(row=1, column=0) self.text.bind("<<set-line-and-column>>", self.set_line_and_column) self.text.event_add("<<set-line-and-column>>", "<KeyRelease>", "<ButtonRelease>") self.text.after_idle(self.set_line_and_column) def set_line_and_column(self, event=None): line, column = self.text.index(tkinter.INSERT).split('.') self.status_bar.set_label('column', 'Column: %s' % column) self.status_bar.set_label('line', 'Line: %s' % line) ########################################################################### def event_text_key(self, event): """ So a "invert shift" for user inputs: Convert all lowercase letters to uppercase and vice versa. """ char = event.char if not char or char not in string.ascii_letters: # ignore all non letter inputs return converted_char = invert_shift(char) log.debug("convert keycode %s - char %s to %s", event.keycode, repr(char), converted_char) # self.text.delete(Tkinter.INSERT + "-1c") # Delete last input char self.text.insert(tkinter.INSERT, converted_char) # Insert converted char return "break" # def event_syntax_check(self, event): # index = self.text.search(r'\s', "insert", backwards=True, regexp=True) # if index == "": # index ="1.0" # else: # index = self.text.index("%s+1c" % index) # word = self.text.get(index, "insert") # log.critical("inserted word: %r", word) # print self.machine_api.parse_ascii_listing(word) def setup_filepath(self, filepath): log.critical(filepath) self.filepath = os.path.normpath(os.path.abspath(filepath)) self.current_dir, self.filename = os.path.split(self.filepath) self.root.title("%s - %s" % (self.base_title, repr(self.filename))) def command_load_file(self): infile = filedialog.askopenfile( parent=self.root, mode="r", title="Select a BASIC file to load", filetypes=self.FILETYPES, initialdir=self.current_dir, ) if infile is not None: content = infile.read() infile.close() content = content.strip() listing_ascii = content.splitlines() self.set_content(listing_ascii) self.setup_filepath(infile.name) def command_save_file(self): outfile = filedialog.asksaveasfile( parent=self.root, mode="w", filetypes=self.FILETYPES, defaultextension=self.DEFAULTEXTENSION, initialdir=self.current_dir, ) if outfile is not None: content = self.get_content() outfile.write(content) outfile.close() self.setup_filepath(outfile.name) def debug_display_tokens(self): content = self.get_content() self.token_window = TokenWindow(self.cfg, self.root) self.token_window.display_listing(content) def renumber_listing(self): # save text cursor and scroll position self.text.save_position() # renumer the content content = self.get_content() content = self.machine_api.renum_ascii_listing(content) self.set_content(content) # restore text cursor and scroll position self.text.restore_position() def reformat_listing(self): # save text cursor and scroll position self.text.save_position() # renumer the content content = self.get_content() content = self.machine_api.reformat_ascii_listing(content) self.set_content(content) # restore text cursor and scroll position self.text.restore_position() def get_content(self): content = self.text.get("1.0", tkinter.END) content = content.strip() return content def set_content(self, listing_ascii): # self.text.config(state=Tkinter.NORMAL) self.text.delete("1.0", tkinter.END) log.critical("insert listing:") if not isinstance(listing_ascii, (list, tuple)): listing_ascii = listing_ascii.splitlines() for line in listing_ascii: line = "%s\n" % line # use os.sep ?!? log.debug("\t%s", repr(line)) self.text.insert(tkinter.END, line) # self.text.config(state=Tkinter.DISABLED) self.text.mark_set(tkinter.INSERT, '1.0') # Set cursor at start self.focus_text() self.highlight_currentline.update(force=True) self.highlighting.update(force=True) def focus_text(self): if not self.standalone_run: # see: # http://www.python-forum.de/viewtopic.php?f=18&t=34643 (de) # http://bugs.python.org/issue11571 # http://bugs.python.org/issue9384 self.root.attributes('-topmost', True) self.root.attributes('-topmost', False) self.root.focus_force() self.root.lift(aboveThis=self.gui.root) self.text.focus() def mainloop(self): """ for standalone usage """ self.root.mainloop()