class VennGUI(object): def __init__(self, argv): """ :param argv: arguments for running the program Usage: venn_gui.py <-f filename> """ # Arguments parser = argparse.ArgumentParser() parser.add_argument("-f", "--filename", help="Read premises from local file", type=str) parser.add_argument("-e", "--eval", help="The argument being validated", type=str) parser.add_argument("--no_window", help="Get the result immediately without" " showing the interactive window " "(Need -f argument)", action="store_true") parser.add_argument("--export", help="Export the result to an image file " "(Need -f and --no_window argument)", type=str) self.args = parser.parse_args(argv[1:]) # Basic components self.filename = "" self.filepath = "" self.collect = None self.root = None self.fig = None self.msg_text = None self.msg_label = None self.premises_box = None self.show_btn = None self.is_possible_highlight = None self.show_exp_in_diagram = None self.eval_box = None if not self.args.no_window: self.set_up() # =============================================================================== # Basic GUI related operations # =============================================================================== def run(self): """ Start the GUI window """ if self.args.no_window: s = ExpressionSet() if self.args.filename: with open(self.args.filename, 'r', encoding='utf8') as f: premises = f.read() s.add_premises(premises) s.parse_premises() s.display_diagram() if self.args.eval: ret = s.evaluate(Expression(self.args.eval), show=True) if self.args.export: plt.savefig(self.args.export) else: plt.show(block=True) else: print("ERROR: No premises found.", file=sys.stderr) else: if self.args.filename: self.filepath = self.args.filename self.load(new_file=False) if self.args.eval: self.eval_box.delete(0, tk.END) self.eval_box.insert(0, self.args.eval) self.evaluate_exp() self.root.update() self.root.deiconify() self.root.mainloop() def clear(self): """ Empty the diagram, premises box and evaluation box """ self.premises_box.delete('1.0', tk.END) self.msg_text.set("") self.eval_box.delete(0, tk.END) plt.clf() def quit(self): """ Quit the program """ if self.premises_box.edit_modified(): save_before_exit = tk.messagebox.askyesnocancel( "Venn Diagram Interpreter", "Do you want to save the changes?") if save_before_exit is None: return if save_before_exit: self.save() self.root.quit() # =============================================================================== # GUI preparation # =============================================================================== def set_up(self): """ Set up all GUI components """ # Set up the venn self.collect = ExpressionSet() # Set up GUI self.root = tk.Tk() self.root.title("Venn Diagram Interpreter") self.root.withdraw() tk.Grid.rowconfigure(self.root, 0, weight=1) tk.Grid.columnconfigure(self.root, 0, weight=1) self.fig = plt.figure(1) canvas = FigureCanvasTkAgg(self.fig, master=self.root) plot_widget = canvas.get_tk_widget() # The main panel plot_widget.grid(row=0, column=0, columnspan=2, sticky=tk.N + tk.S + tk.E + tk.W) # ---------------------------- Premises -------------------------------- # Message self.msg_text = tk.StringVar() self.msg_label = tk.Label(self.root, textvariable=self.msg_text) self.msg_label.grid(row=1, sticky="w", columnspan=2) # Premises input box tk.Label(self.root, text="Sytnax: (Use quote or a newline to separate)").grid( row=2, sticky="w", columnspan=2) tk.Label(self.root, text="\tSet (total 3 at most): The name of the set, " "use a quote(\"\") if it contains multiple words").grid( row=3, sticky="w", columnspan=2) tk.Label(self.root, text="\tExpression: <All/Some> A's are <(not)> B's").grid( row=4, sticky="w", columnspan=2) tk.Label(self.root, text="Enter the premises:").grid(row=6, sticky="w", columnspan=2) PREMISE_BOX_HEIGHT = 4 FIRST_ROW_OF_PREMISE_BOX = 3 + PREMISE_BOX_HEIGHT self.premises_box = ScrolledText(self.root, height=PREMISE_BOX_HEIGHT) self.premises_box.grid(row=FIRST_ROW_OF_PREMISE_BOX, column=0, sticky="nsew", rowspan=PREMISE_BOX_HEIGHT) def premises_modified(event): curr_title = self.root.title() if self.premises_box.edit_modified(): if not curr_title.startswith("*"): self.root.title("*" + curr_title) else: curr_title = curr_title[1:] if curr_title[ 0] == '*' else curr_title self.root.title(curr_title) self.premises_box.bind("<<Modified>>", premises_modified) def focus_next_widget(event): event.widget.tk_focusNext().focus() return "break" self.premises_box.bind("<Tab>", focus_next_widget) self.show_btn = tk.Button(self.root, text="Show diagram", command=self.show_diagram) self.show_btn.grid(row=FIRST_ROW_OF_PREMISE_BOX + 1, column=1, sticky=tk.W + tk.E, rowspan=1) self.show_btn.bind("<Return>", lambda e: self.show_btn.invoke()) self.premises_box.bind("<Control-Return>", lambda e: self.show_btn.invoke()) clear_btn = tk.Button(self.root, text="Clear", command=self.clear) clear_btn.grid(row=FIRST_ROW_OF_PREMISE_BOX + 2, column=1, sticky=tk.W + tk.E, rowspan=1) clear_btn.bind("<Return>", lambda e: clear_btn.invoke()) self.is_possible_highlight = tk.IntVar() poss_check = tk.Checkbutton( self.root, text="Use color shadow to highlight \"Some\" statements.", variable=self.is_possible_highlight) poss_check.grid(row=FIRST_ROW_OF_PREMISE_BOX + PREMISE_BOX_HEIGHT, column=0) poss_check.toggle() self.show_exp_in_diagram = tk.IntVar() show_exp_check = tk.Checkbutton( self.root, text="Display the argument in the diagram", variable=self.show_exp_in_diagram) show_exp_check.grid(row=FIRST_ROW_OF_PREMISE_BOX + PREMISE_BOX_HEIGHT + 1, column=0) show_exp_check.toggle() # Input box tk.Label(self.root, text="Enter the expression you want to evaluate:").grid( row=FIRST_ROW_OF_PREMISE_BOX + PREMISE_BOX_HEIGHT + 2, sticky="w", columnspan=2) self.eval_box = tk.Entry(self.root) self.eval_box.grid(row=FIRST_ROW_OF_PREMISE_BOX + PREMISE_BOX_HEIGHT + 3, column=0, sticky="ew") self.eval_box.bind("<Return>", lambda e: self.evaluate_exp()) eval_btn = tk.Button(self.root, text="Evaluate", command=self.evaluate_exp) eval_btn.grid(row=FIRST_ROW_OF_PREMISE_BOX + PREMISE_BOX_HEIGHT + 3, column=1) eval_btn.bind("<Return>", lambda e: eval_btn.invoke()) # Menu bar menubar = tk.Menu(self.root) filemenu = tk.Menu(menubar, tearoff=0) filemenu.add_command(label="\tNew ", accelerator=" Ctrl+N", command=self.new_file) self.root.bind('<Control-n>', lambda e: self.new_file()) filemenu.add_command(label="\tOpen... ", accelerator=" Ctrl+O", command=self.load) self.root.bind('<Control-o>', lambda e: self.load()) filemenu.add_command(label="\tSave ", accelerator=" Ctrl+S", command=self.save) self.root.bind('<Control-s>', lambda e: self.save()) filemenu.add_command(label="\tSave As... ", accelerator="Ctrl+Shift+S", command=self.save_as) self.root.bind('<Control-Shift-s>', lambda e: self.save_as()) filemenu.add_separator() filemenu.add_command(label="\tExit", command=quit) menubar.add_cascade(label="File", menu=filemenu) editmenu = tk.Menu(menubar, tearoff=0) editmenu.add_command( label="\tUndo", accelerator="Ctrl+Z", command=lambda: self.root.focus_get().event_generate('<<Undo>>')) editmenu.add_separator() editmenu.add_command( label="\tCut", accelerator="Ctrl+X", command=lambda: self.root.focus_get().event_generate('<<Cut>>')) editmenu.add_command( label="\tCopy", accelerator="Ctrl+C", command=lambda: self.root.focus_get().event_generate('<<Copy>>')) editmenu.add_command( label="\tPaste", accelerator="Ctrl+V", command=lambda: self.root.focus_get().event_generate('<<Paste>>')) editmenu.add_separator() editmenu.add_command(label="\tSelect All", accelerator="Ctrl+A", command=lambda: self.root.focus_get(). event_generate('<<SelectAll>>')) menubar.add_cascade(label="Edit", menu=editmenu) helpmenu = tk.Menu(menubar, tearoff=0) helpmenu.add_command(label="Help Index") helpmenu.add_command(label="About...") menubar.add_cascade(label="Help", menu=helpmenu) self.root.config(menu=menubar) self.root.protocol("WM_DELETE_WINDOW", quit) # =============================================================================== # Diagram display operations # =============================================================================== # "Show" button def show_diagram(self): """ Displays the diagram with existing premises """ plt.clf() self.msg_text.set("") # Create the ExpressionSet object self.collect = ExpressionSet() if self.premises_box.get("1.0", tk.END) == "": return # Add all premises try: self.collect.add_premises( self.premises_box.get("1.0", tk.END).replace(';', '\n')) except NameError as e: self.msg_text.set(str(e)) self.msg_label.configure(foreground="red") except TypeError as e: print(e, file=sys.stderr) pass except ValueError as e: self.msg_text.set(str(e)) self.msg_label.configure(foreground="red") return except SyntaxError as e: self.msg_text.set(str(e)) self.msg_label.configure(foreground="red") return if self.collect.empty() or len(self.collect) == 1: return # Parse premises try: self.collect.parse_premises() except ValueError as e: self.msg_text.set(str(e)) self.msg_label.configure(foreground="red") return self.collect.display_diagram( highlight_some=bool(self.is_possible_highlight.get())) if not self.args.no_window: self.fig.canvas.flush_events() self.fig.canvas.draw() # "Update" button def evaluate_exp(self): """ Evaluate an argument and displays the result """ self.show_diagram() if self.collect.empty(): self.msg_text.set("The diagram is empty!") self.msg_label.configure(foreground="red") return if self.eval_box.get() == "": return try: ret, must, reason = self.collect.evaluate( Expression(self.eval_box.get()), show=True, show_exp=self.show_exp_in_diagram.get()) self.msg_text.set(reason) if ret: if must: self.msg_label.configure(foreground="green") else: self.msg_label.configure(foreground="yellowgreen") else: if must: self.msg_label.configure(foreground="red") else: self.msg_label.configure(foreground="darkorange") if self.args.no_window: plt.show(block=True) else: self.fig.canvas.flush_events() self.fig.canvas.draw() except SyntaxError as e: self.msg_text.set(str(e)) self.msg_label.configure(foreground="red") # =============================================================================== # Local file operations # =============================================================================== filetypes = (("Venn Diagram file (*.venn)", "*.venn"), ("Normal text file (*.txt)", "*.txt"), ("All types (*.*)", "*.*")) def load(self, new_file=True): """ Load premises from local file """ if new_file: self.filepath = tk.filedialog.askopenfilename( defaultextension=".venn", filetypes=VennGUI.filetypes) if self.filepath == "": return if not os.path.exists(self.filepath): print("ERROR File \"{}\" does not exist.".format(self.filepath), file=sys.stderr) return self.filename = os.path.basename(self.filepath) with open(self.filepath, 'r', encoding='utf8') as f: text = f.read() self.premises_box.delete('1.0', tk.END) self.premises_box.insert(tk.INSERT, text) self.premises_box.edit_modified(False) self.show_btn.invoke() self.msg_text.set("Successfully load from file \"{}\"".format( self.filename)) self.msg_label.configure(foreground="green") self.root.title(self.filename + " - Venn Diagram Interpreter") def save_as(self, new_file=True): """ Save premises to local file """ if new_file or self.filepath == "" or self.filename == "": self.filepath = tk.filedialog.asksaveasfilename( defaultextension=".venn", filetypes=VennGUI.filetypes) if self.filepath == "": return self.filename = os.path.basename(self.filepath) with open(self.filepath, "w", encoding='utf8') as text_file: text_file.write(self.premises_box.get("1.0", tk.END)) self.msg_text.set("Successfully saved file \"{}\"".format( self.filename)) self.msg_label.configure(foreground="green") self.root.title(self.filename + " - Venn Diagram Interpreter") def save(self): """ Save premises to current file """ if self.filename == "": self.save_as() self.save_as(new_file=False) def new_file(self): """ Create a new file """ if self.premises_box.edit_modified(): save_before_new = tk.messagebox.askyesnocancel( "Venn Diagram Interpreter", "Do you want to save the changes?") if save_before_new is None: return if save_before_new: self.save() self.clear() self.premises_box.edit_modified(False) self.filename = "" self.filepath = "" self.root.title("Venn Diagram Interpreter")
class OptimizerMainWindow(): ''' classdocs ''' #TODO: change that name def reactToClick(self, event): a = AddRestrictionDialog(self) def __init__(self, optimizer): # always have a reference to model/controller self.optimizer = optimizer # setup main GUI and make stretchable self.guiRoot = Tk() self.guiRoot.title("OPTIMIZR") self.guiRoot.columnconfigure(1, weight=1) self.guiRoot.rowconfigure(0, weight=1) # left (settings) and right (sequences) part self.frameLeft = Frame(self.guiRoot) self.frameLeft.grid(row=0, column=0, sticky=W+E+N+S) self.frameLeft.columnconfigure(0, weight=1) self.frameRight = Frame(self.guiRoot) self.frameRight.grid(row=0, column=1, sticky=W+E+N+S) self.frameRight.columnconfigure(0, weight=1) self.frameRight.rowconfigure(0, weight=1) self.frameRight.rowconfigure(1, weight=1) self.frameSpeciesControll = LabelFrame(self.frameLeft, text="Species", pady=10, padx=10) self.frameSpeciesControll.columnconfigure(1, weight=1) self.frameOptimizationControll = LabelFrame(self.frameLeft, text="Optimization", pady=10, padx=10) self.frameRestrictionControll = LabelFrame(self.frameLeft, text="Restriction Enzymes", pady=10, padx=10) self.frameSpeciesControll.grid(row=0, column=0, sticky=W+E, padx=10, pady=10) self.frameOptimizationControll.grid(row=1, column=0, sticky=W+E, padx=10, pady=10) self.frameRestrictionControll.grid(row=2, column=0, sticky=W+E, padx=10, pady=10) # Species Controll Label(self.frameSpeciesControll, text="Source:").grid(row=0, column=0) Label(self.frameSpeciesControll, text="Target:").grid(row=1, column=0) self.comboSourceSpecies = Combobox(self.frameSpeciesControll, state="readonly") self.comboSourceSpecies.grid(row=0, column=1, pady=5, sticky="ew") self.comboTargetSpecies = Combobox(self.frameSpeciesControll, state="readonly") self.comboTargetSpecies.grid(row=1, column=1, pady=5, sticky="we") self.buttonSpeciesList = Button(self.frameSpeciesControll, text="Edit Species List") self.buttonSpeciesList.grid(row=2, column=1, pady=5, sticky="e") self.comboSourceSpecies.bind("<<ComboboxSelected>>", self.actionOptimizerSettingsChanged) self.comboTargetSpecies.bind("<<ComboboxSelected>>", self.actionOptimizerSettingsChanged) # Optimization Controll Label(self.frameOptimizationControll, text="Optimization Strategy:").grid(row=0, column=0) self.comboOptimizationStrategy = Combobox(self.frameOptimizationControll, state="readonly") self.comboOptimizationStrategy.grid(row=0, column=1) self.comboOptimizationStrategy["values"] = self.optimizer.possibleOptimizationStrategies self.comboOptimizationStrategy.bind("<<ComboboxSelected>>", self.actionOptimizerSettingsChanged) # Restriction Enzymes self.listRestriction = Listbox(self.frameRestrictionControll) self.listRestriction.grid(row=0, column=0, columnspan=3, pady=5, sticky=W+E) self.frameRestrictionControll.columnconfigure(0, weight=1) self.buttonRestricionAdd = Button(self.frameRestrictionControll, text=" + ") self.buttonRestricionDel = Button(self.frameRestrictionControll, text=" - ") self.buttonRestricionAdd.grid(row=1, column=1, padx=5) self.buttonRestricionDel.grid(row=1, column=2, padx=5) # Source Sequence Frame self.frameSourceSequence = LabelFrame(self.frameRight, text="Source Sequence", padx=10, pady=10) self.frameResultSequence = LabelFrame(self.frameRight, text="Result Sequence", padx=10, pady=10) self.frameSourceSequence.grid(row=0, column=0, sticky="wens", padx=10, pady=10) self.frameResultSequence.grid(row=1, column=0, sticky="wens", padx=10, pady=10) self.buttonSourceLoad = Button(self.frameSourceSequence, text=" Load ") self.textSourceSeq = ScrolledText(self.frameSourceSequence, height=10) self.buttonSourceLoad.grid(row=0, column=1, sticky="e", pady=5) self.textSourceSeq.grid(row=1, column=0, columnspan=2, sticky="wens") self.frameSourceSequence.columnconfigure(0, weight=1) self.frameSourceSequence.rowconfigure(1, weight=1) self.textSourceSeq.frame.columnconfigure(1, weight=1) self.textSourceSeq.frame.rowconfigure(0, weight=1) self.buttonOptimize = Button(self.frameResultSequence, text=" OPTIMIZE! ") self.buttonOptimize.bind("<ButtonRelease>", self.actionOptimize) self.buttonRemoveRestriction = Button(self.frameResultSequence, text=" RESTRICTION-B-GONE! ") self.buttonRemoveRestriction.bind("<ButtonRelease>", self.actionRemoveRestricion) self.buttonSaveResult = Button(self.frameResultSequence, text=" Save ") self.textResultSequence = ScrolledText(self.frameResultSequence, height=10) self.buttonOptimize.grid(column=0, row=0, pady=5, sticky="w") self.buttonRemoveRestriction.grid(column=1, row=0, pady=5, padx=10, sticky="w") self.textResultSequence.grid(row=1, column=0, columnspan=4, sticky="wens") self.buttonSaveResult.grid(row=2, column=3, pady=5, sticky="e") self.frameResultSequence.columnconfigure(2, weight=1) self.frameResultSequence.rowconfigure(1, weight=1) self.textResultSequence.frame.columnconfigure(1, weight=1) self.textResultSequence.frame.rowconfigure(0, weight=1) self.textSourceSeq.bind("<<Modified>>", self.actionSequenceModified) self.textResultSequence.bind("<<Modified>>", self.actionSequenceModified) #generate color tags for textboxes for i in range(101): #green for normal codons (r,g,b) = colorsys.hsv_to_rgb(210/360, i/100, 1.0) colorHex = "#%02x%02x%02x" % (int(r*255), int(g*255), int(b*255)) self.textSourceSeq.tag_config("normal"+str(i), background=colorHex) self.textResultSequence.tag_config("normal"+str(i), background=colorHex) #red for codons with restriction sites (r,g,b) = colorsys.hsv_to_rgb(5/360, i/100, 1.0) colorHex = "#%02x%02x%02x" % (int(r*255), int(g*255), int(b*255)) self.textSourceSeq.tag_config("restrict"+str(i), background=colorHex) self.textResultSequence.tag_config("restrict"+str(i), background=colorHex) # Set (minimum + max) Window size self.guiRoot.update() self.guiRoot.minsize(self.guiRoot.winfo_width(), self.guiRoot.winfo_height()) self.buttonRestricionAdd.bind("<ButtonRelease>", self.reactToClick) self.buttonRestricionDel.bind("<ButtonRelease>", self.actionRestrictionEnzymeDelete) self.buttonSpeciesList.bind("<ButtonRelease>", self.actionEditSpeciesButton) self.buttonSourceLoad.bind("<ButtonRelease>", self.actionLoadSequence) self.buttonSaveResult.bind("<ButtonRelease>", self.actionSaveSequence) # TEST # self.listRestriction.insert("end", "EcoRI") # self.listRestriction.insert("end", "BamHI") # # dummy event to manually trigger update self.guiRoot.bind("<<Update>>", self.actionUpdate) self.actionUpdate(None) self.guiRoot.mainloop() def actionRestrictionEnzymeDelete(self, event): try: selectedEnzyme = self.listRestriction.selection_get() self.optimizer.restrictionEnzymeList.remove(selectedEnzyme) self.guiRoot.event_generate("<<Update>>") except tkinter.TclError : # no selection pass def actionUpdate(self, event): # print("update called") # clear list of restriction enzymes self.listRestriction.delete(0, "end") for r in self.optimizer.restrictionEnzymeList: self.listRestriction.insert("end", r) self.comboSourceSpecies.delete(0, "end") self.comboTargetSpecies.delete(0, "end") speciesValues = list() for (taxid, name) in self.optimizer.speciesList: speciesValues.append(taxid + ": " + name) self.comboSourceSpecies["values"] = speciesValues self.comboTargetSpecies["values"] = speciesValues if self.comboSourceSpecies.get() not in speciesValues: self.comboSourceSpecies.set("") if self.comboTargetSpecies.get() not in speciesValues: self.comboTargetSpecies.set("") self.textSourceSeq.edit_modified(True) self.textResultSequence.edit_modified(True) self.optimizer.saveConfig("config.ini") def actionEditSpeciesButton(self, event): speciesListDialog = SpeciesListDialog(self) def actionOptimizerSettingsChanged(self, event=None): # print("Something happened") strategy = self.comboOptimizationStrategy.get() sourceString = self.comboSourceSpecies.get() targetString = self.comboTargetSpecies.get() if not (strategy and sourceString and targetString): return sourceTaxid = sourceString.split(":")[0] targetTaxid = targetString.split(":")[0] self.optimizer.setOptimizer(sourceTaxid, targetTaxid, strategy) self.textSourceSeq.edit_modified(True) self.textResultSequence.edit_modified(True) # self.optimizer.testPrint() def actionOptimize(self, event=None): self.optimizer.runOptimization() self.textSourceSeq.edit_modified(True) self.textResultSequence.edit_modified(True) def actionRemoveRestricion(self, event=None): self.optimizer.runRestricionRemoval() self.textSourceSeq.edit_modified(True) self.textResultSequence.edit_modified(True) def actionSequenceModified(self, event=None): # necessary if, otherwise -> infinite loop if self.textSourceSeq.edit_modified(): seq = self.textSourceSeq.get("1.0", "end").strip() seq = stripCharsNotInList(seq.upper(), ['A', 'C', 'G', 'T']) self.optimizer.setSourceSeq(seq) oldInsert = self.textSourceSeq.index("insert") self.textSourceSeq.delete("1.0", "end") sourceCodons = self.optimizer.getCodonsForPrint(True) if not sourceCodons: self.textSourceSeq.insert("end", self.optimizer.sourceSequence) else: for (co, sc, r) in sourceCodons: if sc: if not r: self.textSourceSeq.insert("end", co, "normal"+str(int(sc*100))) #print("normal"+str(int(sc*100))) else: self.textSourceSeq.insert("end", co, "restrict"+str(int(sc*100))) else: # remainder without color self.textSourceSeq.insert("end", co) self.textSourceSeq.mark_set("insert", oldInsert) # reset the modified status at the very end self.textSourceSeq.edit_modified(False) if self.textResultSequence.edit_modified(): seq = self.textResultSequence.get("1.0", "end").strip() # self.optimizer.setOptimizedSeq(seq) oldInsert = self.textResultSequence.index("insert") self.textResultSequence.delete("1.0", "end") targetCodons = self.optimizer.getCodonsForPrint(False) if not targetCodons: self.textSourceSeq.insert("end", self.optimizer.optimizedSequence) else: for (co, sc, r) in targetCodons: if sc: if not r: self.textResultSequence.insert("end", co, "normal"+str(int(sc*100))) #print("normal"+str(int(sc*100))) else: self.textResultSequence.insert("end", co, "restrict"+str(int(sc*100))) else: # remainder without color self.textResultSequence.insert("end", co) self.textSourceSeq.mark_set("insert", oldInsert) self.textResultSequence.edit_modified(False) def actionLoadSequence(self, event=None): filename = tkinter.filedialog.askopenfilename() if filename: seq = sequenceIO.readFile(filename) self.textSourceSeq.delete("1.0", "end") self.textSourceSeq.insert("end", seq) self.textSourceSeq.edit_modified(True) def actionSaveSequence(self, event=None): filename = tkinter.filedialog.asksaveasfilename() if filename: # print("file is " + filename) with open(filename, mode='w') as fd: fd.write(self.optimizer.optimizedSequence)
class Gui(): def __init__(self): self.file_path = None self.simulation_data = None # A ScriptOutput object self.root = tk.Tk() self.root.protocol("WM_DELETE_WINDOW", self.file_quit) self.set_title() self.scriptLabel = None self.scriptField = None self._create_widgets() self._assign_accelerators() self.root.mainloop() def _create_widgets(self): # The frame containing the widgets frame = tk.Frame(self.root) # The menu bar menu_bar = tk.Menu(self.root, tearoff=0) # The File menu file_menu = tk.Menu( menu_bar, tearoff=0) # tearoff = 0: can't be seperated from window file_menu.add_command(label="New", underline=0, command=self.file_new) # , accelerator="Ctrl+N") file_menu.add_command( label="Open...", underline=0, command=self.file_open) # , accelerator="Ctrl+O") file_menu.add_command( label="Save", underline=0, command=self.file_save) # , accelerator="Ctrl+S") file_menu.add_command(label="Save As...", underline=1, command=self.file_save_as) file_menu.add_separator() file_menu.add_command(label="Exit", underline=1, command=self.file_quit) menu_bar.add_cascade(label="File", underline=0, menu=file_menu) # The Run menu run_menu = tk.Menu( menu_bar, tearoff=0) # tearoff = 0: can't be seperated from window run_menu.add_command(label="Simulate and Plot", underline=0, command=self.simulate, accelerator="F5") run_menu.add_command(label="Plot", underline=0, command=self.plot) menu_bar.add_cascade(label="Run", underline=0, menu=run_menu) # The Edit menu edit_menu = tk.Menu( menu_bar, tearoff=0) # tearoff = 0: can't be seperated from window edit_menu.add_command(label="Undo", underline=0, command=self.undo, accelerator="Ctrl+Z") edit_menu.add_command(label="Redo", underline=0, command=self.redo, accelerator="Ctrl+Y") menu_bar.add_cascade(label="Edit", underline=0, menu=edit_menu) self.root.config(menu=menu_bar) # The label lbltxt = "Place your script in the box below or open a text file" # lbltxt = "Simulate: F5, Open: Ctrl+O, Save: Ctrl+S, New: Ctrl+N" scriptLabel = tk.Label(frame, text=lbltxt) scriptLabel.pack(side="top", anchor="w") # The Text widget self.scriptField = ScrolledText(frame) self.scriptField.pack(side="top", fill=BOTH, expand=YES) self.scriptField.config(undo=True) self.scriptField.focus_set() # self.scriptField.config( # borderwidth=0, # font="{Lucida Sans Typewriter} 12", # foreground="green", # background="black", # insertbackground="white", # cursor # selectforeground="green", # selection # selectbackground="#008000", # wrap=tk.WORD, # use word wrapping # width=64, # undo=True, # Tk 8.4 # ) # The Quit button # quitButton = tk.Button(frame, text="Quit", command=self.quit) # quitButton.pack(side="right") # The Close All button closefigButton = tk.Button(frame, text="Close All Figures", command=self.close_figs) closefigButton.pack(side="right") # The Simulate button simButton = tk.Button(frame, text="Simulate and Plot", command=self.simulate) simButton.pack(side="left") # The Plot button plotButton = tk.Button(frame, text="Plot", command=self.plot) plotButton.pack(side="left") frame.pack(fill=BOTH, expand=YES) def simulate(self, event=None): try: script = self.scriptField.get("1.0", "end-1c") script_obj = LsScript.LsScript(script) self.simulation_data = script_obj.run() script_obj.postproc(self.simulation_data) except Exception as ex: self.handle_exception(ex) def plot(self): try: if self.simulation_data is None: raise LsGuiException("No simulation data to plot.") script = self.scriptField.get("1.0", "end-1c") script_obj = LsScript.LsScript(script) script_obj.postproc(self.simulation_data) except Exception as ex: self.handle_exception(ex) def close_figs(self): plt.close("all") def handle_exception(self, ex): # err_msg = ex.args[0] err_msg = str(ex) # if len(ex.args) == 2: # err_msg = "{0} {1}".format(err_msg, ex.args[1]) # # err_msg = err_msg + ex.args[1] messagebox.showerror("Error", err_msg) print(traceback.format_exc()) # def file_open(self): # filename = filedialog.askopenfilename() # # filename = "C:/Python/Python36-32/_Markus/scriptexempel2.txt" # XXX # file = open(filename, "r") # self.scriptField.delete("1.0", "end-1c") # self.scriptField.insert("1.0", file.read()) # self.scriptField.mark_set("insert", "1.0") # file.close() # Make sure you close the file when done def save_changes(self): if self.scriptField.edit_modified(): msg = "This document has been modified. Do you want to save changes?" save_changes = messagebox.askyesnocancel("Save?", msg) if save_changes is None: # Cancel return False elif save_changes is True: # Yes self.file_save() return True def file_new(self, event=None): save_changes = self.save_changes() if not save_changes: return self.scriptField.delete(1.0, "end") self.scriptField.edit_modified(False) self.scriptField.edit_reset() self.file_path = None self.set_title() def file_open(self, event=None): # , filepath=None): save_changes = self.save_changes() if not save_changes: return # XXX initialdir = '.' if os.path.isdir('/home/markus/Dropbox/'): initialdir = '/home/markus/Dropbox/LearningSimulator/Scripts' filepath = filedialog.askopenfilename(filetypes=FILETYPES, initialdir=initialdir) if filepath is not None and len(filepath) != 0: with open(filepath, encoding="utf-8") as f: file_contents = f.read() # Set current text to file contents self.scriptField.delete(1.0, "end") self.scriptField.insert(1.0, file_contents) self.scriptField.edit_modified(False) self.scriptField.mark_set("insert", "1.0") self.file_path = filepath self.set_title() def file_save(self, event=None): self.file_save_as(filepath=self.file_path) def file_save_as(self, filepath=None, event=None): if filepath is None: filepath = filedialog.asksaveasfilename(filetypes=FILETYPES) if len( filepath ) == 0: # Empty tuple or empty string is returned if cancelled return # "cancelled" try: with open(filepath, 'wb') as f: text = self.scriptField.get(1.0, "end-1c") f.write(bytes(text, 'UTF-8')) self.scriptField.edit_modified(False) self.file_path = filepath self.set_title() return # "saved" except IOError as e: self.handle_exception(e) return # "cancelled" def file_quit(self, event=None): save_changes = self.save_changes() if not save_changes: return self.close_figs() self.root.destroy() # sys.exit(0) def set_title(self, event=None): if self.file_path is not None: # title = os.path.basename(self.file_path) title = os.path.abspath(self.file_path) else: title = "Untitled" self.root.title(title + " - " + TITLE) def undo(self, event=None): try: self.scriptField.edit_undo() except Exception as e: self.handle_exception(e) return "break" def redo(self, event=None): self.scriptField.edit_redo() return "break" def _assign_accelerators(self): # self.scriptField.bind("<Control-n>", self.file_new) # self.scriptField.bind("<Control-N>", self.file_new) # self.scriptField.bind("<Control-o>", self.file_open) # self.scriptField.bind("<Control-O>", self.file_open) # self.scriptField.bind("<Control-S>", self.file_save) # self.scriptField.bind("<Control-s>", self.file_save) self.scriptField.bind("<Control-y>", self.redo) self.scriptField.bind("<Control-Y>", self.redo) self.scriptField.bind("<Control-z>", self.undo) self.scriptField.bind("<Control-Z>", self.undo) # self.root.bind_class("Text", ",<Control-z>", self.undo) # self.root.bind_class("Text", ",<Control-Z>", self.undo) # self.root.bind_class("Text", ",<Control-y>", self.redo) # self.root.bind_class("Text", ",<Control-Y>", self.redo) self.scriptField.bind("<F5>", self.simulate)
class main: def __init__(self, master, lexer): self.master = master self.master.title("PyDE - Untitled") self.filename = None self.lexer = lexer self.x, self.y = 0, 10 self.ftsize = 15 self.end = "" self.img = PhotoImage(file="C:/Users/shiven/Desktop/anime.png") self.__anime__ = self.img.subsample(3, 3) self.mario1 = PhotoImage( file="C:/Users/shiven/Desktop/C++/mariofinal1.png") self.mario2 = PhotoImage( file="C:/Users/shiven/Desktop/C++/mariofinal2.png") self.mario1 = self.mario1.subsample(2, 2) self.types = [("All Files", "*.*"), ("Text Files", "*.txt")] self.draw() self.text.bind("<Control-N>", self.newfile) self.text.bind("<Control-n>", self.newfile) self.text.bind("<Control-S>", self.savefile) self.text.bind("<Control-s>", self.savefile) self.text.bind("<Control-o>", self.openfile) self.text.bind("<Control-O>", self.openfile) self.text.bind("<Control-d>", self.copy_cur_line) self.text.bind("<Control-D>", self.copy_cur_line) self.text.bind("<Tab>", self.spaces) self.text.bind("<KeyRelease>", self.cur_line_col) self.text.bind("<Button-1>", self.cur_line_col) self.text.bind("<Button-3>", self.cur_line_col) self.text.bind("<Button-2>", self.cur_line_col) self.text.bind("<Motion>", self.cur_line_col) self.text.bind("<Configure>", self.cur_line_col) self.master.bind("<Control-[>", self.indent) self.master.bind("<Control-]>", self.dedent) self.master.bind("<Control-/>", self.comment) self.master.bind("<Alt-s>", self.uncomment) self.master.bind("<Alt-Up>", self.zoom_in) self.master.bind("<F3>", self.zoom_out) self.master.bind("<Shift-(>", self.insert_paren) self.master.bind("<[>", self.insert_paren) self.master.bind("<Shift-{>", self.insert_paren) self.master.bind("<Control-b>", self.runscript) self.animation() self.display_time() self.__styles() self.master.bind("<KeyRelease>", self.highlight) self.master.bind("<Key>", self.highlight) def highlight(self, e): self.recolor() def highlight_(self): self.recolor() self.master.after(1000, self.highlight_()) def __styles(self): self.bdfont = font.Font(self.text, self.text.cget("font")) self.bdfont.config(weight=font.BOLD) self.itfont = font.Font(self.text, self.text.cget("font")) self.itfont.config(slant=font.ITALIC) self.style = __get__('default') for ttype, ndef in self.style: self.tag_font = None if ndef['bold']: self.tag_font = self.bdfont elif ndef['italic']: self.tag_font = self.itfont if ndef['color']: self.fg = "#%s" % ndef['color'] else: self.fg = None self.text.tag_configure(str(ttype), foreground=self.fg, font=self.tag_font) def recolor(self): self.code = self.text.get("1.0", "end-1c") self.tokensource = self.lexer.get_tokens(self.code) self.start_line = 1 self.start_index = 0 self.end_line = 1 self.end_index = 0 for ttype, value in self.tokensource: if "\n" in value: self.end_line += value.count("\n") self.end_index = len(value.rsplit("\n", 1)[1]) else: self.end_index += len(value) if value not in (" ", "\n"): idx1 = "%s.%s" % (self.start_line, self.start_index) idx2 = "%s.%s" % (self.end_line, self.end_index) for tagname in self.text.tag_names(idx1): self.text.tag_remove(tagname, idx1, idx2) self.text.tag_add(str(ttype), idx1, idx2) self.start_line = self.end_line self.start_index = self.end_index def draw(self): self.filename = None self.path = None self.master.title("PyDE - {}".format("Untitled")) self.master.config(bg="Gray") self.anime__ = Canvas(self.master, width=1200, height=25, bg="Gray", relief=RAISED, highlightbackground='Gray') self.anime__.pack(anchor=NE) self.__display = Label(self.master, text="", bg="Gray", fg="White", padx=55, pady=10, justify=RIGHT, font=("8514oem", 1, 'normal')) self.__display.place(x=0, y=0) self.lcol = Label(self.master, bg="Gray") self.lcol.pack(side=BOTTOM, fill=X) self.scrollx = Scrollbar(self.master, orient=HORIZONTAL) self.scrollx.pack(side=BOTTOM, fill=X) self.text = ST(self.master, xscrollcommand=self.scrollx.set, selectbackground="Gray", fg="Gray", height=400, bg="Black", width=500, wrap=NONE, blockcursor=True) self.text.pack(side=TOP) self.scrollx.config(command=self.text.xview) self.text.config(fg="White", font=("8514oem", self.ftsize, 'bold'), insertbackground="Red") self.l_c = Label(self.lcol, bg="Gray") self.l_c.pack(side=RIGHT) self.timelabel = Label(self.lcol, text="", bg=self.anime__['bg'], font=("8514oem", self.ftsize, "bold")) self.timelabel.place(x=0, y=self.master.winfo_height() - 3) def newfile(self, e): self.filename = None self.path = None self.curname = "Untitled" if len(self.text.get(0.0, END)) > 1: self.asknew = askyesno("File changed", "Save file?") if self.asknew == True: self.savefile_() else: self.text.delete(1.0, END) self.master.title("PyDE - {}".format(self.curname)) self.__display.config(text="Untitled.py") else: self.__display.config(text="Untitled.py") def savefile_(self): if self.filename == None: self.s = asksaveasfile(defaultextension=self.types, filetypes=self.types) self.path = self.s.name self.curname = self.s.name.split("/")[-1] self.master.title("PyDE - {}".format(self.curname)) self.__display.config(text=self.curname) else: self.s.write(self.text.get(1.0, END)) def savefile(self, e): if self.filename == None: self.s = asksaveasfile(defaultextension=self.types, filetypes=self.types) self.path = self.s.name self.curname = self.s.name.split("/")[-1] self.master.title("PyDE - {}".format(self.curname)) self.__display.config(text=self.curname) else: self.s.write(self.text.get(1.0, END)) def openfile(self, e): try: self.o = askopenfile(filetypes=self.types, defaultextension=self.types) self.curname = self.o.name.split("/")[-1] self.path = self.o.name self.master.title("PyDE - {}".format(self.curname)) self.__display.config(text=self.curname) if self.text.edit_modified(): self.a_open = askyesno("save this thing?", "Save file?") if self.a_open == True: self.savefile_() else: pass else: self.text.delete(0.0, END) self.op = self.o.read() self.text.insert(END, self.op) except UnicodeDecodeError: self.unable = showerror("Invalid file", "Invalid file") def openfile_(self): try: if self.text.edit_modified(): self.savefile_() else: self.o = askopenfile(filetypes=self.types, defaultextension=self.types) self.op = self.o.read() self.path = self.o.name self.text.insert(END, self.op) except UnicodeDecodeError: self.unable = showerror("Invalid file", "Invalid file") def animation(self): self.x += 5 self.anime__.delete(ALL) self.anime__.create_image(self.x * 2, self.y + 5, image=self.mario1) if (self.x - 10) >= self.anime__.winfo_width(): self.x = 0 self.master.after(100, self.animation) # self.y-=5 def cur_line_col(self, e): self.l_raw = self.text.index(INSERT) self.lines = self.l_raw.split(".")[0] self.cols = self.l_raw.split(".")[1] self.binder_ = int(self.cols) self.l_c.config(text="lines:{0} columns:{1}".format( self.lines, self.cols), font=("8514oem", 9, 'bold')) def spaces(self, e): self.text.insert(INSERT, " " * 4) return 'break' def indent(self, e): self.tab = " " self.untabbed = self.text.get("sel.first", "sel.last") self.splitted = self.untabbed.split("\n") self.text.delete("sel.first", "sel.last") self.conts = [] for self.conts in list(self.splitted): self.conts = self.tab + self.conts + "\n" self.text.insert(INSERT, self.conts) def dedent(self, e): self.tab = " " self.tabbed = self.text.get("sel.first", "sel.last") self.splitted = self.tabbed.split("\n") self.text.delete("sel.first", "sel.last") self.conts = [] for self.conts in list(self.splitted): self.conts = self.conts.replace(self.tab, "") + "\n" self.text.insert(INSERT, self.conts) def comment(self, e): self.comment = "#" self.uncommented = self.text.get("sel.first", "sel.last") self.split_comment = self.uncommented.split("\n") self.split_comment = list(self.split_comment) self.text.delete("sel.first", "sel.last") self.commconts = [] for self.commconts in self.split_comment: self.commconts = self.comment + self.commconts + "\n" self.text.insert(INSERT, self.commconts) def uncomment(self, e): self.comment = "#" self.commented = self.text.get("sel.first", "sel.last") self.split_uncomm = self.commented.split("\n") self.split_uncomm = list(self.split_uncomm) self.text.delete("sel.first", "sel.last") self.unconts = [] for self.unconts in self.split_uncomm: self.unconts = self.unconts.replace(self.comment, "") + "\n" self.text.insert(INSERT, self.unconts) def runscript(self, e): if self.path == None: self.asksave = askyesno("Save this file?", "Save?") if self.asksave == True: self.savefile() os.system("python {}".format(self.path)) self.result = str( subprocess.check_output(['python', self.path])) self.output = showinfo("Output", "%s" % (self.result)) else: showinfo("Cant run before saving..", "Cant run before saving..") else: os.system("python {}".format(self.path)) self.result = str(subprocess.check_output(['python', self.path])) self.output = showinfo("Output", "%s" % (self.result)) def zoom_in(self, event): self.ftsize += 2 self.bdfont.config(size=self.ftsize) self.itfont.config(size=self.ftsize) self.text.config(font=("8514oem", self.ftsize, 'bold')) def zoom_out(self, e): self.ftsize -= 2 self.bdfont.config(size=self.ftsize) self.itfont.config(size=self.ftsize) self.text.config(font=("8514oem", self.ftsize, "bold")) def display_time(self): self.curtime = strftime("%H : %M : %S") self.timelabel.config(text=self.curtime) self.master.after(1000, self.display_time) def insert_paren(self, e): self.startparams = "([{" self.endparams = ")]}" self.cursor = self.text.index(INSERT) self.linecur = str(self.cursor.split(".")[0]) self.colcur = int(self.cursor.split(".")[1]) if e.char == self.startparams[0]: self.text.insert(INSERT, self.endparams[0]) self.text.mark_set(INSERT, self.linecur + "." + str(self.colcur)) elif e.char == self.startparams[1]: self.text.insert(INSERT, self.endparams[1]) self.text.mark_set(INSERT, self.linecur + "." + str(self.colcur)) elif e.char == self.startparams[2]: self.text.insert(INSERT, self.endparams[2]) self.text.mark_set(INSERT, self.linecur + "." + str(self.colcur)) else: pass def copy_cur_line(self, e): self.linetext = self.text.get("insert linestart", "insert lineend") self.newidx = float(self.text.index(INSERT)) + 1.1 self.text.insert(INSERT, "\n") self.text.insert(self.newidx, self.linetext + "\n") self.text.mark_set("insert", self.newidx) return 'break'
class Main(object): def __init__(self, root_): self.root = root_ self.file_path = None self.root.title("Proyecto final Inteligencia Artifical II") # Images and title self.title_label = Label( root, text="UNIVERSIDAD DE LAS FUERZAS ARMADAS ESPE") self.title_label.grid(row=0, column=0, columnspan=2) img = Image.open("logo.png") img = img.resize((250, 70), Image.ANTIALIAS) self.image = ImageTk.PhotoImage(img) self.image_label = Label(root, image=self.image) self.image_label.grid(row=1, column=0, columnspan=2) self.rule_editor_label = Label(root, text="Hechos: ", padx=10, pady=1) self.rule_editor_label.grid(sticky="W", row=2, column=0, columnspan=2, pady=3) # Create rule editor where we can edit the rules we want to enter: self.rule_editor = ScrolledText(root, width=100, height=30, padx=10, pady=10) self.rule_editor.grid(sticky=W + E, row=3, column=0, columnspan=2, padx=10) self.rule_editor.config(wrap="word", undo=True) self.rule_editor.focus() # Create a query label: self.query_label = Label(root, text="Prolog Query:", padx=10, pady=1) self.query_label.grid(sticky=W, row=4, column=0, columnspan=2, pady=3) # Create the Prolog query editor we'll use to query our rules: self.query_editor = Text(root, width=77, height=2, padx=10, pady=10) self.query_editor.grid(sticky=W, row=5, column=0, pady=3, padx=10) self.query_editor.config(wrap="word", undo=True) # Create a run button which runs the query against our rules and outputs the # results in our solutions text box / editor. self.run_button = Button( root, text="Find Query Solutions", height=2, width=20, command=self.run_query, ) self.run_button.grid(sticky=E, row=5, column=1, pady=3, padx=10) # Create a solutions label self.solutions_label = Label(root, text="Query Solutions:", padx=10, pady=1) self.solutions_label.grid(sticky="W", row=6, column=0, columnspan=2, padx=10, pady=3) # Create a text box which we'll use to display our Prolog query solutions: self.solutions_display = ScrolledText(root, width=100, height=5, padx=10, pady=10) self.solutions_display.grid(row=7, column=0, columnspan=2, padx=10, pady=7) # Finally, let's create the file menu self.menu_bar = self.create_file_menu() def add_new_fact(self): pass def load_exercise_two(self): pass def load_exercise_five(self): pass def create_file_menu(self): """Create a menu which will allow us to open / save our Prolog rules, run our query, and exit our editor interface """ menu_bar = Menu(root) file_menu = Menu(menu_bar, tearoff=0) file_menu.add_command(label="Abrir", underline=1, command=self.open_file) file_menu.add_separator() file_menu.add_command(label="Save", underline=1, command=self.save_file) file_menu.add_command(label="Save As...", underline=5, command=self.save_file_as) file_menu.add_separator() file_menu.add_command(label="Run", underline=1, command=self.run_query) file_menu.add_separator() file_menu.add_command(label="Exit", underline=2, command=self.root.destroy) menu_bar.add_cascade(label="File", underline=0, menu=file_menu) self.root.config(menu=menu_bar) return menu_bar def run_query(self): """Interpret the entered rules and query and display the results in the solutions text box """ # Delete all of the text in our solutions display text box self.solutions_display.delete("1.0", END) self.set_busy() # Fetch the raw rule / query text entered by the user rules_text = self.rule_editor.get(1.0, "end-1c") query_text = self.query_editor.get(1.0, "end-1c") # Create a new solver so we can try to query for solutions. try: solver = Solver(rules_text) except Exception as e: self.handle_exception("Error processing prolog rules.", str(e)) return # Attempt to find the solutions and handle any exceptions gracefully try: solutions = solver.find_solutions(query_text) except Exception as e: self.handle_exception("Error processing prolog query.", str(e)) return # If our query returns a boolean, we simply display a 'Yes' or a 'No' # depending on its value if isinstance(solutions, bool): self.solutions_display.insert(END, "Yes." if solutions else "No.") # Our solver returned a map, so we display the variable name to value mappings elif isinstance(solutions, dict): self.solutions_display.insert( END, "\n".join( "{} = {}" # If our solution is a list contining one item, we show that # item, otherwise we display the entire list .format(variable, value[0] if len(value) == 1 else value) for variable, value in solutions.items() ), ) else: # We know we have no matching solutions in this instance so we provide # relevant feedback self.solutions_display.insert(END, "No solutions found.") self.set_not_busy() def handle_exception(self, error_message, exception=""): """Handle the exception by printing an error message as well as exception in our solution text editor / display """ self.solutions_display.insert(END, error_message + "\n") self.solutions_display.insert(END, str(exception) + "\n") self.set_not_busy() def set_rule_editor_text(self, text): self.rule_editor.delete(1.0, "end") self.rule_editor.insert(1.0, text) self.rule_editor.edit_modified(False) def set_busy(self): # Show a busy cursor and update the UI self.root.config(cursor="watch") self.root.update() def set_not_busy(self): # Show a regular cursor self.root.config(cursor="") def open_file(self, file_path=None): # Open a a new file dialog which allows the user to select a file to open if file_path is None: file_path = filedialog.askopenfilename() if is_file_path_selected(file_path): file_contents = get_file_contents(file_path) # Set the rule editor text to contain the selected file contents self.set_rule_editor_text(file_contents) self.file_path = file_path def save_file(self): """If we have specified a file path, save the file - otherwise, prompt the user to specify the file location prior to saving the file """ if self.file_path is None: result = self.save_file_as() else: result = self.save_file_as(file_path=self.file_path) return result def write_editor_text_to_file(self, file): editor_text = self.rule_editor.get(1.0, "end-1c") file.write(bytes(editor_text, "UTF-8")) self.rule_editor.edit_modified(False) def save_file_as(self, file_path=None): # If there is no file path specified, prompt the user with a dialog which # allows him/her to select where they want to save the file if file_path is None: file_path = filedialog.asksaveasfilename(filetypes=( ("Text files", "*.txt"), ("Prolog files", "*.pl *.pro"), ("All files", "*.*"), )) try: # Write the Prolog rule editor contents to the file location with open(file_path, "wb") as file: self.write_editor_text_to_file(file) self.file_path = file_path return "saved" except FileNotFoundError: return "cancelled" def undo(self): self.rule_editor.edit_undo() def redo(self): self.rule_editor.edit_redo()
class EditorTab(tk.Frame): def __init__(self, master, filepath: str, new_file=False): tk.Frame.__init__(self, master) self.new_file = new_file self.filepath = filepath self.filename = get_filename(filepath) if not new_file else filepath self.master = master self.modified = False self.text_editor = ScrolledText(self, font=("", 15), undo=True, maxundo=-1, wrap="none") self.text_editor.config(highlightthickness=0, bd=0) self.text_editor.grid(row=0, column=1, sticky=tk.NSEW) self.scrollbar_x = tk.Scrollbar(self, orient=tk.HORIZONTAL, command=self.text_editor.xview) self.scrollbar_x.grid(row=1, column=0, columnspan=2, stick=tk.EW) self.text_editor.configure(xscrollcommand=self.scrollbar_x.set) self.line_nb_canvas = tk.Canvas(self, bg=self.text_editor.cget("bg"), bd=0, highlightthickness=0) self.line_nb_canvas.grid_propagate(False) self.line_nb_canvas.grid(row=0, column=0, sticky=tk.NS) self.grid_rowconfigure(0, weight=1) self.grid_columnconfigure(1, weight=1) self.default_file_content = str() @property def id(self) -> str: return str(self) def get(self) -> str: return self.text_editor.get("1.0", "end-1c") @property def lines(self): return self.get().splitlines() def update_lines(self): self.line_nb_canvas.delete("all") font = self.text_editor.cget("font") i = 1 y = 0 while self.text_editor.compare(f"{i}.0", "<", tk.END): dline = self.text_editor.dlineinfo(f"{i}.0") if dline: y = dline[1] else: y = -20 self.line_nb_canvas.create_text(1, y, anchor="ne", text=str(i), font=font, fill=Color(175, 175, 175).hex) i += 1 all_boxes = [ self.line_nb_canvas.bbox(item) for item in self.line_nb_canvas.find_all() ] max_width = (min(box[2] - box[0] for box in all_boxes)) * 4 self.line_nb_canvas.configure(width=max_width + 20) for item in self.line_nb_canvas.find_all(): self.line_nb_canvas.move(item, max_width, 0) def get_filename_from_champion_name(self) -> (str, None): content = self.lines for line in content: if line.startswith(".name"): first_quote = line.find('"') if first_quote == -1: break second_quote = line.find('"', first_quote + 1) if second_quote == -1: break name = line[first_quote + 1:second_quote] if len(name) == 0: break return name.replace(" ", "_").lower() + ".s" return None def open(self) -> bool: if not os.path.isfile(self.filepath): showwarning("An error occurs...", f"Can't open '{self.filepath}'") return False with open(self.filepath, "r") as file: self.default_file_content = file.read() self.text_editor.insert("1.0", self.default_file_content) self.text_editor.edit_reset() self.text_editor.edit_modified(False) self.set_modified_status(False, on_opening=True) return True def save(self) -> bool: if self.new_file: return self.master.save_file_as() self.default_file_content = self.text_editor.get("1.0", "end-1c") with open(self.filepath, "w") as file: file.write(self.default_file_content) self.set_modified_status(False) self.text_editor.edit_modified(False) return True def save_as(self, filepath: str) -> bool: self.master.files_opened[filepath] = self.master.files_opened[ self.filepath] self.master.files_opened.pop(self.filepath) self.filepath = filepath self.filename = get_filename(filepath) self.new_file = False return self.save() def close(self) -> bool: if self.modified: save_file = askyesnocancel( f"{self.filename} - Modifications not saved", "This file was modified and was not saved.\nDo you want to save this file ?" ) if save_file is None: return False if save_file and not self.save(): return False self.master.forget(self.id) self.master.files_opened.pop(self.filepath) return True def undo(self) -> None: try: self.text_editor.edit_undo() except tk.TclError: pass def redo(self) -> None: try: self.text_editor.edit_redo() except tk.TclError: pass def copy_to_clipboard(self, remove_from_editor=False) -> bool: try: txt = self.text_editor.get("sel.first", "sel.last") self.clipboard_clear() self.clipboard_append(txt) if remove_from_editor: self.text_editor.delete("sel.first", "sel.last") except tk.TclError: return False return True def paste_from_clipboard(self) -> None: try: self.text_editor.get("sel.first", "sel.last") except tk.TclError: pass else: self.text_editor.mark_set("insert", "sel.first") self.text_editor.delete("sel.first", "sel.last") self.text_editor.insert("insert", self.clipboard_get()) def check_file_status(self) -> None: actual = self.text_editor.get("1.0", "end-1c") if self.text_editor.edit_modified(): self.text_editor.edit_separator() self.text_editor.edit_modified(False) self.set_modified_status(actual != self.default_file_content) def set_modified_status(self, status: bool, on_opening=False) -> None: self.modified = status if not on_opening: if self.modified and not self.new_file: self.master.tab(self.id, text=self.filename + " - Modified") else: self.master.tab(self.id, text=self.filename) def add(self) -> None: self.master.add(self, text=self.filename) def select(self) -> None: self.master.select(self.id) self.text_editor.focus_set() def set_template(self, name: str, comment: str, author: str) -> None: content = [ line for line in self.lines if not line.startswith(".name") and not line.startswith(".comment") ] header = [ "#", "# {name} champion for CoreWar".format(name=name), "#", "# By {author}".format(author=author), "#", "# {date}".format(date=date.today().strftime("%c")), "#", "" ".name \"{name}\"".format(name=name), ".comment \"{comment}\"".format(comment=comment), "" ] content = header + content self.text_editor.delete("1.0", "end") self.text_editor.insert("1.0", "\n".join(content)) def insert_command(self, cmd: str) -> None: insert = self.text_editor.index(tk.INSERT).split(".") end_of_line = insert[0] + "." + tk.END self.text_editor.insert(end_of_line, "\n" + cmd)
class OptimizerMainWindow: """ classdocs """ # TODO: change that name def reactToClick(self, event): a = AddRestrictionDialog(self) def __init__(self, optimizer): # always have a reference to model/controller self.optimizer = optimizer # setup main GUI and make stretchable self.guiRoot = Tk() self.guiRoot.title("OPTIMIZR") self.guiRoot.columnconfigure(1, weight=1) self.guiRoot.rowconfigure(0, weight=1) # left (settings) and right (sequences) part self.frameLeft = Frame(self.guiRoot) self.frameLeft.grid(row=0, column=0, sticky=W + E + N + S) self.frameLeft.columnconfigure(0, weight=1) self.frameRight = Frame(self.guiRoot) self.frameRight.grid(row=0, column=1, sticky=W + E + N + S) self.frameRight.columnconfigure(0, weight=1) self.frameRight.rowconfigure(0, weight=1) self.frameRight.rowconfigure(1, weight=1) self.frameSpeciesControll = LabelFrame(self.frameLeft, text="Species", pady=10, padx=10) self.frameSpeciesControll.columnconfigure(1, weight=1) self.frameOptimizationControll = LabelFrame(self.frameLeft, text="Optimization", pady=10, padx=10) self.frameRestrictionControll = LabelFrame(self.frameLeft, text="Restriction Enzymes", pady=10, padx=10) self.frameSpeciesControll.grid(row=0, column=0, sticky=W + E, padx=10, pady=10) self.frameOptimizationControll.grid(row=1, column=0, sticky=W + E, padx=10, pady=10) self.frameRestrictionControll.grid(row=2, column=0, sticky=W + E, padx=10, pady=10) # Species Controll Label(self.frameSpeciesControll, text="Source:").grid(row=0, column=0) Label(self.frameSpeciesControll, text="Target:").grid(row=1, column=0) self.comboSourceSpecies = Combobox(self.frameSpeciesControll, state="readonly") self.comboSourceSpecies.grid(row=0, column=1, pady=5, sticky="ew") self.comboTargetSpecies = Combobox(self.frameSpeciesControll, state="readonly") self.comboTargetSpecies.grid(row=1, column=1, pady=5, sticky="we") self.buttonSpeciesList = Button(self.frameSpeciesControll, text="Edit Species List") self.buttonSpeciesList.grid(row=2, column=1, pady=5, sticky="e") self.comboSourceSpecies.bind("<<ComboboxSelected>>", self.actionOptimizerSettingsChanged) self.comboTargetSpecies.bind("<<ComboboxSelected>>", self.actionOptimizerSettingsChanged) # Optimization Controll Label(self.frameOptimizationControll, text="Optimization Strategy:").grid(row=0, column=0) self.comboOptimizationStrategy = Combobox(self.frameOptimizationControll, state="readonly") self.comboOptimizationStrategy.grid(row=0, column=1) self.comboOptimizationStrategy["values"] = self.optimizer.possibleOptimizationStrategies self.comboOptimizationStrategy.bind("<<ComboboxSelected>>", self.actionOptimizerSettingsChanged) # Restriction Enzymes self.listRestriction = Listbox(self.frameRestrictionControll) self.listRestriction.grid(row=0, column=0, columnspan=3, pady=5, sticky=W + E) self.frameRestrictionControll.columnconfigure(0, weight=1) self.buttonRestricionAdd = Button(self.frameRestrictionControll, text=" + ") self.buttonRestricionDel = Button(self.frameRestrictionControll, text=" - ") self.buttonRestricionAdd.grid(row=1, column=1, padx=5) self.buttonRestricionDel.grid(row=1, column=2, padx=5) # Source Sequence Frame self.frameSourceSequence = LabelFrame(self.frameRight, text="Source Sequence", padx=10, pady=10) self.frameResultSequence = LabelFrame(self.frameRight, text="Result Sequence", padx=10, pady=10) self.frameSourceSequence.grid(row=0, column=0, sticky="wens", padx=10, pady=10) self.frameResultSequence.grid(row=1, column=0, sticky="wens", padx=10, pady=10) self.buttonSourceLoad = Button(self.frameSourceSequence, text=" Load ") self.textSourceSeq = ScrolledText(self.frameSourceSequence, height=10) self.buttonSourceLoad.grid(row=0, column=1, sticky="e", pady=5) self.textSourceSeq.grid(row=1, column=0, columnspan=2, sticky="wens") self.frameSourceSequence.columnconfigure(0, weight=1) self.frameSourceSequence.rowconfigure(1, weight=1) self.textSourceSeq.frame.columnconfigure(1, weight=1) self.textSourceSeq.frame.rowconfigure(0, weight=1) self.buttonOptimize = Button(self.frameResultSequence, text=" OPTIMIZE! ") self.buttonOptimize.bind("<ButtonRelease>", self.actionOptimize) self.buttonRemoveRestriction = Button(self.frameResultSequence, text=" RESTRICTION-B-GONE! ") self.buttonRemoveRestriction.bind("<ButtonRelease>", self.actionRemoveRestricion) self.buttonSaveResult = Button(self.frameResultSequence, text=" Save ") self.textResultSequence = ScrolledText(self.frameResultSequence, height=10) self.buttonOptimize.grid(column=0, row=0, pady=5, sticky="w") self.buttonRemoveRestriction.grid(column=1, row=0, pady=5, padx=10, sticky="w") self.textResultSequence.grid(row=1, column=0, columnspan=4, sticky="wens") self.buttonSaveResult.grid(row=2, column=3, pady=5, sticky="e") self.frameResultSequence.columnconfigure(2, weight=1) self.frameResultSequence.rowconfigure(1, weight=1) self.textResultSequence.frame.columnconfigure(1, weight=1) self.textResultSequence.frame.rowconfigure(0, weight=1) self.textSourceSeq.bind("<<Modified>>", self.actionSequenceModified) self.textResultSequence.bind("<<Modified>>", self.actionSequenceModified) # generate color tags for textboxes for i in range(101): # green for normal codons (r, g, b) = colorsys.hsv_to_rgb(210 / 360, i / 100, 1.0) colorHex = "#%02x%02x%02x" % (int(r * 255), int(g * 255), int(b * 255)) self.textSourceSeq.tag_config("normal" + str(i), background=colorHex) self.textResultSequence.tag_config("normal" + str(i), background=colorHex) # red for codons with restriction sites (r, g, b) = colorsys.hsv_to_rgb(5 / 360, i / 100, 1.0) colorHex = "#%02x%02x%02x" % (int(r * 255), int(g * 255), int(b * 255)) self.textSourceSeq.tag_config("restrict" + str(i), background=colorHex) self.textResultSequence.tag_config("restrict" + str(i), background=colorHex) # Set (minimum + max) Window size self.guiRoot.update() self.guiRoot.minsize(self.guiRoot.winfo_width(), self.guiRoot.winfo_height()) self.buttonRestricionAdd.bind("<ButtonRelease>", self.reactToClick) self.buttonRestricionDel.bind("<ButtonRelease>", self.actionRestrictionEnzymeDelete) self.buttonSpeciesList.bind("<ButtonRelease>", self.actionEditSpeciesButton) self.buttonSourceLoad.bind("<ButtonRelease>", self.actionLoadSequence) self.buttonSaveResult.bind("<ButtonRelease>", self.actionSaveSequence) # TEST # self.listRestriction.insert("end", "EcoRI") # self.listRestriction.insert("end", "BamHI") # # dummy event to manually trigger update self.guiRoot.bind("<<Update>>", self.actionUpdate) self.actionUpdate(None) self.guiRoot.mainloop() def actionRestrictionEnzymeDelete(self, event): try: selectedEnzyme = self.listRestriction.selection_get() self.optimizer.restrictionEnzymeList.remove(selectedEnzyme) self.guiRoot.event_generate("<<Update>>") except tkinter.TclError: # no selection pass def actionUpdate(self, event): # print("update called") # clear list of restriction enzymes self.listRestriction.delete(0, "end") for r in self.optimizer.restrictionEnzymeList: self.listRestriction.insert("end", r) self.comboSourceSpecies.delete(0, "end") self.comboTargetSpecies.delete(0, "end") speciesValues = list() for (taxid, name) in self.optimizer.speciesList: speciesValues.append(taxid + ": " + name) self.comboSourceSpecies["values"] = speciesValues self.comboTargetSpecies["values"] = speciesValues if self.comboSourceSpecies.get() not in speciesValues: self.comboSourceSpecies.set("") if self.comboTargetSpecies.get() not in speciesValues: self.comboTargetSpecies.set("") self.textSourceSeq.edit_modified(True) self.textResultSequence.edit_modified(True) self.optimizer.saveConfig("config.ini") def actionEditSpeciesButton(self, event): speciesListDialog = SpeciesListDialog(self) def actionOptimizerSettingsChanged(self, event=None): # print("Something happened") strategy = self.comboOptimizationStrategy.get() sourceString = self.comboSourceSpecies.get() targetString = self.comboTargetSpecies.get() if not (strategy and sourceString and targetString): return sourceTaxid = sourceString.split(":")[0] targetTaxid = targetString.split(":")[0] self.optimizer.setOptimizer(sourceTaxid, targetTaxid, strategy) self.textSourceSeq.edit_modified(True) self.textResultSequence.edit_modified(True) # self.optimizer.testPrint() def actionOptimize(self, event=None): self.optimizer.runOptimization() self.textSourceSeq.edit_modified(True) self.textResultSequence.edit_modified(True) def actionRemoveRestricion(self, event=None): self.optimizer.runRestricionRemoval() self.textSourceSeq.edit_modified(True) self.textResultSequence.edit_modified(True) def actionSequenceModified(self, event=None): # necessary if, otherwise -> infinite loop if self.textSourceSeq.edit_modified(): seq = self.textSourceSeq.get("1.0", "end").strip() seq = stripCharsNotInList(seq.upper(), ["A", "C", "G", "T"]) self.optimizer.setSourceSeq(seq) oldInsert = self.textSourceSeq.index("insert") self.textSourceSeq.delete("1.0", "end") sourceCodons = self.optimizer.getCodonsForPrint(True) if not sourceCodons: self.textSourceSeq.insert("end", self.optimizer.sourceSequence) else: for (co, sc, r) in sourceCodons: if sc: if not r: self.textSourceSeq.insert("end", co, "normal" + str(int(sc * 100))) # print("normal"+str(int(sc*100))) else: self.textSourceSeq.insert("end", co, "restrict" + str(int(sc * 100))) else: # remainder without color self.textSourceSeq.insert("end", co) self.textSourceSeq.mark_set("insert", oldInsert) # reset the modified status at the very end self.textSourceSeq.edit_modified(False) if self.textResultSequence.edit_modified(): seq = self.textResultSequence.get("1.0", "end").strip() # self.optimizer.setOptimizedSeq(seq) oldInsert = self.textResultSequence.index("insert") self.textResultSequence.delete("1.0", "end") targetCodons = self.optimizer.getCodonsForPrint(False) if not targetCodons: self.textSourceSeq.insert("end", self.optimizer.optimizedSequence) else: for (co, sc, r) in targetCodons: if sc: if not r: self.textResultSequence.insert("end", co, "normal" + str(int(sc * 100))) # print("normal"+str(int(sc*100))) else: self.textResultSequence.insert("end", co, "restrict" + str(int(sc * 100))) else: # remainder without color self.textResultSequence.insert("end", co) self.textSourceSeq.mark_set("insert", oldInsert) self.textResultSequence.edit_modified(False) def actionLoadSequence(self, event=None): filename = tkinter.filedialog.askopenfilename() if filename: seq = sequenceIO.readFile(filename) self.textSourceSeq.delete("1.0", "end") self.textSourceSeq.insert("end", seq) self.textSourceSeq.edit_modified(True) def actionSaveSequence(self, event=None): filename = tkinter.filedialog.asksaveasfilename() if filename: # print("file is " + filename) with open(filename, mode="w") as fd: fd.write(self.optimizer.optimizedSequence)
class Editor(): def __init__(self, root): self.root = root self.file_path = None self.root.title('Prolog Interpreter') # Create a rule label self.rule_editor_label = Label(root, text="Prolog Rules: ", padx=10, pady=1) self.rule_editor_label.grid(sticky="W", row=0, column=0, columnspan=2, pady=3) # Create rule editor where we can edit the rules we want to enter: self.rule_editor = ScrolledText(root, width=100, height=30, padx=10, pady=10) self.rule_editor.grid(sticky=W + E, row=1, column=0, columnspan=2, padx=10) self.rule_editor.config(wrap="word", undo=True) self.rule_editor.focus() # Create a query label: self.query_label = Label(root, text="Prolog Query:", padx=10, pady=1) self.query_label.grid(sticky=W, row=2, column=0, columnspan=2, pady=3) # Create the Prolog query editor we'll use to query our rules: self.query_editor = Text(root, width=77, height=2, padx=10, pady=10) self.query_editor.grid(sticky=W, row=3, column=0, pady=3, padx=10) self.query_editor.config(wrap="word", undo=True) # Create a run button which runs the query against our rules and outputs the results in our # solutions text box / editor. self.run_button = Button(root, text='Find Query Solutions', height=2, width=20, command=self.run_query) self.run_button.grid(sticky=E, row=3, column=1, pady=3, padx=10) # Create a solutions label self.solutions_label = Label(root, text="Query Solutions:", padx=10, pady=1) self.solutions_label.grid(sticky="W", row=4, column=0, columnspan=2, padx=10, pady=3) # Create a text box which we'll use to display our Prolog query solutions: self.solutions_display = ScrolledText(root, width=100, height=5, padx=10, pady=10) self.solutions_display.grid(row=5, column=0, columnspan=2, padx=10, pady=7) # Finally, let's create the file menu self.create_file_menu() # Create a menu which will allow us to open / save our Prolog rules, run our query, # and exit our editor interface def create_file_menu(self): self.menu_bar = Menu(root) file_menu = Menu(self.menu_bar, tearoff=0) file_menu.add_command(label="Open...", underline=1, command=self.open_file) file_menu.add_separator() file_menu.add_command(label="Save", underline=1, command=self.save_file) file_menu.add_command(label="Save As...", underline=5, command=self.save_file_as) file_menu.add_separator() file_menu.add_command(label="Run", underline=1, command=self.run_query) file_menu.add_separator() file_menu.add_command(label="Exit", underline=2, command=self.root.destroy) self.menu_bar.add_cascade(label="File", underline=0, menu=file_menu) self.root.config(menu=self.menu_bar) # Show a busy cursor and update the UI def set_busy(self): self.root.config(cursor="watch") self.root.update() # Show a regular cursor def set_not_busy(self): self.root.config(cursor="") # Interpret the entered rules and query and display the results in the solutions text box def run_query(self): # Delete all of the text in our solutions display text box self.solutions_display.delete('1.0', END) self.set_busy() # Fetch the raw rule / query text entered by the user rules_text = self.rule_editor.get(1.0, "end-1c") query_text = self.query_editor.get(1.0, "end-1c") # Create a new solver so we can try to query for solutions. try: solver = Solver(rules_text) except Exception as exception: self.handle_exception("Error processing prolog rules.", exception) return # Attempt to find the solutions and handle any exceptions gracefully try: solutions = solver.find_solutions(query_text) except Exception as exception: self.handle_exception("Error processing prolog query.", exception) return # If our query returns a boolean, we simply display a 'Yes' or a 'No' depending on its value if isinstance(solutions, bool): self.solutions_display.insert(END, 'Yes.' if solutions else 'No.') # Our solver returned a map, so we display the variable name to value mappings elif isinstance(solutions, dict): self.solutions_display.insert( END, "\n".join("{} = {}" # If our solution is a list contining one item, we show that # item, otherwise we display the entire list .format(variable, value[0] if len(value) == 1 else value) for variable, value in solutions.items()) ) else: # We know we have no matching solutions in this instance so we provide relevant feedback self.solutions_display.insert(END, "No solutions found.") self.set_not_busy() # Handle the exception by printing an error message as well as exception in our solution text editor / display def handle_exception(self, error_message, exception=''): self.solutions_display.insert(END, error_message + "\n") self.solutions_display.insert(END, str(exception) + '\n') self.set_not_busy() def is_file_path_selected(self, file_path): return file_path != None and file_path != '' # Return a string containing the file contents of the file located at the specified file path def get_file_contents(self, file_path): with open(file_path, encoding="utf-8") as f: file_contents = f.read() return file_contents def set_rule_editor_text(self, text): self.rule_editor.delete(1.0, "end") self.rule_editor.insert(1.0, text) self.rule_editor.edit_modified(False) def open_file(self, file_path=None): # Open a a new file dialog which allows the user to select a file to open if file_path == None: file_path = filedialog.askopenfilename() if self.is_file_path_selected(file_path): file_contents = self.get_file_contents(file_path) # Set the rule editor text to contain the selected file contents self.set_rule_editor_text(file_contents) self.file_path = file_path # If we have specified a file path, save the file - otherwise, prompt the user to specify the file location # prior to saving the file def save_file(self): if self.file_path == None: result = self.save_file_as() else: result = self.save_file_as(file_path=self.file_path) return result def write_editor_text_to_file(self, file): editor_text = self.rule_editor.get(1.0, "end-1c") file.write(bytes(editor_text, 'UTF-8')) self.rule_editor.edit_modified(False) def save_file_as(self, file_path=None): # If there is no file path specified, prompt the user with a dialog which allows him/her to select # where they want to save the file if file_path == None: file_path = filedialog.asksaveasfilename( filetypes=(('Text files', '*.txt'), ('Prolog files', '*.pl *.pro'), ('All files', '*.*'))) try: # Write the Prolog rule editor contents to the file location with open(file_path, 'wb') as file: self.write_editor_text_to_file(file) self.file_path = file_path return "saved" except FileNotFoundError: return "cancelled" def undo(self, event=None): self.rule_editor.edit_undo() def redo(self, event=None): self.rule_editor.edit_redo()
class NoteEditor: def __init__(self): self.id = None self.page_name = None self.font_name = 'arial' self.font_size = 12 self.font_weight = tk.NORMAL self.editor = None self.file_io = FileIO() self.syntax_file_io = FileIO() def create_editor(self, master): self.editor = ScrolledText(master, undo=True, autoseparators=True, maxundo=-1) # Styling of text area self.set_editor_font(None, None) self.editor.pack(side="left") self.editor.focus() self.editor.pack(fill="both", expand=True) # Configuring style tags self.editor.tag_config("BACKGROUND", background="yellow") self.editor.tag_configure("HIGHLIGHT", foreground="red") self.editor['wrap'] = tk.NONE self.editor.bind('<Button-3>', self.rClicker, add='') def set_editor_font(self, font_name, font_size, font_weight=None): if font_name is not None: self.font_name = font_name if font_size is not None and int(font_size) > 0: self.font_size = font_size if font_weight is not None: self.font_weight = font_weight self.editor['font'] = Font(family=self.font_name, size=self.font_size, weight=self.font_weight) def set_editor_bgcolor(self, hex_color): self.editor['background'] = hex_color def set_editor_fgcolor(self, hex_color): self.editor['foreground'] = hex_color def set_emphasis(self, on): if on == 1: bold_font = Font(family=self.font_name, size=self.font_size, weight="bold") self.editor.tag_configure("BOLDFONT", font=bold_font) if self.editor.tag_ranges(tk.SEL): self.editor.tag_add("BOLDFONT", tk.SEL_FIRST, tk.SEL_LAST) else: self.editor.tag_add("BOLDFONT", "1.0", tk.END) else: self.editor.tag_remove("BOLDFONT", "1.0", tk.END) def toggle_wrap(self, on): if on == 1: self.editor['wrap'] = tk.WORD else: self.editor['wrap'] = tk.NONE def search_forward(self, text): located_start = self.editor.search(text, tk.INSERT, stopindex=tk.END, forwards=True, nocase=True) located_end = '{}+{}c'.format(located_start, len(text)) if located_start is '' or located_end is '': return False self.select_editor_location(located_start, located_end) # Start position is moved after current found location. self.editor.mark_set(tk.INSERT, located_end) return True def search_backward(self, text): located_start = self.editor.search(text, tk.INSERT, stopindex='1.0', backwards=True, nocase=True) located_end = '{}+{}c'.format(located_start, len(text)) if located_start is '' or located_end is '': return False self.select_editor_location(located_start, located_end) # Start position is moved after current found location. self.editor.mark_set(tk.INSERT, located_start) return True def replace_selected_text(self, new_text): self.editor.delete('sel.first', 'sel.last') self.editor.insert('insert', new_text) def select_editor_location(self, selection_start, selection_end): print('Found location start: ', selection_start) print('Found location end: ', selection_end) selection_start_float = float(selection_start) self.editor.tag_remove(tk.SEL, "1.0", 'end') self.editor.tag_add(tk.SEL, selection_start, selection_end) self.editor.focus_force() self.editor.see(selection_start_float) def is_dirty(self): return self.editor.edit_modified() def rClicker(self, e): ''' right click context menu for all Tk Entry and Text widgets ''' try: def rClick_Copy(e, apnd=0): e.widget.event_generate('<Control-c>') def rClick_Cut(e): e.widget.event_generate('<Control-x>') def rClick_Paste(e): e.widget.event_generate('<Control-v>') def rClick_Highlight_Keyword(e): self.highlight_syntax(True) e.widget.focus() nclst = [ (' Cut', lambda e=e: rClick_Cut(e)), (' Copy', lambda e=e: rClick_Copy(e)), (' Paste', lambda e=e: rClick_Paste(e)), (' Highlight Keyword', lambda e=e: rClick_Highlight_Keyword(e)), ] rmenu = tk.Menu(None, tearoff=0, takefocus=0) for (txt, cmd) in nclst: rmenu.add_command(label=txt, command=cmd) rmenu.tk_popup(e.x_root + 40, e.y_root + 10, entry="0") except tk.TclError: print ' - rClick menu, something wrong' pass return "break" def highlight_syntax(self, enable=True): syntax_file = Path(Path( self.file_io.file_name).suffix[1:]).with_suffix('.hs') hs_config_data = Configuration.get_hs_configuration(syntax_file) if hs_config_data is None: print('No syntax file ', syntax_file) return #print(hs_config_data) keywords = hs_config_data['keyword']['tags'] keyword_fgcolor = hs_config_data['keyword']['color'] constant_fgcolor = hs_config_data['constant']['color'] numbers = re.findall(r'\d{1,3}', self.file_io.file_data) self.editor.tag_config('tg_kw', foreground=keyword_fgcolor) self.editor.tag_config('tg_num', foreground=constant_fgcolor) #keywords = ['package', 'public', 'private', 'abstract', 'internal', 'new', 'static', 'final', 'long', 'extends', # 'class', 'import', 'null', 'for', 'if', 'return', 'int', 'char', 'float', 'double', 'implements'] for keyword in keywords: self.editor.mark_set(tk.INSERT, '1.0') while True: located_end = self.highlight_keyword(keyword + ' ', 'tg_kw') if located_end == 0: break self.editor.mark_set(tk.INSERT, located_end) self.editor.mark_set(tk.INSERT, '1.0') for each_number in numbers: located_end = self.highlight_keyword(each_number, 'tg_num') if located_end != 0: self.editor.mark_set(tk.INSERT, located_end) print("Syntax highlight executed.") def highlight_keyword(self, text, tag): located_start = self.editor.search(text, tk.INSERT, stopindex=tk.END, forwards=True, nocase=False) located_end = '{}+{}c'.format(located_start, len(text)) print(located_start, ',', located_end) print('keyword', text) if located_start is '' or located_end is '': return 0 self.editor.tag_add(tag, located_start, located_end) return located_end
class TitlerApp: def __init__(self, root): self.file = open('title.html', 'w') self.ready = False self.root = root frame = Frame(root) frame.pack(fill=BOTH, expand=True) notebook = Notebook(frame) notebook.pack(fill=BOTH, expand=True) textFrame = Frame() notebook.add(textFrame, text="Text") Grid.columnconfigure(textFrame, 0, weight=1) textTopPanel = Frame(textFrame) textTopPanel.grid(row=0, sticky=W) openBrowserButton = Button(textTopPanel, text="Open Browser", command=self._openBrowser) openBrowserButton.grid(row=0, column=0) self.previewVar = IntVar() previewCheckbutton = Checkbutton(textTopPanel, text="Preview", command=self.updateFile, variable=self.previewVar) previewCheckbutton.grid(row=0, column=1) self.previewVar.set(1) self.statusLabel = Label(textTopPanel) self.statusLabel.grid(row=0, column=2) self.textBox = ScrolledText(textFrame, width=40, height=10) self.textBox.grid(row=1, sticky=N + S + E + W) self.textBox.bind_all('<<Modified>>', self._textboxCallback) propertiesFrame = Frame(textFrame) propertiesFrame.grid(row=2, sticky=E + W) self._makePropertiesFrame(propertiesFrame) layoutFrame = Frame() notebook.add(layoutFrame, text="Layout") layoutTopPanel = Frame(layoutFrame) layoutTopPanel.grid(row=0, sticky=W) getFromClipboardButton = Button(layoutTopPanel, text="Get from clipboard", command=self._getImageFromClipboard) getFromClipboardButton.grid(row=0, column=0) saveButton = Button(layoutTopPanel, text="Save Image", command=self._saveImage) saveButton.grid(row=0, column=1) self.imageLabel = Label(layoutFrame) self.imageLabel.grid(row=1, column=0) self.processedImage = None self.imageLabelPhoto = None # thumbnail def _makePropertiesFrame(self, frame): #Grid.columnconfigure(frame, 0, weight=1) Grid.columnconfigure(frame, 1, weight=1) row = 0 self.textColor = "#ffffff" self.backgroundColor = "#000000" textColorLabel = Label(frame, text="Text color:") textColorLabel.grid(row=row, column=0, sticky=E) self.textColorButton = tkinter.Button(frame, width=5, command=self._pickTextColor) self.textColorButton.grid(row=row, column=1, sticky=W) row += 1 backgroundColorLabel = Label(frame, text="Background color:") backgroundColorLabel.grid(row=row, column=0, sticky=E) self.backgroundColorButton = tkinter.Button( frame, width=5, command=self._pickBackgroundColor) self.backgroundColorButton.grid(row=row, column=1, sticky=W) row += 1 fontLabel = Label(frame, text="Font:") fontLabel.grid(row=row, column=0, sticky=E) self.fontModeVar = StringVar() websafeFontFrame = Frame(frame) websafeFontFrame.grid(row=row, column=1, sticky=W) row += 1 Radiobutton(websafeFontFrame, text="Web Safe:", variable=self.fontModeVar, value="websafe", command=self.updateFile) \ .grid(row=0, column=0) self.websafeFontVar = StringVar() self.websafeFontVar.set(fonts[0]) fontOptionMenu = \ OptionMenu(*([websafeFontFrame, self.websafeFontVar] + fonts)) fontOptionMenu.grid(row=0, column=1) self.websafeFontVar.trace(mode="w", callback=self.updateFile) googleFontFrame = Frame(frame) googleFontFrame.grid(row=row, column=1, sticky=W) row += 1 Radiobutton(googleFontFrame, text="Google:", variable=self.fontModeVar, value="google", command=self.updateFile) \ .grid(row=0, column=0) self.googleFontVar = StringVar() googleFontEntry = Entry(googleFontFrame, width=22, textvariable=self.googleFontVar) googleFontEntry.grid(row=0, column=1) self.googleFontVar.set("") self.googleFontVar.trace(mode="w", callback=self.updateFile) self.fontModeVar.set("websafe") fontSizeLabel = Label(frame, text="Font size:") fontSizeLabel.grid(row=row, column=0, sticky=E) # has to be self. , otherwise it will be garbage collected self.fontSizeVar = StringVar() fontSizeBox = Spinbox(frame, from_=0, to=65536, width=5, textvariable=self.fontSizeVar) fontSizeBox.grid(row=row, column=1, sticky=W) self.fontSizeVar.set('12') self.fontSizeVar.trace(mode="w", callback=self.updateFile) row += 1 letterSpacingLabel = Label(frame, text="Letter spacing:") letterSpacingLabel.grid(row=row, column=0, sticky=E) self.letterSpacingVar = StringVar() letterSpacingBox = Spinbox(frame, from_=-999, to=999, width=5, textvariable=self.letterSpacingVar) letterSpacingBox.grid(row=row, column=1, sticky=W) self.letterSpacingVar.set('0') self.letterSpacingVar.trace(mode="w", callback=self.updateFile) row += 1 wordSpacingLabel = Label(frame, text="Word spacing:") wordSpacingLabel.grid(row=row, column=0, sticky=E) self.wordSpacingVar = StringVar() wordSpacingBox = Spinbox(frame, from_=-999, to=999, width=5, textvariable=self.wordSpacingVar) wordSpacingBox.grid(row=row, column=1, sticky=W) self.wordSpacingVar.set('0') self.wordSpacingVar.trace(mode="w", callback=self.updateFile) row += 1 lineHeightLabel = Label(frame, text="Line height:") lineHeightLabel.grid(row=row, column=0, sticky=E) self.lineHeightVar = StringVar() lineHeightBox = Spinbox(frame, from_=0, to=9999, width=5, textvariable=self.lineHeightVar) lineHeightBox.grid(row=row, column=1, sticky=W) self.lineHeightVar.set('100') self.lineHeightVar.trace(mode="w", callback=self.updateFile) row += 1 paragraphMarginLabel = Label(frame, text="Paragraph break height:") paragraphMarginLabel.grid(row=row, column=0, sticky=E) self.paragraphMarginVar = StringVar() paragraphMarginBox = Spinbox(frame, from_=0, to=9999, width=5, textvariable=self.paragraphMarginVar) paragraphMarginBox.grid(row=row, column=1, sticky=W) self.paragraphMarginVar.set('0') self.paragraphMarginVar.trace(mode="w", callback=self.updateFile) row += 1 wrapWidthLabel = Label(frame, text="Wrap width:") wrapWidthLabel.grid(row=row, column=0, sticky=E) self.wrapWidthVar = StringVar() wrapWidthBox = Spinbox(frame, from_=0, to=9999, width=5, textvariable=self.wrapWidthVar) wrapWidthBox.grid(row=row, column=1, sticky=W) self.wrapWidthVar.set('0') self.wrapWidthVar.trace(mode="w", callback=self.updateFile) row += 1 textAlignLabel = Label(frame, text="Text align:") textAlignLabel.grid(row=row, column=0, sticky=E) self.textAlignVar = StringVar() Radiobutton(frame, text="Left", variable=self.textAlignVar, value="left", command=self.updateFile)\ .grid(row=row, column=1, sticky=W) row += 1 Radiobutton(frame, text="Center", variable=self.textAlignVar, value="center", command=self.updateFile)\ .grid(row=row, column=1, sticky=W) row += 1 Radiobutton(frame, text="Right", variable=self.textAlignVar, value="right", command=self.updateFile)\ .grid(row=row, column=1, sticky=W) row += 1 Radiobutton(frame, text="Justify", variable=self.textAlignVar, value="justify", command=self.updateFile)\ .grid(row=row, column=1, sticky=W) row += 1 self.textAlignVar.set('left') fontWeightLabel = Label(frame, text="Font weight:") fontWeightLabel.grid(row=row, column=0, sticky=E) fontWeightFrame = Frame(frame) fontWeightFrame.grid(row=row, column=1, sticky=W) self.fontWeightVar = StringVar() self.fontWeightBox = Spinbox(fontWeightFrame, from_=1, to=9, width=5, textvariable=self.fontWeightVar) self.fontWeightBox.pack(side=LEFT) self.fontWeightVar.set('4') self.fontWeightVar.trace(mode="w", callback=self.updateFile) fontWeightValuesLabel = Label(fontWeightFrame, text="1 - 9; 4: Normal, 7: Bold") fontWeightValuesLabel.pack(side=LEFT) row += 1 self.italicsVar = IntVar() italicsLabel = Label(frame, text="Italics:") italicsLabel.grid(row=row, column=0, sticky=E) italicsCheckbutton = Checkbutton(frame, command=self.updateFile, variable=self.italicsVar) italicsCheckbutton.grid(row=row, column=1, sticky=W) row += 1 self.underlineVar = IntVar() underlineLabel = Label(frame, text="Underline:") underlineLabel.grid(row=row, column=0, sticky=E) underlineCheckbutton = Checkbutton(frame, command=self.updateFile, variable=self.underlineVar) underlineCheckbutton.grid(row=row, column=1, sticky=W) row += 1 self.strikethroughVar = IntVar() strikethroughLabel = Label(frame, text="Strikethrough:") strikethroughLabel.grid(row=row, column=0, sticky=E) strikethroughCheckbutton = Checkbutton(frame, command=self.updateFile, variable=self.strikethroughVar) strikethroughCheckbutton.grid(row=row, column=1, sticky=W) row += 1 capsModeLabel = Label(frame, text="Caps:") capsModeLabel.grid(row=row, column=0, sticky=E) self.capsModeVar = StringVar() Radiobutton(frame, text="Normal", variable=self.capsModeVar, value="normal", command=self.updateFile) \ .grid(row=row, column=1, sticky=W) row += 1 Radiobutton(frame, text="ALL CAPS", variable=self.capsModeVar, value="upper", command=self.updateFile) \ .grid(row=row, column=1, sticky=W) row += 1 Radiobutton(frame, text="all lowercase", variable=self.capsModeVar, value="lower", command=self.updateFile) \ .grid(row=row, column=1, sticky=W) row += 1 Radiobutton(frame, text="Small Caps", variable=self.capsModeVar, value="small", command=self.updateFile) \ .grid(row=row, column=1, sticky=W) row += 1 self.capsModeVar.set("normal") self.ready = True self.updateFile() def _pickTextColor(self): color = colorchooser.askcolor()[1] if color is not None: self.textColor = color self.updateFile() def _pickBackgroundColor(self): color = colorchooser.askcolor()[1] if color is not None: self.backgroundColor = color self.updateFile() def _openBrowser(self): webbrowser.open(self.file.name) def _textboxCallback(self, *args, **kwargs): self.textBox.edit_modified(0) # allow <<Modified>> event to run again self.updateFile() def updateFile(self, *args, **kwargs): if not self.ready: return # update gui self.textColorButton.configure(background=self.textColor) self.backgroundColorButton.configure(background=self.backgroundColor) try: text = self._generateHTML() except BaseException: self.statusLabel.config(text="ERROR", foreground="#FF0000") return self._writeFile(text) self.statusLabel.config(text="Updated", foreground="#000000") def _generateHTML(self): preview = self.previewVar.get() == 1 fontName = "" fontLink = "" fontMode = self.fontModeVar.get() if fontMode == 'websafe': fontName = self.websafeFontVar.get() elif fontMode == 'google': fontName = self.googleFontVar.get() fontLink = '<link rel="stylesheet" type="text/css" ' \ 'href="https://fonts.googleapis.com/css?family=' \ + (fontName.replace(' ', '+')) + ':' \ + self.fontWeightVar.get() + '00' \ + ('i' if self.italicsVar.get()==1 else '') \ + '">' fontName = "'" + fontName + "'" rules = [ ('*', { 'margin': '0pt', 'padding': '0pt' }), ('body', { 'background-color': self.backgroundColor if preview \ else "#000000" }), ('pre', { 'display': 'table', 'border-style': 'none' if preview else 'solid', 'border-color': "#FF0000", 'border-width': '1px', 'color': self.textColor if preview else "#FFFFFF", 'font-family': fontName, 'font-size': self.fontSizeVar.get() + 'pt', 'letter-spacing': self.letterSpacingVar.get() + 'pt', 'word-spacing': self.wordSpacingVar.get() + 'pt', 'line-height': self.lineHeightVar.get() + '%', 'margin-bottom': self.paragraphMarginVar.get() + 'pt', 'width': 'auto' if float(self.wrapWidthVar.get()) == 0 \ else (self.wrapWidthVar.get() + 'pt'), 'white-space': 'normal' if self.textAlignVar.get() == 'justify'\ else ('pre' if float(self.wrapWidthVar.get()) == 0 else 'pre-wrap'), 'text-align': self.textAlignVar.get(), 'font-weight': int(self.fontWeightVar.get()) * 100, 'font-style': "italic" if self.italicsVar.get()==1 \ else "normal", 'text-decoration': ("underline " if self.underlineVar.get()==1 else "") \ + ("line-through " if self.strikethroughVar.get()==1 else ""), 'font-variant': \ "small-caps" if self.capsModeVar.get() == "small" \ else "normal" }) ] styleStr = generateCSS(rules) htmlStr = \ """<!DOCTYPE html> <html> <head> <meta charset="UTF-8"> {link} <style> {style} </style> </head> <body> <pre> {text} </pre> </body> </html> """ text = self.textBox.get("1.0", END) text = text.rstrip() if self.capsModeVar.get() == "upper": text = text.upper() elif self.capsModeVar.get() == "lower": text = text.lower() text = html.escape(text) text = text.replace('\n\n', '</pre><pre>') text = text.replace('\n', '<br>') htmlStr = htmlStr.format(link=fontLink, style=styleStr, text=text) return htmlStr def _writeFile(self, text): self.file.seek(0) self.file.truncate(0) self.file.write(text) self.file.flush() def _getImageFromClipboard(self): clipboardImage = ImageGrab.grabclipboard() if clipboardImage == None: return self.processedImage = clipboardImage.convert("RGB") bbox = self.processedImage.getbbox() self.processedImage = self.processedImage.crop(bbox) data = self.processedImage.getdata() textColor = struct.unpack('BBB', bytes.fromhex(self.textColor[1:])) newData = bytes() for pixel in data: if pixel == (255, 0, 0): newData += bytes([0, 0, 0, 0]) else: alpha = pixel[0] newData += bytes(textColor + (alpha, )) self.processedImage = \ Image.frombytes("RGBA", (self.processedImage.size), newData) thumbnail = self.processedImage.resize( (384, int(self.processedImage.height / self.processedImage.width * 384.0)), Image.BICUBIC) self.imageLabelPhoto = ImageTk.PhotoImage(thumbnail) self.imageLabel.config(image=self.imageLabelPhoto) def _saveImage(self): if self.processedImage == None: return file = filedialog.asksaveasfile() if file == None: return try: try: self.processedImage.save(file.name) except KeyError as e: self.processedImage.save(file.name + ".png") except BaseException as e: messagebox.showerror("Error saving image!", str(e))