def handle_button_click(self, event): val = self.button_selected.get() - 1 val = self.radio_buttons.index(event.widget) if event.state & 0x001: # Shift key down self.x_flipped[val] = not self.x_flipped[val] try: raise IOError image_file = imget(self.img_lists[val][self.images_selected[val]]) import_image = Image.open(image_file) except IOError: image_file = imget_bdgp(self.img_lists[val][self.images_selected[val]]) import_image = Image.open(image_file) import_image = import_image.resize((180,80), Image.ANTIALIAS) import_image = import_image.rotate(180*self.x_flipped[val]) embryo_image = ImageTk.PhotoImage(import_image) label = Label(image=embryo_image) label.image = embryo_image self.radio_buttons[val].configure( #text=image_file, image=label.image, ) elif event.state & 0x004: # Control key down popup = Menu(root, tearoff=0) popup.add_command(label=self.radio_buttons[val].cget('text')) popup.add_separator() popup.add_command(label="Invert X") popup.add_command(label="Invert Y") try: popup.tk_popup(event.x_root, event.y_root, 0) finally: # make sure to release the grab (Tk 8.0a1 only) popup.grab_release() elif val >= 0: self.images_selected[val] = ((self.images_selected[val] + 2*event.num - 3) % len(self.img_lists[val])) self.x_flipped[val] = False if self.images_selected[val] == 0: stdout.write('\a') stdout.flush() try: raise IOError image_file = imget(self.img_lists[val][self.images_selected[val]]) import_image = Image.open(image_file) except IOError: image_file = imget_bdgp(self.img_lists[val][self.images_selected[val]]) import_image = Image.open(image_file) import_image = import_image.resize((180,80), Image.ANTIALIAS) embryo_image = ImageTk.PhotoImage(import_image) label = Label(image=embryo_image) label.image = embryo_image self.radio_buttons[val].configure( #text=image_file, image=label.image, ) self.image_files[val] = image_file self.button_selected.set(-1)
def _popUp(self, event): row = self.table.identify_row(event.y) #print(row) col = self.table.identify_column(event.x) #print(col) ''' I subtract 1 here because the root column has index zero. In order that the indices of the columnsfrom the tree_view to map with the indices of the column_names, and popup_choices, 1 needs to be subracted. ''' col = int(col.lstrip('#')) - 1 def setChoice(choice): self._sendChoice(self, row, col, choice) popup = Menu(self.root, tearoff=0) if col in self.popup_choices.keys(): choices = self.popup_choices[col] for i, j in enumerate(choices): '''This line below is a bit tricky. Needs to be done this way because the i in the loop is only scoped for the loop, and does not persist.''' popup.add_command( command=lambda choice=choices[i]: setChoice(choice), label=j) try: popup.tk_popup(event.x_root, event.y_root, 0) finally: popup.grab_release()
class FancyListbox(Listbox): def __init__(self, parent, popup_menu=True, *args, **kwargs): Listbox.__init__(self, parent, *args, **kwargs) self.popup_menu = popup_menu if self.popup_menu: self.popup_menu = Menu(self, tearoff=0) self.popup_menu.add_command(label="Add to user words", command=self.add_user_word) self.bind("<Button-3>", self.popup) # self.entry_box = Entry(self, bg='PaleGreen1') # self.entry_box.pack() self.pack(side='top') self.bind('<ButtonRelease-1>', self.get_list_element) # @classmethod def get_list_element(self): vw = self.yview() # get selected line index if self.curselection(): index = self.curselection()[0] # get the line's text # delete previous text in enter1 # entry.delete(0, 100) # # # now display the selected text # entry.insert(0, text) self.yview_moveto(vw[0]) print(self.get(index)) self.last_entry = self.get(index) def set_list(self, entry, event): """ insert an edited line from the entry widget back into the listbox """ vw = self.yview() index = self.curselection()[0] # delete old listbox line self.delete(index) # insert edited item back into listbox1 at index self.insert(index, entry) self.yview_moveto(vw[0]) def popup(self, event): try: self.popup_menu.tk_popup(event.x_root, event.y_root, 0) finally: self.popup_menu.grab_release() def add_user_word(self): with open(global_vars.path_root_UI + '/user_words.txt', 'a', encoding='UTF-8') as f: f.write(self.get(self.curselection()) + '\n')
def show(self, event: Event, parent: Tk = None, **kwargs) -> bool: menu = Menu(parent, tearoff=0) added_any = False for option in self._options: added_any |= option.maybe_add(menu, kwargs) if added_any: try: menu.tk_popup(event.x_root, event.y_root) # noqa finally: menu.grab_release() return added_any
def pop(self, event): popup = Menu(self.root, tearoff=0) def setChoice(choice): self.callback(choice) for c in self.choices: '''This line below is a bit tricky. Needs to be done this way because the i in the loop is only scoped for the loop, and does not persist.''' popup.add_command(command=lambda choice=c: setChoice(choice), label=c) try: popup.tk_popup(event.x_root, event.y_root, 0) finally: popup.grab_release() return self.choice
def _on_rightClick(self, event): """ create popup; delete message or copy text """ popup = Menu(self.msg_box, tearoff=False, font=("New Times Roman", 9, "bold"), activebackground="DeepSkyBlue3") popup.add_separator() popup.add_command(label="Copy text", command=lambda: self.copy_text(e=event)) popup.add_separator() popup.add_command(label="Delete for me", command=self.delete) popup.add_separator() try: popup.tk_popup(event.x_root - 10, event.y_root + 30, 0) except Exception: pass finally: popup.grab_release()
class Interface(Frame): def __init__(self, master=None, *_): Frame.__init__(self, master) self.master = master # settings variables self.word_wrap = BooleanVar() self.word_wrap.set(True) self.__show_status_bar = BooleanVar() self.__show_status_bar.set(True) self.fnt = font.Font(family="Courier New", size=10) self.find_open = False self.replace_open = False self.goto_open = False self.prior_search = '' self.prior_goto = '' # init methods self.__init_main_window() self.__build_status_bar() self.__build_menu_bar() self.__bind_shortcuts() self.toggle_word_wrap() self.context_menu = Menu(self.master, tearoff=0) self.last_hash = get_signature(self.text_area.get(1.0, END)) def __init_main_window(self): self.text_area = Text(self.master, undo=True) self.text_area.config(font=self.fnt, wrap=WORD) # To add scrollbar self.scroll_bar_x = Scrollbar(self.master, orient=HORIZONTAL) self.scroll_bar_y = Scrollbar(self.master, orient=VERTICAL) __file = None try: self.master.wm_iconbitmap('notepad.ico') except TclError: log.error("unable to set icon to notepad.ico") pass # Set the window text self.master.title('Untitled - Notepad') # To make the text area auto resizable self.master.grid_rowconfigure(0, weight=1) self.master.grid_columnconfigure(0, weight=1) self.text_area.grid(column=0, row=0, sticky='nsew') self.scroll_bar_y.grid(column=1, row=0, sticky='nsew') self.scroll_bar_x.grid(column=0, row=1, stic='nsew') # Scrollbar will adjust automatically according to the content self.scroll_bar_x.config(command=self.text_area.xview) self.scroll_bar_y.config(command=self.text_area.yview) self.text_area.config(xscrollcommand=self.scroll_bar_x.set, yscrollcommand=self.scroll_bar_y.set) self.text_area.focus() def __build_menu_bar(self): # main and submenus self.menu_bar = Menu(self.master) self.file_menu = Menu(self.menu_bar, tearoff=0) self.edit_menu = Menu(self.menu_bar, tearoff=0) self.format_menu = Menu(self.menu_bar, tearoff=0) self.thisViewMenu = Menu(self.menu_bar, tearoff=0) self.help_menu = Menu(self.menu_bar, tearoff=0) # File Menu self.menu_bar.add_cascade(label='File', underline=0, menu=self.file_menu) self.file_menu.add_command(label='New', underline=0, accelerator='Ctrl+N', command=new_file) self.file_menu.add_command(label='Open...', underline=0, accelerator='Ctrl+O', command=open_file) self.file_menu.add_command(label='Save', underline=0, accelerator='Ctrl+S', command=save_file) self.file_menu.add_command(label='Save As...', underline=5, command=save_file_as) self.file_menu.add_separator() self.file_menu.add_command(label='Page Setup...', underline=5, accelerator='Ctrl+S', command=save_file) self.file_menu.add_command(label='Print', underline=0, accelerator='Ctrl+P', command=save_file) self.file_menu.add_separator() self.file_menu.add_command(label='Exit', underline=1, command=self.quit_application) # Edit Menu self.menu_bar.add_cascade(label='Edit', underline=0, menu=self.edit_menu) self.edit_menu.add_command(label='Undo', underline=0, accelerator='Ctrl+Z', command=self.undo) self.edit_menu.add_separator() self.edit_menu.add_command(label='Cut', underline=2, accelerator='Ctrl+X', command=self.cut) self.edit_menu.add_command(label='Copy', underline=0, accelerator='Ctrl+C', command=self.copy) self.edit_menu.add_command(label='Paste', underline=0, accelerator='Ctrl+V', command=self.paste) self.edit_menu.add_command(label='Delete', underline=2, accelerator='Del', command=self.delete) self.edit_menu.add_command(label='Search with Bing... ', underline=0, accelerator='Ctrl+B', command=self.search_selected_text) self.edit_menu.add_separator() self.edit_menu.add_command(label='Find...', underline=0, accelerator='Ctrl+F', command=self.show_find) self.edit_menu.add_command(label='Find Next', underline=5, accelerator='F3', command=self.find_next) self.edit_menu.add_command(label='Replace...', underline=0, accelerator='Ctrl+H', command=self.show_find_replace) self.edit_menu.add_command(label='Go To...', underline=0, accelerator='Ctrl+G', command=self.show_goto) self.edit_menu.add_separator() self.edit_menu.add_command(label='Select All', underline=7, accelerator='Ctrl+A', command=lambda: self.select_all()) self.edit_menu.add_command(label='Time/Date', underline=5, accelerator='F5', command=self.time_date) # Format Menu self.menu_bar.add_cascade(label='Format', underline=0, menu=self.format_menu) self.format_menu.add_checkbutton(label='Word Wrap', underline=0, variable=self.word_wrap, command=self.toggle_word_wrap) self.format_menu.add_command(label='Font...', underline=0, command=self.set_font) # View Menu self.menu_bar.add_cascade(label='View', underline=1, menu=self.thisViewMenu) self.thisViewMenu.add_checkbutton(label='Status Bar', underline=0, variable=self.__show_status_bar, command=self.toggle_status_bar) # Help Menu self.menu_bar.add_cascade(label='Help', underline=0, menu=self.help_menu) self.help_menu.add_command(label='View Help', underline=5, command=self.get_help) self.help_menu.add_separator() self.help_menu.add_command(label='About Notepad', underline=0, command=show_about) self.master.config(menu=self.menu_bar) def show_context_menu(self, event): try: self.context_menu = Menu(self.master, tearoff=0) self.context_menu.add_command(label='Undo', underline=2, accelerator='Ctrl+Z', command=self.undo) self.context_menu.add_separator() self.context_menu.add_command(label='Cut', underline=2, accelerator='Ctrl+X', command=self.cut) self.context_menu.add_command(label='Copy', underline=0, accelerator='Ctrl+C', command=self.copy) self.context_menu.add_command(label='Paste', underline=0, accelerator='Ctrl+V', command=self.paste) self.context_menu.add_command(label='Delete', underline=2, accelerator='Del', command=self.delete) self.context_menu.add_separator() self.context_menu.add_command(label='Select All', underline=2, accelerator='Ctrl+A', command=self.select_all) self.context_menu.add_separator() self.context_menu.add_command(label='Search with Bing... ', underline=0, accelerator='Ctrl+B', command=self.search_selected_text) self.context_menu.tk_popup(event.x_root, event.y_root) finally: self.context_menu.grab_release() def set_font(self): fnt = fontpicker.ask_font(family=self.fnt.actual(option='family'), size=self.fnt.actual(option='size'), weight=self.fnt.actual(option='weight'), slant=self.fnt.actual(option='slant')) if fnt: self.fnt = font.Font(family=fnt['family'], size=int(fnt['size']), weight=fnt['weight'], slant=fnt['slant']) self.text_area.config(font=self.fnt) def __build_status_bar(self): self.status_bar = Label(self.master, text="Ln 1, Col 1\t", bd=1, relief=SUNKEN, anchor='e') self.toggle_status_bar() def toggle_status_bar(self): if self.__show_status_bar.get(): self.status_bar.grid(sticky='sew') else: self.status_bar.grid_forget() def toggle_word_wrap(self): if self.word_wrap.get(): self.text_area.config(wrap=WORD) self.scroll_bar_x.grid_forget() log.info("word wrap on, scroll bar off") else: self.text_area.config(wrap=NONE) self.scroll_bar_x.grid(column=0, row=1, sticky='nsew') log.info("word wrap off, scroll bar on") def __bind_shortcuts(self): self.master.bind_class('Text', '<Control-a>', self.select_all) self.master.bind_class('Text', '<Control-A>', self.select_all) self.master.bind_class('Text', '<Control-s>', save_file) self.master.bind_class('Text', '<Control-S>', save_file) self.master.bind_class('Text', '<Control-n>', new_file) self.master.bind_class('Text', '<Control-N>', new_file) self.master.bind_class('Text', '<Control-b>', self.search_selected_text) self.master.bind_class('Text', '<Control-B>', self.search_selected_text) self.master.bind_class('Text', '<Control-f>', self.show_find) self.master.bind_class('Text', '<Control-F>', self.show_find) self.master.bind_class('Text', '<Control-h>', self.show_find_replace) self.master.bind_class('Text', '<Control-H>', self.show_find_replace) self.master.bind_class('Text', '<Control-g>', self.show_goto) self.master.bind_class('Text', '<Control-G>', self.show_goto) self.master.bind_class('Text', '<F5>', self.time_date) self.master.bind_class('Text', '<F3>', self.find_next) self.text_area.bind_class(self.text_area, '<Any-KeyPress>', self.on_key) self.text_area.bind_class(self.text_area, '<Button-1>', self.on_click) self.text_area.bind_class(self.text_area, '<Button-3>', self.show_context_menu) def quit_application(self): if notepad.has_changed(): save_box = messagebox.askquestion( 'Confirm save', 'Do you want to save before closing this file?', icon='warning') if save_box == 'yes': save_file() self.master.destroy() exit() def undo(self, *_): self.text_area.event_generate('<<Undo>>') def on_key(self, *_): self.update_status_bar(INSERT) def on_click(self, *_): self.update_status_bar(CURRENT) try: self.context_menu.destroy() except AttributeError: log.warning( 'error occurred while trying to exit context menu, probably not instansiated' ) def update_status_bar(self, obj): row, col = self.text_area.index(obj).split('.') self.status_bar.config(text=str('Ln ' + row + ', Col ' + col + ' \t')) def cut(self, *_): self.text_area.event_generate('<<Cut>>') def copy(self, *_): self.text_area.event_generate('<<Copy>>') def paste(self, *_): self.text_area.event_generate('<<Paste>>') def select_all(self, *_): self.text_area.tag_add('sel', '1.0', 'end') def delete(self, *_): self.text_area.event_generate('<Delete>') def search_selected_text(self, *_): try: s = self.text_area.selection_get() if s is not None: search_with_bing(s) else: log.debug('selection was empty, not searching with bing') except TclError: print('TclError - Probably because nothing was selected ') def time_date(self, *_): now = datetime.now() s = now.strftime("%I:%M %p %m/%d/%Y") self.text_area.insert(INSERT, s) def show_find(self, *_): if not self.find_open: self.find_open = True FindWindow(master=self) def show_find_replace(self, *_): if not self.replace_open: self.replace_open = True FindReplaceWindow(master=self) def show_goto(self, *_): if not self.goto_open: self.goto_open = True GotoWindow(master=self) @staticmethod def get_help(): search_with_bing("get+help+with+notepad+in+windows+10") def run(self): # Run main application self.master.mainloop() def set_title(self, string): self.master.title(string + ' - Notepad') def clear_text(self): self.text_area.delete(1.0, END) def get_text(self): return self.text_area.get(1.0, END) def write_text(self, text, start_index=1.0): self.text_area.insert(start_index, text) def find_next(self, _): search_string = self.prior_search location = self.text_area.search(search_string, self.text_area.index(INSERT), nocase=True) log.info('searching next -- forwards') if location != '': log.info('found ' + search_string + ' at position ' + location) row, col = get_index(location) end_col = str(col + len(search_string)) end_location = str(str(row) + '.' + end_col) self.text_area.mark_set("insert", end_location) self.text_area.see("insert") self.text_area.tag_remove('sel', "1.0", END) self.text_area.tag_raise("sel") self.text_area.tag_add('sel', location, end_location) self.text_area.focus() else: log.warning(search_string + 'string not found') def has_changed(self): if get_signature(self.text_area.get(1.0, END)) == self.last_hash: log.info('file has changed') return False else: log.info('file has not changed') return True
class Main(Frame): def __init__(self, window, *args, **kwargs): Frame.__init__(self, window, *args, **kwargs) self.window = window self.window.title("YouTube Downloader") self.window.rowconfigure(0, weigh=1) self.window.columnconfigure(0, weight=1) self.format_tuple = () self.step = 0 self.bytes = 0 self.max_bytes = 0 # Create a Queue self.guiQueue = queue.Queue() self.create_widgets() self.path = os.path.abspath(os.getcwd()) def create_widgets(self): # Variables self.url_var = tk.StringVar() # self.url_var.trace_add('write', self.populate_format) self.save_to_var = tk.StringVar() self.format_var = tk.StringVar() self.format_var.trace_add('write', self.check_audio) self.includes_var = tk.StringVar() self.percent_var = tk.StringVar() self.bar_var = tk.IntVar() self.convert_var = tk.StringVar() # Create popup menu for Copy/Paste self.m = Menu(self.window, tearoff=0) self.m.add_command(label="Cut") self.m.add_command(label="Copy") self.m.add_command(label="Paste") # Main frame self.main_frame = tk.Frame(self.window) self.main_frame.grid(column=0, row=0, sticky='wne', padx=10, pady=10) self.main_frame.rowconfigure(2, weight=1) self.main_frame.columnconfigure(0, weight=1) self.main_frame.columnconfigure(1, weight=1) self.url_frame = ttk.Frame(self.main_frame) self.url_frame.grid(column=0, row=0, columnspan=2, sticky='enw') self.url_frame.columnconfigure(1, weight=1) self.url_label = ttk.Label(self.url_frame, text="URL") self.url_label.grid(column=0, row=0, sticky='w') self.url_entry = ttk.Entry(self.url_frame, textvariable=self.url_var) self.url_entry.grid(column=1, row=0, sticky='ew') self.save_to_button = ttk.Button(self.url_frame, text="Save To", command=self.save_to) self.save_to_button.grid(column=0, row=1, sticky='w') self.save_to_entry = ttk.Entry(self.url_frame, textvariable=self.save_to_var) self.save_to_entry.grid(column=1, row=1, sticky='ew') self.download_frame = tk.Frame(self.main_frame) self.download_frame.columnconfigure(2, weight=1) self.download_frame.columnconfigure(3, weight=1) # self.download_frame.columnconfigure(1, weight=1) self.download_frame.grid(column=0, row=1, columnspan=2, pady=5, sticky='ew') self.load_url = ttk.Button(self.download_frame, text="Load URL", command=self.populate_format) self.load_url.grid(column=0, row=0, ipady=10) self.format_combo = ttk.Combobox(self.download_frame, textvariable=self.format_var) self.format_combo.grid(column=1, row=0, padx=10) self.includes_audio = ttk.Label(self.download_frame, textvariable=self.includes_var, width=20) self.includes_audio.grid(column=2, row=0, padx=10) self.download_button = ttk.Button(self.download_frame, text="Download Video", command=self.download_video) self.download_button.grid(column=3, row=0, ipadx=30, ipady=10, sticky='e') self.download_label = ttk.Label(self.download_frame, textvariable=self.percent_var) self.download_label.grid(column=0, row=1, sticky='ew', columnspan=4) self.download_bar = ttk.Progressbar(self.download_frame, orient=tk.HORIZONTAL, mode='determinate', variable=self.bar_var) self.download_bar.grid(column=0, row=2, columnspan=4, sticky='ew', pady=10) # create a Treeview self.tree = ttk.Treeview(self.main_frame, show='headings', columns=('Name', 'Format', 'Size', 'Resolution')) self.tree.grid(column=0, row=2, columnspan=2, sticky='wne') self.tree.bind('<<TreeviewSelect>>', self.file_to_convert) self.tree.column('Name', width=250, anchor='center') self.tree.heading('Name', text='Name') self.tree.column('Format', width=30, anchor='center') self.tree.heading('Format', text='Format') self.tree.column('Size', width=70, anchor='center') self.tree.heading('Size', text='Size') self.tree.column('Resolution', width=70, anchor='center') self.tree.heading('Resolution', text='Resolution') self.check_platform() self.convert_frame = ttk.Frame(self.main_frame) self.convert_frame.grid(column=0, row=3, columnspan=2, sticky='ew') # self.convert_frame.columnconfigure(0, weight=1) self.convert_frame.columnconfigure(2, weight=1) # self.convert_frame.columnconfigure(2, weight=1) # self.convert_frame.columnconfigure(2, weight=1) self.file_label = ttk.Label(self.convert_frame, text="File name") self.file_label.grid(column=0, row=0) self.convert_entry = ttk.Entry(self.convert_frame, textvariable=self.convert_var) self.convert_entry.grid(column=1, row=0, sticky='ew') self.convert_progress = ttk.Progressbar(self.convert_frame, orient=tk.HORIZONTAL, mode='indeterminate') self.convert_progress.grid(column=2, row=0, ipadx=10, sticky='ew') self.convert_button = ttk.Button(self.convert_frame, text="Convert Audio", command=self.convert_video) self.convert_button.grid(column=3, row=0, ipadx=30, ipady=10, sticky='e') def save_to(self): file_path = filedialog.askdirectory() self.save_to_var.set(file_path) self.path = self.save_to_var.get() def popup(self, event): try: self.m.entryconfig( "Cut", command=lambda: event.widget.event_generate("<<Cut>>")) self.m.entryconfig( "Copy", command=lambda: event.widget.event_generate("<<Copy>>")) self.m.entryconfig( "Paste", command=lambda: event.widget.event_generate("<<Paste>>")) self.m.tk.call("tk_popup", self.m, event.x_root, event.y_root) finally: self.m.grab_release() def check_platform(self): plt = platform.system() if plt == "Windows": print("Your system is Windows") self.url_entry.bind("<Button-3>", self.popup) self.save_to_entry.bind("<Button-3>", self.popup) elif plt == "Linux": print("Your system is Linux") self.url_entry.bind("<Button-3>", self.popup) self.save_to_entry.bind("<Button-3>", self.popup) elif plt == "Darwin": print("Your system is MacOS") self.url_entry.bind("<Button-2>", self.popup) self.save_to_entry.bind("<Button-2>", self.popup) else: print("Unidentified system") mBox.showinfo("Copy/Paste functionality not working.") def file_to_convert(self, *args): # Reset the convert progressbar if used before self.convert_progress.stop() item = self.tree.focus() item = self.tree.item(item) self.video_file = item['text'] title_file = item['values'][0] self.convert_var.set(title_file) def convert_video(self, *args): if len(self.convert_var.get()) > 0: try: from pydub import AudioSegment print("Alabama", self.video_file) if os.path.isfile(self.video_file): self.convert_progress.start() self.convert_progress.step(10) self.convert_progress.update_idletasks() audio = AudioSegment.from_file(self.video_file) new_file = self.video_file.replace("mp4", "mp3") audio.export(new_file, format="mp3", codec="libmp3lame") # self.convert_progress.stop() # mBox.showinfo("Convert to MP3", "The video has been converted from MP4 to MP3.") else: mBox.showerror( "Convert to MP3", "The file to convert doesn't exists!\nPlease check the folder for the actual file!" ) except: mBox.showerror("Convert to MP3", "The conversion to MP3 failed!") else: mBox.showwarning( "Convert to MP3", "No file selected from the list to be converted!") def check_audio(self, *args): """ Check is current stream has audio""" if self.yt.streams[self.format_combo.current()].includes_audio_track: self.includes_var.set("Video includes audio? Yes") else: self.includes_var.set("Video includes audio? No") def download_video(self): if len(self.url_entry.get()) > 0: self.stream = self.yt.streams[self.format_combo.current()] # Set progress bar's maximum to video size self.max_bytes = self.stream.filesize self.download_bar['maximum'] = 100 self.download_bar['value'] = self.step self.t1 = threading.Thread(target=self.fill_bar, args=[]) self.t1.start() else: mBox.showwarning( "URL Error", "You have not entered an Url.\nPlease enter a valid YouTuber Url to download a video." ) def populate_format(self, *args): """ Get the streams from URL, filter only the mp4 streams, extract the resolution and fps. Populate the combo box with the extracted values. """ # TODO extract everything in a different thread # Reset the convert progressbar if used before self.convert_progress.stop() self.format_combo['values'] = () try: self.yt = YouTube(self.url_entry.get(), on_progress_callback=self.progress_bar, on_complete_callback=self.insert_tree) for stream in self.yt.streams.filter(subtype="mp4"): if stream.includes_video_track: self.format_tuple += (str(stream.mime_type) + " " + str(stream.resolution) + " " + str(stream.fps) + "fps", ) except exceptions.VideoUnavailable as videoUnavailable: mBox.showerror( "Error", "Something wrong happened!\nError on line {}".format( sys.exc_info()[-1].tb_lineno) + ". " + str(videoUnavailable.__doc__)) except exceptions.RegexMatchError as regexError: mBox.showerror( "Error", "Something wrong happened!\nError on line {}".format( sys.exc_info()[-1].tb_lineno) + ". " + str(regexError.__doc__)) except exceptions.HTMLParseError as htmlParseError: mBox.showerror( "Error", "Something wrong happened!\nError on line {}".format( sys.exc_info()[-1].tb_lineno) + ". " + str(htmlParseError.__doc__)) except exceptions.ExtractError as extractError: mBox.showerror( "Error", "Something wrong happened!\nError on line {}".format( sys.exc_info()[-1].tb_lineno) + ". " + str(extractError.__doc__)) except exceptions.PytubeError as pytubeError: mBox.showerror( "Error", "Something wrong happened!\nError on line {}".format( sys.exc_info()[-1].tb_lineno) + ". " + str(pytubeError.__doc__)) except KeyError as io: mBox.showerror( "Error", "Something wrong happened!\nError on line {}".format( sys.exc_info()[-1].tb_lineno) + ". " + str(io.__doc__) + " " + str(io)) except: mBox.showerror("Error", "Something wrong happened!") if len(self.format_tuple) > 0: self.format_combo['values'] = self.format_tuple self.format_combo.current(0) self.check_audio() def progress_bar(self, chunk, file_handle, bytes_remaining): remaining = (100 * bytes_remaining) / self.max_bytes self.step = 100 - int(remaining) self.guiQueue.put(self.step) self.window.after(1000, self.listen_result) def fill_bar(self): if len(self.save_to_var.get()) > 0: self.path = self.save_to_var.get() if os.path.isfile(self.path + "/" + str(self.format_combo.current()) + "_" + self.stream.default_filename): mBox.showerror("Download error", "This file already exists!\nPlease check again!") elif not os.path.isdir(self.path): mBox.showerror( "Download error", "The selected path does not exists!\nPlease check again!") else: self.stream.download( output_path=self.path, filename_prefix=str(self.format_combo.current()) + "_") def listen_result(self): try: self.step = self.guiQueue.get_nowait() self.bar_var.set(self.step) self.percent_var.set("Downloading... " + str(self.step) + "%") self.window.after(1000, self.listen_result) except queue.Empty: # self.window.after(100, self.listen_result) pass def insert_tree(self, *args): """ Insert details of downloaded video into the tree. """ self.percent_var.set("Downloading... " + str(self.step) + "% Completed!") iid = self.path + "/" + str( self.format_combo.current()) + "_" + self.stream.default_filename name = str( self.format_combo.current()) + "_" + self.stream.default_filename video_format = "mp4" size = str(round(self.stream.filesize * 0.000001, 1)) + "MB" resolution = self.set_resolution() try: self.tree.insert('', 'end', iid=iid, text=iid, values=(name, video_format, size, resolution)) except TclError as err: mBox.showerror( "Download error", "Error after download!\nError on line {}".format( sys.exc_info()[-1].tb_lineno) + ". " + str(err)) def set_resolution(self): """ Label the resolution of the video """ if self.stream.resolution == "2160p": return "3840x2160" elif self.stream.resolution == "1440p": return "2560x1440" elif self.stream.resolution == "1080p": return "1920x1080" elif self.stream.resolution == "720p": return "1280x720" elif self.stream.resolution == "480p": return "854x480" elif self.stream.resolution == "360p": return "640x360" elif self.stream.resolution == "240p": return "426x240" elif self.stream.resolution == "144p": return "256x144" else: return "No resolution detected"
class CrawlTab(ttk.Frame): def __init__(self, root, crawler=None, freeze_tabs=None, unfreeze_tabs=None): ttk.Frame.__init__(self) self.root = root self.crawler = crawler self.lock = crawler.lock self.freeze_tabs = freeze_tabs self.unfreeze_tabs = unfreeze_tabs self.topframe = ttk.Frame(self) self.topframe.pack(anchor='center', padx=20, pady=20, fill="x") self.entry_url_input = EnhancedEntry(self.topframe, 'Enter URL to crawl') self.entry_url_input.entry.bind('<Return>', self.enter_hit) self.button_crawl = ttk.Button(self.topframe, text="Start", command=self.btn_crawl_pushed) self.button_crawl.pack(side=LEFT, padx=(0, 20)) self.button_clear = ttk.Button(self.topframe, text="Clear", command=self.btn_clear_pushed) self.button_clear.pack(side=LEFT, padx=(0, 20)) self.button_clear['state'] = 'disabled' # macOS and linux have issues with the below style so only use it on # windows for now if sys.platform != "win32": self.progressbar = ttk.Progressbar(self.topframe, orient="horizontal", length=150, mode="determinate", maximum=100, value=0) elif sys.platform == "win32": self.style = ttk.Style(self) self.style.layout( 'text.Horizontal.TProgressbar', [('Horizontal.Progressbar.trough', { 'children': [('Horizontal.Progressbar.pbar', { 'side': 'left', 'sticky': 'ns' })], 'sticky': 'nswe' }), ('Horizontal.Progressbar.label', { 'sticky': '' })]) self.style.configure('text.Horizontal.TProgressbar', text='0 %') self.progressbar = ttk.Progressbar( self.topframe, orient="horizontal", length=150, mode="determinate", maximum=100, value=0, style='text.Horizontal.TProgressbar') self.progressbar.pack(side=LEFT, fill="x") self.middle_frame = ttk.Frame(self) self.middle_frame.pack(anchor='center', fill='both', expand=True) self.treeview_table = ttk.Treeview(self.middle_frame, selectmode="browse") # Capture right clicks on table right_click = '<Button-3>' if sys.platform == 'darwin': right_click = '<Button-2>' self.treeview_table.bind(right_click, self.assign_treeview_click) self.scrollbar_vertical = ttk.Scrollbar( self.middle_frame, orient="vertical", command=self.vertical_scrollbar_clicked) self.scrollbar_vertical.pack(side="right", fill="y") self.scrollbar_horizontal = ttk.Scrollbar( self.middle_frame, orient="horizontal", command=self.treeview_table.xview) self.scrollbar_horizontal.pack(side="bottom", fill="x") self.treeview_table.configure( yscrollcommand=self.scrollbar_vertical.set, xscrollcommand=self.scrollbar_horizontal.set) self.treeview_table.pack(fill="both", expand=1) self.bottom_frame = ttk.Frame(self) self.bottom_frame.pack(anchor='center', padx=5, pady=5, fill='x') self.urls_string_var = StringVar() self.urls_string_var.set("Speed: - URL/s") self.label_urls_per_second = ttk.Label( self.bottom_frame, textvariable=self.urls_string_var) self.label_urls_per_second.pack(side=LEFT) self.urls_crawled_string_var = StringVar() self.urls_crawled_string_var.set("URLs crawled/discovered: 0/0 (0%)") self.label_urls_crawled = ttk.Label( self.bottom_frame, textvariable=self.urls_crawled_string_var) self.label_urls_crawled.pack(side=RIGHT) self.percentage = 0 self.populate_columns() self.row_counter = 1 # pop up menu for treeview header items self.popup_menu = Menu(self, tearoff=0) self.popup_menu.add_command(label='Reset Filters', command=self.reset_filters) self.popup_menu.add_separator() labels = Defaults.popup_menu_labels generate_menu(self.popup_menu, labels, self.show_filter_window) self.selected_column = '' self.filter_window = None # action menu for treeview row items self.action_menu = Menu(self, tearoff=0) labels = ['Copy URL', 'Open URL in Browser', '_', 'View Inlinks'] generate_menu(self.action_menu, labels, self.show_action_window) self.row_values = [] self.suspend_auto_scroll = False self.viewed_table = 'crawl' self.filters = [] def clear_output_table(self): # Clear table self.treeview_table.delete(*self.treeview_table.get_children()) self.row_counter = 1 def get_display_columns(self, table=None): if not table: if self.crawler.columns: return self.crawler.columns.copy() return Defaults.display_columns.copy() return self.crawler.get_columns(table) def populate_columns(self, columns=None): column_default_width = 80 column_url_width = 700 column_titles_width = 250 display_column_mapping = { 'url': ('URL', column_url_width), 'redirect_url': ('Redirect URL', column_url_width), 'canonical_tag': ('Canonical Tag', column_url_width), 'content_type': ('Content Type', 100), 'h1': ('H1', column_titles_width), 'page_title': ('Page Title', column_titles_width), 'url_from': ('URL From', column_url_width), 'url_to': ('URL To', column_url_width) } if not columns: columns = self.get_display_columns() self.treeview_table["columns"] = tuple(columns) self.treeview_table.heading("#0", text="id", anchor=W) self.treeview_table.column("#0", width=55, stretch=False) for e in self.treeview_table["columns"]: name, width = display_column_mapping.get(e, (None, None)) if not name: name = e.replace('_', ' ').title() width = column_default_width self.treeview_table.heading(e, text=name, anchor=W) self.treeview_table.column(e, width=width, stretch=False) def enter_hit(self, event=None): self.btn_crawl_pushed() def start_new_crawl(self, url): files = [('Greenflare DB', f'*{Defaults.file_extension}'), ('All files', '.*')] db_file = fd.asksaveasfilename(filetypes=files) if db_file: if not db_file.endswith(Defaults.file_extension): db_file += Defaults.file_extension if path.isfile(db_file): remove(db_file) self.crawler.reset_crawl() self.run_first_time = False self.crawler.db_file = db_file self.crawler.settings["STARTING_URL"] = url self.entry_url_input.entry["state"] = "disabled" self.crawler.start_crawl() self.clear_output_table() self.populate_columns() self.master.title( f"{self.crawler.gf.get_domain(self.crawler.settings['STARTING_URL'])} - {Defaults.window_title}" ) self.after(10, self.add_to_outputtable) self.after(10, self.update_buttons) @run_in_background_with_window([], title='Stopping crawl ...', msg='Waiting for crawl to finish ...') def stop_crawl(self): self.crawler.end_crawl_gracefully() self.after(10, self.update_buttons) def btn_crawl_pushed(self): url = self.entry_url_input.get().strip() if self.button_crawl["text"] == "Start": # Validate input url url_components = self.crawler.gf.parse_url(url) if self.crawler.settings.get('MODE', '') == 'Spider': if url_components['scheme'] == '': url = 'http://' + url url_components = self.crawler.gf.parse_url(url) if url_components['netloc'] == '' or ' ' in url_components[ 'netloc']: messagebox.showerror(title='Invalid URL', message='Please enter a valid URL!') return url = self.crawler.gf.url_components_to_str(url_components) self.entry_url_input.entry.delete(0, 'end') self.entry_url_input.entry.insert(0, url) self.start_new_crawl(url) elif self.button_crawl["text"] == "Pause": self.stop_crawl() elif self.button_crawl["text"] == "Resume": self.populate_columns() self.crawler.resume_crawl() self.row_counter = self.crawler.urls_crawled + 1 self.after(10, self.add_to_outputtable) self.after(10, self.update_buttons) elif self.button_crawl["text"] == "Restart": self.start_new_crawl(url) print(self.crawler.settings) def update_buttons(self): btn_txt = self.button_crawl["text"] if btn_txt == "Start": self.button_crawl["text"] = "Pause" self.button_clear['state'] = 'disabled' self.freeze_tabs() elif btn_txt == "Pause": self.button_crawl["text"] = "Resume" self.button_clear['state'] = 'enabled' self.unfreeze_tabs() elif btn_txt == "Resume": self.button_crawl["text"] = "Pause" self.button_clear['state'] = 'enabled' self.freeze_tabs() elif btn_txt == "Restart": self.button_crawl["text"] = "Pause" self.button_clear['state'] = 'enabled' def btn_clear_pushed(self): msg = messagebox.askquestion( 'Clear View', 'Are you sure you want clear the view? All data has been saved.', icon='warning') if msg == 'yes': self.reset(reset_url_input=False) else: return def add_item_to_outputtable(self, item): self.treeview_table.insert('', 'end', text=self.row_counter, values=item) with self.lock: self.row_counter += 1 # Allow user to scroll up and only continue autoscroll if the # scroll bar is near the bottom edge if not self.suspend_auto_scroll: self.treeview_table.yview_moveto(1) def add_to_outputtable(self): items = [] with self.lock: if self.crawler.gui_url_queue: items = self.crawler.gui_url_queue.copy() self.crawler.gui_url_queue = [] if len(items) > 0: for item in items: self.add_item_to_outputtable(item) self.update_progressbar() self.update_bottom_stats() if self.crawler.crawl_completed.is_set(): self.button_crawl["text"] = "Restart" self.unfreeze_tabs() self.button_clear['state'] = 'enabled' if self.crawler.settings.get("MODE", "") == "Spider": messagebox.showinfo( title='Crawl completed', message= f'{self.crawler.settings.get("ROOT_DOMAIN", "")} has been crawled successfully!' ) else: messagebox.showinfo( title='Crawl completed', message='List Mode Crawl has been completed successfully!') self.update_bottom_stats() return if self.crawler.crawl_timed_out.is_set(): messagebox.showerror(title='Error - Timed Out', message='Crawl timed out!') self.button_crawl["text"] = "Resume" self.button_clear['state'] = 'enabled' self.update_bottom_stats() return if self.crawler.crawl_running.is_set(): self.update_bottom_stats() return self.after(250, self.add_to_outputtable) @tk_after def add_items(self, items): for i, item in enumerate(items, 1): self.treeview_table.insert('', 'end', text=i, values=item) @run_in_background_with_window( [], title='Loading crawl ...', msg='Please wait while the data is being loaded ...') def load_crawl_to_outputtable(self, filters, table, columns=None): self.suspend_auto_scroll = True if not filters: self.master.title(self.master.title().replace( ' (Filtered View)', '')) if not table: table = self.viewed_table self.clear_output_table() columns, items = self.crawler.get_crawl_data(filters, table, columns) self.populate_columns(columns=columns) self.add_items(items) self.suspend_auto_scroll = False self.treeview_table.yview_moveto(1) def update_progressbar(self): with self.lock: if self.crawler.urls_total > 0: self.percentage = int( (self.crawler.urls_crawled / self.crawler.urls_total) * 100) self.progressbar["value"] = self.percentage if sys.platform == "win32": self.style.configure('text.Horizontal.TProgressbar', text=f'{self.percentage} %') def update_bottom_stats(self): with self.lock: self.urls_string_var.set( f"Speed: {self.crawler.current_urls_per_second} URL/s") self.urls_crawled_string_var.set( f"URLs crawled/discovered: {'{:,}'.format(self.crawler.urls_crawled)}/{'{:,}'.format(self.crawler.urls_total)} ({self.percentage}%)" ) def update(self): self.button_crawl["text"] = "Resume" self.entry_url_input.entry['state'] = 'enabled' self.entry_url_input.entry.delete(0, 'end') self.entry_url_input.entry.insert( 0, self.crawler.settings["STARTING_URL"]) self.row_counter = self.crawler.urls_crawled self.populate_columns() self.update_progressbar() def reset(self, reset_url_input=True): self.entry_url_input.entry["state"] = "enabled" if reset_url_input: self.entry_url_input.entry.delete(0, 'end') self.entry_url_input.entry.insert(0, "Enter URL to crawl") self.progressbar["value"] = 0 self.clear_output_table() self.populate_columns() self.button_crawl["text"] = "Start" self.suspend_auto_scroll = False self.filters = None self.reset_filter_window() self.crawler.reset_crawl() self.master.title(Defaults.window_title) def show_list_mode(self): self.reset() self.master.title(f'List Mode - {Defaults.window_title}') self.entry_url_input.entry.delete(0, 'end') self.entry_url_input.entry.insert(0, "List Mode ...") self.freeze_input() def freeze_input(self): self.entry_url_input.entry["state"] = "disabled" def assign_treeview_click(self, event): region = self.treeview_table.identify("region", event.x, event.y) if region == 'cell': iid = self.treeview_table.identify_row(event.y) if iid: self.treeview_table.selection_set(iid) item = self.treeview_table.selection() self.row_values = self.treeview_table.item(item)['values'] try: self.action_menu.tk_popup(event.x_root, event.y_root + 20, 0) finally: self.action_menu.grab_release() elif region == 'heading': col = self.treeview_table.identify_column(event.x) self.selected_column = self.treeview_table.heading(col)['text'] try: self.popup_menu.tk_popup(event.x_root, event.y_root + 20, 0) finally: self.popup_menu.grab_release() def show_filter_window(self, label): columns = self.get_display_columns() if self.viewed_table != 'crawl': columns = self.get_display_columns(self.viewed_table) if 'Sort' in label: column = self.selected_column.lower().replace(' ', '_') print('Sorting column', column) # Remove previous sorting filters self.filters = [t for t in self.filters if 'Sort' not in t[1]] self.filters.append((column, label, '')) self.load_crawl_to_outputtable(self.filters, self.viewed_table, columns=columns) return # Window has never been initialised if not self.filter_window: self.filter_window = FilterWindow( self, label, self.selected_column, columns, table=self.viewed_table, title=f'Filter By {self.selected_column}') # window has been initialised but has been closed elif self.filter_window.winfo_exists() == 0: self.filter_window = FilterWindow( self, label, self.selected_column, columns, table=self.viewed_table, title=f'Filter By {self.selected_column}') else: self.filter_window.update() self.filter_window.deiconify() def show_action_window(self, label): url = '' if self.row_values: url = self.row_values[0] if label == 'Copy URL' and url: self.master.clipboard_clear() self.master.clipboard_append(url) elif label == 'Open URL in Browser' and url: open_in_browser(url, new=2) elif label == 'View Inlinks' and url: ViewInlinks(url, self.crawler.get_inlinks) def vertical_scrollbar_clicked(self, *args, **kwargs): self.treeview_table.yview(*args, **kwargs) if float(args[1]) < 0.95: self.suspend_auto_scroll = True else: self.suspend_auto_scroll = False def reset_filters(self): self.load_crawl_to_outputtable(None, self.viewed_table) def reset_filter_window(self): if not self.filter_window: return self.filter_window = None
class TShapesWindow(Frame): """ Class represents auxiliary window containg shapes information. :param master: master window object. :type master: tkinter.Tk :param app: main app object. :type app: TApp """ def __init__(self, master, TApp): """ Call the parent class constructor and initialise object variables. """ super().__init__() self.TApp = TApp self.round_digits = TTicksSettings.ROUND_DIGITS self.init_widgets() def init_widgets(self): """ Init frame widgets. """ # Listbox self.shapes_list = Listbox(self, exportselection=False, selectmode=EXTENDED) self.grid_columnconfigure(0, weight=1, minsize=300) self.grid_rowconfigure(0, weight=1) self.shapes_list.grid(row=0, column=0, sticky=NSEW, padx=(5, 25), pady=5) self.shapes_list.bind("<<ListboxSelect>>", self.shapes_list_selected_item) # Listbox's yscrollbar self.shapes_list_scrollbar = Scrollbar(self, orient = VERTICAL, \ command = self.shapes_list.yview) self.shapes_list_scrollbar.grid(row=0, column=0, sticky=NS + E, padx=(0, 5), pady=5) self.shapes_list.config(yscrollcommand=self.shapes_list_scrollbar.set) # Drop down menu with materials self.material_box = Combobox(self, values=["pec", "free_space"]) self.material_box.grid(row=1, column=0, sticky=EW, padx=5, pady=5) self.material_box.bind("<<ComboboxSelected>>", self.assign_material_to_shape) # Right click popup menu self.init_popup_menu() self.shapes_list.bind("<Button-3>", self.show_popoup_menu) # Delete key removes selected shape(s) self.shapes_list.bind("<Delete>", self.remove_shape) def update_list(self, shapes, *, swap=False): """ Update shapes list. :param swap: shapes list selection swap toggle. :type swap: boolean """ selection = self.shapes_list.curselection() try: shape_num = selection[0] except: shape_num = 0 self.shapes_list.delete(0, END) coord_string = "" for i, single_shape in enumerate(shapes): if (single_shape.type == "Rectangle"): coord_string = "(" + str(round(single_shape.point1_mod.x, self.round_digits)) + \ ", " + str(round(single_shape.point1_mod.y, self.round_digits)) + \ "), (" + str(round (single_shape.point2_mod.x, self.round_digits)) + \ ", " + str(round(single_shape.point2_mod.y, self.round_digits)) + ")" elif (single_shape.type == "Cylinder"): coord_string = "(" + str(round(single_shape.centre_mod.x, self.round_digits)) + \ ", " + str(round(single_shape.centre_mod.y, self.round_digits)) + \ "), " + str(round(single_shape.radius_mod, self.round_digits)) elif (single_shape.type == "CylinSector"): coord_string = "(" + str(round(single_shape.centre_mod.x, self.round_digits)) + \ ", " + str(round(single_shape.centre_mod.y, self.round_digits)) + \ "), " + str(round(single_shape.radius_mod, self.round_digits)) + \ ", " + str(round(single_shape.start, self.round_digits)) + \ ", " + str(round(single_shape.extent, self.round_digits)) elif (single_shape.type == "Polygon"): coord_string = str(len(single_shape.points)) self.shapes_list.insert( i, str(i + 1) + ". " + single_shape.type + ": " + coord_string) coord_string = "" if (not swap): self.shapes_list.select_clear(0, END) if (shape_num >= self.shapes_list.size()): self.shapes_list.selection_set(shape_num - 1) self.shapes_list.activate(shape_num) else: for item in selection: self.shapes_list.selection_set(item) self.shapes_list.activate(shape_num) def assign_material_to_shape(self, event): """ Assign material to a shape. :param event: event evoking this method (listbox select). :type event: tkinter.Event """ material = self.material_box.get() try: shape_num = (self.shapes_list.curselection())[0] except: return else: if (shape_num < 0 or material == ""): return else: try: self.TApp.shapes[shape_num].material = material except Exception as message: messagebox.showerror("Material assignment error!", message) return def shapes_list_selected_item(self, event): """ Handle listbox selection event. :param event: event evoking this method (listbox select). :type event: tkinter.Event """ # Add multiple selection self.shapes_list.focus_force() try: shape_num = (self.shapes_list.curselection())[0] selection = self.shapes_list.curselection() except IndexError: return except Exception as message: messagebox.showerror("Error while picking shape!", message) if (shape_num < 0): return else: try: shape = self.TApp.shapes[shape_num] except Exception as message: messagebox.showerror("Materials list error", message) return self.material_box.set(str(shape.material)) for single_shape in self.TApp.shapes: single_shape.width = 1 for item in selection: self.TApp.shapes[item].width = 2 self.TApp.main_canvas.delete("all") for item in selection: self.shapes_list.selection_set(item) self.TApp.canvas_refresh() def init_popup_menu(self): """ Init shapes pane pup-up menu. """ self.popup_menu = Menu(self, tearoff=0) self.popup_menu.add_command(label="Edit shape", command=self.edit_shape) self.popup_menu.add_command(label="Change shape colour", command=self.change_shape_colour) self.popup_menu.add_command(label="Remove shape(s)", command=self.remove_shape) self.popup_menu.add_separator() self.popup_menu.add_command(label="Add vertex to polygon", command=self.add_vertex_to_polygon) self.popup_menu.add_separator() self.popup_menu.add_command(label="Copy shape", command=self.copy_shape) self.popup_menu.add_command(label="Paste shape", command=self.paste_shape) self.popup_menu.add_separator() self.popup_menu.add_command(label="Move up", command=self.move_shape_up) self.popup_menu.add_command(label="Move down", command=self.move_shape_down) self.popup_menu.add_command(label="Move to top", command=self.move_shape_top) self.popup_menu.add_command(label="Move to bottom", command=self.move_shape_bottom) def show_popoup_menu(self, event): """ Show shapes list pop-up menu. :param event: event evoking this method (RMB click). :type event: tkinter.Event """ try: self.popup_menu.post(event.x_root, event.y_root) finally: self.popup_menu.grab_release() def move_shape_up(self): """ Move a shape one place up the shapes list. """ try: shape_num = (self.shapes_list.curselection())[0] except IndexError: return if (shape_num < 0): return else: try: self.TApp.shapes.insert(shape_num - 1, self.TApp.shapes.pop(shape_num)) self.update_list(self.TApp.shapes) self.TApp.main_canvas.delete("all") self.TApp.canvas_refresh(swap=True) self.shapes_list.selection_set(shape_num - 1) self.shapes_list.activate(shape_num - 1) except Exception as message: messagebox.showerror("Error while manipulating shapes list!", message) return def move_shape_down(self): """ Move a shape one place down the shapes list. """ try: shape_num = (self.shapes_list.curselection())[0] except IndexError: return if (shape_num < 0): return else: try: self.TApp.shapes.insert(shape_num + 1, self.TApp.shapes.pop(shape_num)) self.update_list(self.TApp.shapes) self.TApp.main_canvas.delete("all") self.TApp.canvas_refresh(swap=True) self.shapes_list.selection_set(shape_num + 1) self.shapes_list.activate(shape_num + 1) except Exception as message: messagebox.showerror("Error while manipulating shapes list!", message) return def move_shape_top(self): """ Move a shape to the top of the shapes list. """ try: shape_num = (self.shapes_list.curselection())[0] except IndexError: return if (shape_num < 0): return else: try: self.TApp.shapes.insert(0, self.TApp.shapes.pop(shape_num)) self.update_list(self.TApp.shapes) self.TApp.main_canvas.delete("all") self.TApp.canvas_refresh(swap=True) self.shapes_list.selection_set(0) self.shapes_list.activate(0) # self.shapes_list.focus_set () except Exception as message: messagebox.showerror("Error while manipulating shapes list!", message) return def move_shape_bottom(self): """ Move a shape to the bottom of the shapes list. """ try: shape_num = (self.shapes_list.curselection())[0] except IndexError: return if (shape_num < 0): return else: try: self.TApp.shapes.append(self.TApp.shapes.pop(shape_num)) self.update_list(self.TApp.shapes) self.TApp.main_canvas.delete("all") self.TApp.canvas_refresh(swap=True) self.shapes_list.selection_set(END) self.shapes_list.activate(END) except Exception as message: messagebox.showerror("Error while manipulating shapes list!", message) return def edit_shape(self): """ Edit selected shape on the shapes list. """ try: shape_num = (self.shapes_list.curselection())[0] except IndexError: return if (shape_num < 0): return else: self.TApp.operations.append(TOperation("edit", shape = \ deepcopy(self.TApp.shapes[shape_num]), \ num = shape_num)) if (self.TApp.shapes[shape_num].type == "Rectangle"): self.TApp.edit_rectangle(shape_num) elif (self.TApp.shapes[shape_num].type == "Cylinder"): self.TApp.edit_cylin(shape_num) elif (self.TApp.shapes[shape_num].type == "CylinSector"): self.TApp.edit_cylin_sector(shape_num) elif (self.TApp.shapes[shape_num].type == "Polygon"): self.TApp.edit_polygon(shape_num) def change_shape_colour(self): """ Change selected shape on the shapes list colour. """ try: shape_num = (self.shapes_list.curselection())[0] except IndexError: return if (shape_num < 0): return else: self.TApp.change_shape_colour(shape_num=shape_num) def remove_shape(self, event=None): """ Remove selected shape on the shapes list. """ try: selection = self.shapes_list.curselection() except IndexError: return if (len(selection) == 0): return else: try: for item in reversed(selection): del self.TApp.shapes[item] self.update_list(self.TApp.shapes) self.TApp.main_canvas.delete("all") self.TApp.canvas_refresh() except Exception as message: messagebox.showerror("Error while manipulating shapes list!", message) return def add_vertex_to_polygon(self): """ Add a vertex to selected polygon on the shapes list. """ try: shape_num = (self.shapes_list.curselection())[0] except IndexError: return input_str = simpledialog.askstring("Input coordinates", "Give mew vertex's coordinates") point_mod_x, point_mod_y = [float(val) for val in input_str.split()] if (self.TApp.shapes[shape_num].type == "Polygon" and shape_num > -1): self.TApp.shapes[shape_num].add_vertex(x_mod=point_mod_x, y_mod=point_mod_y) self.TApp.main_canvas.delete("all") self.TApp.canvas_refresh() def copy_shape(self): """ Copy selected shape on the shapes list. """ try: shape_num = self.shapes_list.curselection()[0] except: shape_num = -1 if (shape_num > -1): try: self.TApp.copy_shape(shape_num=shape_num) except Exception as message: messagebox.showerror("Error while manipulating shapes list!", message) def paste_shape(self, *, deltax=15, deltay=15): """ Paste selected shape from buffer. :param deltax: pasted shape offset in x direction in pixels. :type deltax: integer :param deltay: pasted shape offset in y direction in pixels. :type deltay: integer """ self.TApp.paste_ctrl_v(Event())
class FastMenu(): def __init__(self, root, text): self.root = root self.text = text self.fastMenu = Menu(self.root, tearoff=0) def popup(event): try: self.fastMenu.tk_popup(event.x_root, event.y_root) finally: self.fastMenu.grab_release() self.fastMenu.add_command(label="Title", command=lambda: Format(self.root, self.text). addTags(tag="title", size=4, sizeMod=True), accelerator="Alt+T") self.fastMenu.add_command( label="Subtitle", command=lambda: Format(self.root, self.text).addTags( tag="subtitle", size=2, sizeMod=True), accelerator="Alt+S") self.fastMenu.add_command( label="Bold", command=lambda: Format(self.root, self.text).addTags(tag="bold"), accelerator="Alt+B") self.fastMenu.add_command( label="Italic", command=lambda: Format(self.root, self.text).addTags(tag="italic"), accelerator="Alt+I") self.fastMenu.add_command(label="Underline", command=lambda: Format(self.root, self.text). addTags(tag="underline"), accelerator="Alt+Shift+-") self.fastMenu.add_command(label="Overstrike", command=lambda: Format(self.root, self.text). addTags(tag="overstrike")) self.fastMenu.add_command( label="Remove tags", command=lambda: Format(self.root, self.text).addTags(tag="remove"), accelerator="Alt+R") self.fastMenu.add_separator() self.fastMenu.add_command( label="Choose Color", command=lambda: Format(self.root, self.text).changeColor()) self.fastMenu.add_command( label="Last Color", command=lambda: Format(self.root, self.text).changeColor(), accelerator="Alt+C") #SubMenu self.predefinedColors = Menu(self.fastMenu, tearoff=0) for name, color in globals.colorConfig.items(): self.predefinedColors.add_command( label=name.capitalize(), command=lambda color=color: Format(self.root, self.text ).changeColor(cor=color)) self.fastMenu.add_cascade(label="Predefined Colors", menu=self.predefinedColors) self.fastMenu.add_separator() self.simbolsMenu = Menu(self.fastMenu, tearoff=0) for category, simbols in globals.simbols.items(): self.categoryMenu = Menu(self.simbolsMenu, tearoff=0) for simbol in simbols: self.categoryMenu.add_command( label=simbol, command=lambda simbol=simbol: Format( self.root, self.text).insertSimbols(simbol)) self.simbolsMenu.add_cascade(label=category, menu=self.categoryMenu) self.fastMenu.add_cascade(label="Simbols", menu=self.simbolsMenu) self.fastMenu.add_separator() self.fastMenu.add_command(label="Calculate Selection", command=lambda: self.calculate()) self.text.bind("<Button-3>", popup) self.fastMenu.add_separator() self.fastMenu.add_command( label="Cut", command=lambda: Edit(self.root, self.text).cut(), accelerator="Ctrl+X") self.fastMenu.add_command( label="Copy", command=lambda: Edit(self.root, self.text).copy(), accelerator="Ctrl+C") self.fastMenu.add_command( label="Paste", command=lambda: Edit(self.root, self.text).paste(), accelerator="Ctrl+V") def calculate(self): try: calculus = eval(self.text.get("sel.first", "sel.last")) self.text.insert("sel.last", " ==> (" + str(calculus) + ")") except: self.text.insert("sel.last", " ==> (Invalid Operation)")
class Window(Listbox): # Initializes the variables and settings for the project. Finally # executes the create_menu for the menu bar, and the create_notepad # for the text window def __init__(self, master, **kw): # Sets master, or root super().__init__(master, **kw) self.master = master # Set some variables self.current_file_path = '' self.current_file_text = '' self.is_saved = True # Set up the context menu and the text box self.context_popup_menu = Menu(self.master, tearoff=0) self.text_window = ScrolledText(self.master, undo=True) self.text_window.focus() self.user_data = self.text_window.get('1.0', END + '-1c') # Name the window, icon, and start the create functions self.master.title(NAME) # self.master.iconbitmap('./tk/images/icon.ico') self.initiate_shortcuts() self.create_menu() self.create_notepad() self.create_context_menu() # Creates the context menu def create_context_menu(self): # Adds a command for button, separator for separator self.context_popup_menu.add_command(label="Undo", command=lambda: self.undo()) self.context_popup_menu.add_command(label="Redo", command=lambda: self.redo()) self.context_popup_menu.add_separator() self.context_popup_menu.add_command( label="Cut", command=lambda: self.text_window.event_generate("<<Cut>>")) self.context_popup_menu.add_command( label="Copy", command=lambda: self.text_window.event_generate("<<Copy>>")) self.context_popup_menu.add_command( label="Paste", command=lambda: self.text_window.event_generate("<<Paste>>")) self.context_popup_menu.add_separator() self.context_popup_menu.add_command(label="Delete", command=lambda: self.clear()) self.context_popup_menu.add_separator() self.context_popup_menu.add_command(label="Select All", command=lambda: self.select_all()) # Creates the top bar menu def create_menu(self): # Creating menu bar and adding it to master menu_bar = Menu(self.master) text = self.text_window # Telling root that menu_bar is the Window's menu self.master.config(menu=menu_bar) # Creating the File menu dropdown file_menu = Menu(menu_bar, tearoff=False) file_menu.add_command(label="New Document...", command=self.new_file, accelerator="Ctrl+N") file_menu.add_command(label="Open Document...", command=self.open_file, accelerator="Ctrl+O") file_menu.add_command(label="Save...", command=self.save_file, accelerator="Ctrl+S") file_menu.add_command(label="Save as...", command=self.save_as_file, accelerator="Ctrl+Shift+S") file_menu.add_separator() file_menu.add_command(label="Quit", command=self.exit, accelerator="Ctrl+Q") # Adding it to the menu_bar menu_bar.add_cascade(label="File", menu=file_menu, underline=0) # Creating the Edit menu dropdown edit_menu = Menu(menu_bar, tearoff=False) edit_menu.add_command(label="Undo", command=self.undo, accelerator="Ctrl+Z") edit_menu.add_command(label="Redo", command=self.redo, accelerator="Ctrl+Y") edit_menu.add_separator() edit_menu.add_command(label="Cut", command=lambda: text.event_generate("<<Cut>>"), accelerator="Ctrl+X") edit_menu.add_command(label="Copy", command=lambda: text.event_generate("<<Copy>>"), accelerator="Ctrl+C") edit_menu.add_command(label="Paste", command=lambda: text.event_generate("<<Paste>>"), accelerator="Ctrl+V") edit_menu.add_separator() edit_menu.add_command(label="Select All", command=lambda: self.select_all(), accelerator="Ctrl+A") edit_menu.add_command(label="Delete", command=self.clear, accelerator="Del") # edit_menu.add_separator() # edit_menu.add_command(label="Settings...", command=settings, accelerator="Ctrl+S") # Adding it to the menu_bar menu_bar.add_cascade(label="Edit", menu=edit_menu) # Creating the Help menu help_menu = Menu(menu_bar, tearoff=False) help_menu.add_command(label="About...", command=about) # Adding it to the menu_bar menu_bar.add_cascade(label="Help", menu=help_menu) # Bind the shortcuts to their specified functions def initiate_shortcuts(self): self.master.bind("<KeyRelease>", lambda event: self.on_text_change()) self.master.bind("<Control-n>", lambda event: self.new_file()) self.master.bind("<Control-o>", lambda event: self.open_file()) self.master.bind("<Control-s>", lambda event: self.save_file()) self.master.bind("<Control-Shift-s>", lambda event: self.save_as_file()) self.master.bind("<Control-q>", lambda event: self.exit()) self.master.bind("<Control-z>", lambda event: self.undo()) self.master.bind("<Control-y>", lambda event: self.redo()) self.text_window.bind("<Control-a>", lambda event: self.select_all()) # self.master.bind("<Control-s>", lambda event: settings()) self.master.bind("<Button-3>", lambda event: self.right_click_popup(event)) # Display context menu popup def right_click_popup(self, event): try: # Used +45 and + 12 to corner it self.context_popup_menu.tk_popup(event.x_root + 45, event.y_root + 12, 0) finally: self.context_popup_menu.grab_release() # Scaling the text_window to fit the screen def create_notepad(self): self.text_window.pack(fill="both", expand=True) # Returns the value of the text field def get_text_data(self): return self.text_window.get('1.0', END + '-1c') # Clears the text off the screen, resets the variables def clear_text(self): self.text_window.delete('1.0', END) self.current_file_path = '' self.current_file_text = '' # Called when typing, sets the is_saved variable def on_text_change(self): # If the text in the textbox is equal to the saved text in the variable # This is used when opening a file, changing something, then undoing that change if self.get_text_data() == self.current_file_text: self.is_saved = True else: # If the saved file exists or is valid if os.path.isfile(self.current_file_path): # Open the file, save it's data to this_file with open(self.current_file_path, "r") as f: this_file = f.read() # If this_file is equal to the same text in the textbox # Used if no changes were made, and if they were, set to False self.is_saved = True if this_file == self.get_text_data( ) else False else: # If the data is not equal to variable, and no file, then changes # must have been made self.is_saved = False # MENU CONTROL FUNCTIONS # Clear current selection, erase the current file if saved def new_file(self): # If it's saved, clear it and set the file to saved if self.is_saved is True: self.clear_text() self.is_saved = True else: # Popup the saved popup popup_value = is_saved_popup() if popup_value == "yes": # Save the file, clear it and set the is_saved to True if self.save_file() is True: self.clear_text() self.is_saved = True elif popup_value == "no": # Don't save the file, but clear it and set the is_saved to True self.clear_text() self.is_saved = True else: # Something went wrong print("Error: new_file error") # Open a file if the current file is saved, then insert new file data def open_file(self): # If file is saved, open the open_file window if self.is_saved is True: self.open_file_popup() else: # Save the file, if it's saved, open the open_file window popup_value = is_saved_popup() if popup_value == "yes": if self.save_file() is True: self.is_saved = True self.open_file_popup() # Open the open_file window elif popup_value == "no": self.open_file_popup() else: # An error occurred print("Error: open_file error") # The function that displays the open_file popup def open_file_popup(self): # Gets old data from current file old_file = self.current_file_path # Opens the file location, stores it in file_name file_name = filedialog.askopenfilename( title="Open", filetypes=(("Text files", "*.txt"), ("All files", "*.*"))) # If a file was actually selected, open it if file_name is not '': with open(file_name) as f: data = f.read() # Clear current text self.clear_text() # Set the path variable of the new file self.current_file_path = file_name if os.path.isfile( file_name) else old_file # Add the file data to the text_box self.text_window.insert(INSERT, data) # Add the file data to the variable self.current_file_text = data # is_saved is True self.is_saved = True # Save file, if file exists, overwrite it, otherwise, call save_as_file function def save_file(self): # If the file path exists if os.path.isfile(self.current_file_path): # Stores the current text data into the variable self.current_file_text = self.get_text_data() # Saves the data to the existing file (overwriting) with open(self.current_file_path, "w") as f: return True if f.writelines( self.get_text_data()) is True else False else: # File doesn't exist, call save_as_file if self.save_as_file() is True: return True # Saves file with asksaveasfile to open a save as window. def save_as_file(self): # Gets old file path old_file = self.current_file_path # Opens save_as window file_name = filedialog.asksaveasfilename( title="Save As", defaultextension=".txt", filetypes=(("Text files", "*.txt"), ("All files", "*.*"))) # Set current file path self.current_file_path = old_file if file_name is None else file_name # If the file_path already exists if os.path.isfile(self.current_file_path): # Copy the current text to the variable self.current_file_text = self.get_text_data() # Writes to the named file with open(self.current_file_path, "w") as f: f.writelines(self.get_text_data()) return True else: # A file wasn't selected if file_name is '': print("Error: File is none") return False # Create a new file to store the data self.current_file_text = self.get_text_data() with open(file_name, 'w'): pass self.is_saved = True return True # Exit override command def exit(self): # If the file is saved, exit if self.is_saved is True: self.master.quit() else: # If the file is not saved, call the saved_popup popup_value = is_saved_popup() if popup_value == "yes": # Save and then quit if self.save_file() is True: self.is_saved = True self.quit() elif popup_value == "no": # Don't save, just quit self.master.quit() else: # An error occurred print("Error: open_file error") # Undo last action def undo(self): self.text_window.edit_undo() # Redo last action def redo(self): self.text_window.edit_redo() # Clear (delete) the selected text def clear(self): self.text_window.delete(SEL_FIRST, SEL_LAST) self.text_window.update() # Select the selected text (without new line) def select_all(self): self.text_window.tag_add(SEL, "1.0", END + '-1c') self.text_window.mark_set(INSERT, "1.0") self.text_window.see(INSERT) return 'break'
class Brainfsck(Frame): ''' Main window of the application ''' WINDOW_TITLE = "Brainfsck - iivlxsoft" WINDOW_WIDTH = 700 WINDOW_HEIGHT = 700 WINDOW_WIDTH_MIN = 500 WINDOW_HEIGHT_MIN = 250 WINDOW_WIDTH_OFFSET = 100 WINDOW_HEIGHT_OFFSET = 100 WINDOW_Y_MIN = 50 WINDOW_RESIZABLE = (True, True) engine = None execution_delay = 1 allow_illegal_characters = True input_buffer = [] output_buffer = [] _reset_modifed = False #sponge execution_time_start = 0 execution_time_end = 0 execution_time_total = 0 breakpoints = [] def __init__(self, master, **kw): Frame.__init__(self, master, **kw) self.style = Style() self.configure() loadIcon(self.master, self.master, IIVLXICO) self.master.title(self.WINDOW_TITLE) self.master.resizable(*self.WINDOW_RESIZABLE) x = self.master.winfo_pointerx() - self.WINDOW_WIDTH_OFFSET y = self.master.winfo_pointery() - self.WINDOW_HEIGHT_OFFSET y = y if y > self.WINDOW_Y_MIN else self.WINDOW_Y_MIN self.master.geometry( f'{self.WINDOW_WIDTH}x{self.WINDOW_HEIGHT}+{x}+{y}') self.master.minsize(self.WINDOW_WIDTH_MIN, self.WINDOW_HEIGHT_MIN) # configure master grid self.master.grid_rowconfigure(0, weight=1) self.master.grid_columnconfigure(0, weight=1) # place the window self.grid(row=0, column=0, sticky='news') #configure grid self.grid_rowconfigure(0, weight=1) self.grid_rowconfigure(1, weight=1) self.grid_rowconfigure(2, weight=1) self.grid_rowconfigure(2, weight=0) self.grid_columnconfigure(0, weight=1) self.grid_columnconfigure(1, weight=1) self.grid_columnconfigure(2, weight=1) self.grid_columnconfigure(2, weight=2) # subwindows self.memoryview = None # draw the window self.createMenubar() self.createContextMenu() self.draw() self.setBinds() def setBinds(self): self.codeInput.bind("<Button-3>", self.showContextMenu) #self.textInput.bind("<<Modified>>", self.handleInput) self.textInput.bind("<Key>", self.handleKey) def draw(self): self.drawCode() self.drawIO() self.drawControls() self.drawStatusBar() def drawCode(self): ''' code''' self.codeInput = Text(self) self.codeInput.grid(row=0, column=0, rowspan=2, columnspan=2, sticky='news') def drawIO(self): self.textOutput = Text(self) self.textOutput.configure(state=DISABLED) self.textOutput.grid(row=0, column=2, columnspan=2, sticky='news') self.textInput = Text(self) self.textInput.grid(row=1, column=2, columnspan=2, sticky='news') self.textInputModified = False self.textInputIndex = 0 self.textInput.config(state=DISABLED) def drawControls(self): ''' main controls''' startStopButton = Button(self, text="Run") startStopButton.config(command=lambda: self.startStop()) startStopButton.grid(row=2, column=0) stepButton = Button(self, text="Step", command=lambda: self.step()) stepButton.grid(row=2, column=1) resetButton = Button(self, text="Reset/Load", command=lambda: self.reset()) resetButton.grid(row=2, column=2) quitButton = Button(self, text="Quit") quitButton.config(command=lambda: self.close()) quitButton.grid(row=2, column=3) def drawStatusBar(self): self.statusBar = Label( self, text='Instruction Pointer: 0, Memory Pointer: 0, Memory Value: 0') self.statusBar.grid(row=3, column=0, columnspan=4, sticky='ews') self.statusBar.config(relief=SUNKEN) def updateStatusBar(self): ip = self.engine.instruction_pointer mp = self.engine.memory_pointer #print(mp) #sponge value = self.engine.memory[mp] er = self.engine.running p = '' if self.running else ' (paused)' status_string = 'Running: %s%s, Instruction Pointer: %d, Memory Pointer: %d, Memory Value: %d' % ( er, p, ip, mp, value) if self.execution_time_total: status_string += ', Execution Time: %f' % self.execution_time_total self.statusBar.config(text=status_string) def createMenubar(self): ''' Create and add the menubar The menubar consists of the following submenus: File Edit View About ''' self.menubar = Menu(self.master) self.master.config(menu=self.menubar) # add submenus self.menubar.add_cascade(label='File', menu=self.createMenubarFile()) self.menubar.add_cascade(label='Edit', menu=self.createMenubarEdit()) self.menubar.add_cascade(label='View', menu=self.createMenubarView()) self.menubar.add_cascade(label='Help', menu=self.createMenubarHelp()) def createMenubarFile(self): ''' Create the File submenu ''' self.menubar_file = Menu(self.menubar, tearoff=0) self.menubar_file.add_command(label='Load') self.menubar_file.add_command(label='Save') self.menubar_file.add_separator() self.menubar_file.add_command(label='Exit', command=self.quit) return self.menubar_file def createMenubarEdit(self): ''' Create the Edit submenu ''' self.menubar_edit = Menu(self.menubar, tearoff=0) self.menubar_edit.add_command(label='Set exectuion delay', command=self.showSetExecutionDelay) self.menubar_edit.add_separator() self.menubar_edit.add_command(label='Remove non bf characters', command=self.stripIllegalCharacters) self.menubar_edit.add_command(label='Remove spaces', command=self.stripSpaces) self.menubar_edit.add_command(label='Remove newlines', command=self.stripNewlines) self.menubar_edit.add_separator() self.menubar_edit.add_command(label='Delete all breakpoints', command=self.clearAllBreakpoints) self.menubar_edit.add_separator() self.menubar_edit.add_command(label='Edit memory cell size') self.menubar_edit.add_command(label='Edit memory size') self.menubar_edit.add_command(label='Edit maximum memory cell value', command=self.showSetMaximumCellValue) return self.menubar_edit def createMenubarView(self): ''' Create the View submen ''' self.menubar_view = Menu(self.menubar, tearoff=0) self.menubar_view.add_command(label='Memory Block', command=self.showMemoryBlock) self.menubar_view.add_command(label='Memory Linear', command=self.showMemoryLinear) return self.menubar_view def createMenubarHelp(self): ''' Create the Help submenu ''' self.menubar_about = Menu(self.menubar, tearoff=0) self.menubar_about.add_command(label='About', command=self.showAbout) return self.menubar_about def createContextMenu(self): ''' Right click context menu ''' self.contextMenu = Menu(self, tearoff=0) self.contextMenu.add_command(label='Set Breakpoint', command=self.setBreakpoint) self.contextMenu.add_command(label='Clear Breakpoint', command=self.clearBreakpoint) return self.contextMenu def showContextMenu(self, event): try: self.contextMenu.tk_popup(event.x_root + 50, event.y_root + 10, 0) finally: self.contextMenu.grab_release() def showAbout(self): ''' Show the about dialog ''' About(self) def showMemoryBlock(self): ''' Show memory viewer ''' self.memoryview = MemoryView(self) def showMemoryLinear(self): ''' Show memory viewer ''' self.memoryview = MemoryView(self) def stripCharacters(self, characters): ''' remove characters from code input ''' # remember current cursor position cursor = self.codeInput.index(CURRENT) # strip the code of non legal brainfsck characters code = self.codeInput.get('1.0', END) code = code.translate({ord(c): None for c in characters}) # remove old code and insert stripped code and reset cursor self.codeInput.delete('1.0', END) self.codeInput.insert('1.0', code) self.codeInput.mark_set('insert', cursor) def stripIllegalCharacters(self): ''' Remove all non brainfsck characters from the code input''' # remember current cursor position cursor = self.codeInput.index(CURRENT) # strip the code of non legal brainfsck characters code = self.codeInput.get('1.0', END) code = ''.join( filter( lambda x: x in ['\n', ' ', '.', ',', '+', '-', '>', '<', '[', ']'], code)) # remove old code and insert stripped code and reset cursor self.codeInput.delete('1.0', END) self.codeInput.insert('1.0', code) self.codeInput.mark_set('insert', cursor) def stripSpaces(self): self.stripCharacters(' ') def stripNewlines(self): self.stripCharacters('\n') def checkBreakpoint(self): ''' Check to see if we hit a breakpoint''' if self.engine.instruction_pointer in self.breakpoints: self.pause() def setBreakpoint(self): ''' set a breakpoint at the current selection''' # check to see if something is selected if self.codeInput.tag_ranges('sel'): # add the selection to the breakpoint list for i in range(self.codeInput.count('sel.first', 'sel.last')[0]): count = self.codeInput.count('1.0', 'sel.first') if count is None: count = [0] bp = count[0] + i if bp not in self.breakpoints: self.breakpoints.append(bp) # highlight breakpoints self.codeInput.tag_add('breakpoint', 'sel.first', 'sel.last') self.codeInput.tag_config('breakpoint', background='yellow', foreground='black') self.codeInput.tag_raise('sel') def clearBreakpoint(self): ''' clear the breakpoint at the cursor''' # check to see if anything is selected if self.codeInput.tag_ranges('sel'): # remove selection from breakpoint list for i in range(self.codeInput.count('sel.first', 'sel.last')[0]): count = self.codeInput.count('1.0', 'sel.first') if count is None: count = [0] bp = count[0] + i if bp in self.breakpoints: self.breakpoints.remove(bp) # remove highlight self.codeInput.tag_remove('breakpoint', 'sel.first', 'sel.last') def clearAllBreakpoints(self): for tag in self.codeInput.tag_names(): if tag == 'breakpoint': self.codeInput.tag_delete(tag) self.breakpoints = [] def showSetExecutionDelay(self): ''' Open the SetExecutionDelay dialog and use the value returned to set the execution delay''' SetExecutionDelay(self) def showSetMaximumCellValue(self): ''' open the SetMaximumCellValue dialog and use the value returend to set the execution delay ''' SetMaximumCellValue(self) def setMaximumCellValue(self, value): self.engine.memorymaxvalue = value def getCode(self): if self.codeInput: return self.codeInput.get('1.0', END) else: return "" def startStop(self): ''' Start or start the engine, If we stopped in the middle of the program we should just begin where we left off Otherwise if run_complete is true we want to restart from the beginning.''' if not self.engine.running: self.reset() self.engine.running = True self.updateStatusBar() if not self.execution_time_start: self.execution_time_start = time.time() if self.running: self.pause() else: self.running = True self.run() def pause(self): ''' Pause the execution ''' self.running = False self.updateStatusBar() def run(self): ''' Step through the code one instruction at a time after a timeout until the program finishes.''' self.getOutput() self.updateStatusBar() if self.engine.running == True: self.tagCurrentInstruction() self.checkBreakpoint() self.engine.step() if self.memoryview: self.memoryview.refreshMemory() if self.running: self.master.after(self.execution_delay, self.run) #self.master.after_idle(self.run) else: self.execution_time_total = time.time() - self.execution_time_start self.updateStatusBar() return def step(self): self.getOutput() if self.engine.running == True: self.tagCurrentInstruction() self.engine.step() if self.memoryview: self.memoryview.refreshMemory() self.updateStatusBar() else: self.reset() self.engine.running = True self.updateStatusBar() def clearText(self): self.textOutput.config(state=NORMAL) self.textOutput.delete('1.0', END) self.textOutput.config(state=DISABLED) self.textInput.config(state=NORMAL) self.textInput.delete('1.0', END) self.textInput.config(state=DISABLED) #self.textInputIndex = 0 def tagCurrentInstruction(self): for tag in self.codeInput.tag_names(): if tag == 'current': self.codeInput.tag_delete(tag) current = self.engine.instruction_pointer s = self.codeInput.get('1.0', END)[0] if s.isspace(): return # the code contains only whitespace self.codeInput.tag_add('current', '1.0+%dc' % current) self.codeInput.tag_config('current', background='red') def handleKey(self, event): ''' Handle a keypress on the text input window, we want to copy this character to the input buffer, and also display it on the text input.''' #print(event) if not event.char: return # special character we can ignore this if event.char == '\r': event.char = '\n' self.textInput.config(state=NORMAL) self.textInput.insert(END, event.char) self.textInput.config(state=DISABLED) self.input_buffer.append(event.char) def getOutput(self): if self.output_buffer: self.textOutput.config(state=NORMAL) self.textOutput.insert(END, self.output_buffer.pop(0)) self.textOutput.config(state=DISABLED) def loadEngine(self, engine): self.engine = engine self.code = " " self.reset() def reset(self): self.clearText() self.engine.reset() self.engine.code = self.getCode() self.engine.getBrackets() self.engine.running = False self.running = False self.clearText() self.input_buffer = [] self.output_buffer = [] self.engine.output_buffer = self.output_buffer self.engine.input_buffer = self.input_buffer self.tagCurrentInstruction() self.execution_time_start = 0 self.execution_time_end = 0 self.execution_time_total = 0 #self.engine.run(input = self.input_buffer, output = self.output_buffer) self.updateStatusBar() def close(self): ''' Close this window ''' self.quit()
class PmaConvert: def __init__(self, config): root = Tk() # Root Definition root.geometry('1100x700') root.title('PMA Convert') # Configuration and Variables self.file_selection = '' self.is_converting = False self.options = config['option_definitions'] gui_config = config['gui_config'] # UI ## Frames self.main_frame = Frame(root) self.position_main_frame(gui_config['screen_orientation']) ## Components self.log = Text(self.main_frame, bd=1, relief=SUNKEN, width=140, height=23, state=DISABLED, spacing3=1, wrap=WORD) choose_text = ('1. Choose XLSForm (.xls or .xlsx) file(s) for ' 'conversion.') self.choose_files_label = Label(self.main_frame, text=choose_text) # TODO: Get spacing to work. # self.choose_files_label.grid(row=3, column=3, padx=(50, 50)) # self.choose_files_label.grid(row=3, column=3, pady=(50, 50)) self.choose_files_label.pack() self.choose_files_button = Button(self.main_frame, text='Choose file...', fg='black', command=self.on_open) self.choose_files_button.pack() out_text = 'Choose location for output file(s).' self.output_location_label = Label(self.main_frame, text=out_text) self.output_location_button = Button(self.main_frame, text='Choose location...', fg='black') if gui_config['output_location_on'] is True: self.output_location_label.pack() self.output_location_button.pack() self.choose_options_label = Label(self.main_frame, text='2. Choose conversion options.') self.choose_options_label.pack() ### Create Options Checkboxes # Task: Dynamically generate: http://stackoverflow.com/questions/... # ...553784/can-you-use-a-string-to-instantiate-a-class-in-python self.preexisting = BooleanVar() pre_text = self.options['preexisting']['label'] self.preexisting_opt = Checkbutton(self.main_frame, text=pre_text, variable=self.preexisting) self.preexisting_opt.pack() self.regular = BooleanVar() reg_text = self.options['regular']['label'] self.regular_opt = Checkbutton(self.main_frame, text=reg_text, variable=self.regular) self.regular_opt.pack() self.novalidate = BooleanVar() noval_text = self.options['novalidate']['label'] self.novalidate_opt = Checkbutton(self.main_frame, text=noval_text, variable=self.novalidate) self.novalidate_opt.pack() self.ignore_version = BooleanVar() ig_text = self.options['ignore_version']['label'] self.ignore_version_opt = Checkbutton(self.main_frame, text=ig_text, variable=self.ignore_version) self.ignore_version_opt.pack() self.linking_warn = BooleanVar() link_text = self.options['linking_warn']['label'] self.linking_warn_option = Checkbutton(self.main_frame, text=link_text, variable=self.linking_warn) self.linking_warn_option.pack() self.debug = BooleanVar() debug_text = self.options['debug']['label'] self.debug_option = Checkbutton(self.main_frame, text=debug_text, variable=self.debug) self.debug_option.pack() self.extras = BooleanVar() extras_text = self.options['extras']['label'] self.extras_option = Checkbutton(self.main_frame, text=extras_text, variable=self.extras) self.extras_option.pack() self.convert_label = Label(self.main_frame, text='3. Run conversion.') self.convert_label.pack() # Task: Add xscrollcommand and yscrollcommand. self.convert_button = Button(self.main_frame, text='Convert', fg='black', command=self.convert) self.convert_button.pack() self.log.pack(fill=X, expand=1) self.log_text( 'PMA Convert allows you to convert .xls or .xlsx form ' 'definition files to files which are compatible with ODK ' 'Collect.\n\nIf you need to copy and paste from this ' 'log, highlight the text and press CTRL+C to copy. Then ' 'press CTRL+V to paste.\n\n' '====================================================\n\n' 'Awaiting file selection.') # Task: Fix menus. They're not working. self.context_menu = Menu(self.main_frame, tearoff=0) self.context_menu.add_command(label="Convert", command=self.convert) self.main_frame.bind("<Button-3>", self.popup) # - Note: Strangely this stopped anchoring to bottom suddenly, for some # reason. So it is temporarily disabled. self.status_bar = Label(self.main_frame, text='Awaiting file selection.', bd=1, relief=SUNKEN, anchor=W) if gui_config['status_bar_on'] is True: self.status_bar.pack(side=BOTTOM, fill=X) # Run root.mainloop() # Functions def popup(self, event): # Note: Currently doesn't work. self.context_menu.post(event.x_root, event.y_root) # display the popup menu try: self.context_menu.tk_popup(event.x_root, event.y_root, 0) finally: # make sure to release the grab (Tk 8.0a1 only) self.context_menu.grab_release() def position_main_frame(self, orientation): if orientation == 'center': x, y, a = .5, .5, 'c' return self.main_frame.place(relx=x, rely=y, anchor=a) elif orientation == 'top': return self.main_frame.pack() else: return self.main_frame.pack() def on_open(self): file_types = [('XLS Files', '*.xls'), ('XLSX Files', '*.xlsx'), ('All files', '*')] try: self.file_selection = tkinter.filedialog.askopenfilename( filetypes=file_types, title='Open one or more files.', message='Open one or more files', multiple=1) except: self.file_selection = tkinter.filedialog.askopenfilename( filetypes=file_types, title='Open one or more files.', multiple=1) if self.file_selection != '': self.set_status('Click on Convert to convert files.') log_output = 'Ready for conversion: \n' for file in self.file_selection: log_output += '* ' + str(file) + '\n' log_output = log_output[:-1] # Removes the last '\n'. self.log.configure(self.log_text(log_output)) def set_status(self, new_status): self.status_bar.configure(text=new_status) def log_text(self, new_text): self.log.configure(state=NORMAL) self.log.insert(END, str(new_text) + '\n\n') self.log.configure(state=DISABLED) self.log.bind("<1>", lambda event: self.log.focus_set()) def convert(self): if self.file_selection != '': f = self.file_selection kwargs = { SUFFIX: '', PREEXISTING: self.preexisting.get(), PMA: not self.regular.get(), CHECK_VERSIONING: not self.ignore_version.get(), STRICT_LINKING: not self.linking_warn.get(), VALIDATE: not self.novalidate.get(), EXTRAS: self.extras.get(), DEBUG: self.debug.get() } buffer = io.StringIO() if not kwargs[DEBUG]: sys.stdout = buffer sys.stderr = buffer else: self.log_text('--> DEBUG MODE: check console output') try: xlsform_convert(f, **kwargs) except ConvertError as e: print(str(e)) except OSError as e: # Should catch WindowsError, impossible to test on Mac traceback.print_exc() print(e) if not kwargs[DEBUG]: sys.stdout = sys.__stdout__ sys.stderr = sys.__stderr__ self.log_text(buffer.getvalue())
class MainFrame(Tk): """ Frame for screenlet """ def __init__(self): super().__init__() # Window without frame self.overrideredirect(1) # Set window transparency if system() == 'Linux': self.attributes('-type', 'normal') self.attributes('-alpha', 0.5) self.city = StringVar() try: # Read data from file with open('settings.ini', 'r') as file: data = file.readlines() # Window geometry and position geometry = data[0].strip() self.city.set(data[1].strip()) self.t_unit = data[2].strip() except: geometry = '' self.city.set('Kiev, UA') self.t_unit = 'metric' self.condition = StringVar() self.temperature = StringVar() self.currency = StringVar() self.start_x = 0 self.start_y = 0 # Set data for weather and currency exchange thread = Thread(target=self.get_data()) thread.start() if geometry == '': # Get screen size and calculate window position screen_width = self.winfo_screenwidth() screen_height = self.winfo_screenheight() x = screen_width - 320 - 20 y = screen_height - (screen_height - 100 - 100) # Set new position self.geometry(f'320x100+{x}+{y}') else: self.geometry(geometry) self.resizable(width=False, height=False) # Pressed over the window self.bind('<Button-1>', self.on_mouse_press) # Mouse is moved while being held down self.bind('<B1-Motion>', self.on_drag) # Context menu self.popup_menu = Menu(self, tearoff=0) self.popup_menu.add_command(label="Settings", command=self.settings) self.popup_menu.add_command(label="Exit", command=self.close) self.bind("<Button-3>", self.popup) self.init_widgets() def init_widgets(self): """ Set widgets position """ # Set widget for weather image self.image_label = Label(self, image=self.image) self.image_label.image = self.image self.image_label.pack(side='left') self.image_label.configure(image=self.image) # Show current weather and currency rate Label(self, textvariable=self.condition, fg='Teal', font=("Helvetica", 9, 'italic', 'bold')).pack(side='left') Label(self, textvariable=self.temperature, font=('Helvetica', 20, 'bold'), fg='orange').pack(expand=True) Label(self, textvariable=self.city, font=("Helvetica", 15, 'bold'), padx=10, fg='green').pack() Label(self, textvariable=self.currency, fg='Navy', font=("Helvetica", 10, 'bold')).pack() # Start timer for updating information about # weather and currency rate self.update_thread = Timer(20 * 60, self.get_data()) self.update_thread.start() def get_data(self): """ Set data for weather and currency exchange """ # Get information about current weather # and currency rate loop = get_event_loop() done, _ = loop.run_until_complete(wait([ get_weather(self.city.get(), self.t_unit), get_currency() ])) for item in done: if isinstance(item.result(), dict): weather = item.result() else: currency = item.result() # Update weather image img = Image.open(weather['icon']).resize( (110, 110), Image.ANTIALIAS) self.image = ImageTk.PhotoImage(img) # Set current weather self.condition.set(weather['humidity'] + '\n\n' + weather['wind'] + ' \n\n' + weather['description'].capitalize()) self.temperature.set('{:.1f}'.format( weather['temperature']) + ('° C' if weather['temperature_unit'] == 'metric' else '° F')) self.city.set(value=weather['city']) # Set currency rate (USD) self.currency.set('\n' + currency[0]) def popup(self, event): # Show context menu try: self.popup_menu.tk_popup(event.x_root, event.y_root, 0) finally: self.popup_menu.grab_release() def on_mouse_press(self, event): # Get mouse coordinates self.start_x = event.x self.start_y = event.y def on_drag(self, event): # Get current window position _, x, y = self.geometry().split('+') # Calculate new position x = int(x) + (event.x - self.start_x) y = int(y) + (event.y - self.start_y) # Move window self.geometry(f'+{x}+{y}') def settings(self): # Open program settings and disable current window settings_window = SettingsFrame(self) if system() == 'Windows': self.wm_attributes("-disabled", True) settings_window.mainloop() def close(self): # Save window geometry, position, # city and temperature unit with open('settings.ini', 'w') as file: print(self.geometry(), file=file) print(self.city.get(), file=file) print(self.t_unit, file=file) # Stop timer for updating information and exit self.update_thread.cancel() exit()
def on_button_release(event): if event.button != 3: # Right-click. return images = [*_iter_overlapping_normed_images(artist, event)] if not images: return def edit_norm(_arg=None): # Only some backends pass in an argument. axs = plt.figure().subplots(len(images), 1, squeeze=False)[:, 0] for ax, image in zip(axs, images): array = image.get_array() ax.hist(array.ravel(), _hist_bins(image), histtype="stepfilled") if isinstance(image.norm, mpl.colors.LogNorm): ax.set(xscale="log") elif array.dtype.kind in "iu": # not log. ax.xaxis.get_major_locator().set_params(integer=True) def on_select(vmin, vmax, *, _image=image): array = _image.get_array() if vmin == vmax: _image.set_clim((array.min(), array.max())) else: _image.set_clim((vmin, vmax)) _image.figure.canvas.draw() if hasattr(SpanSelector, "extents"): ss = SpanSelector(ax, on_select, "horizontal", useblit=True, interactive=True) ss.extents = (image.norm.vmin, image.norm.vmax) else: ss = SpanSelector(ax, on_select, "horizontal", useblit=True, span_stays=True) ss.stay_rect.set(x=image.norm.vmin, width=image.norm.vmax - image.norm.vmin, visible=True) _selectors.setdefault(ax, []).append(ss) plt.show(block=False) gui_event = event.guiEvent pkg = type(gui_event).__module__.split(".")[0] if pkg == "gi": from gi.repository import Gtk menu = Gtk.Menu() item = Gtk.MenuItem.new_with_label("Norm") menu.append(item) item.connect("activate", edit_norm) item.show() menu.popup_at_pointer(gui_event) elif pkg.startswith(("PyQt", "PySide")): from matplotlib.backends.qt_compat import QtWidgets menu = QtWidgets.QMenu() menu.addAction("Norm", edit_norm) menu.exec(gui_event.globalPos()) elif pkg == "tkinter": from tkinter import Menu menu = Menu(gui_event.widget, tearoff=0) menu.add_command(label="Norm", command=edit_norm) try: menu.tk_popup(gui_event.x_root, gui_event.y_root) finally: menu.grab_release() elif pkg == "wx": import wx menu = wx.Menu() item = menu.Append(wx.ID_ANY, "Norm") gui_event.EventObject.Bind(wx.EVT_MENU, edit_norm, id=item.Id) gui_event.EventObject.PopupMenu(menu) else: raise NotImplementedError("The current backend is not supported")
def on_button_release(event): if event.button != 3: # Right-click. return images = [*_iter_overlapping_normed_images(artist, event)] if not images: return def edit_norm(_arg=None): # Only some backends pass in an argument. try: im, = images except ValueError: raise NotImplementedError from None array = im.get_array().ravel() sub_ax = plt.figure().subplots() sub_ax.hist(array, _hist_bins(im), histtype="stepfilled") if isinstance(im.norm, mpl.colors.LogNorm): sub_ax.set(xscale="log") def on_select(vmin, vmax): if vmin == vmax: im.set_clim((array.min(), array.max())) else: im.set_clim((vmin, vmax)) im.figure.canvas.draw() ss = sub_ax.__ss = SpanSelector(sub_ax, on_select, "horizontal", useblit=True, span_stays=True) ss.stay_rect.set(x=im.norm.vmin, width=im.norm.vmax - im.norm.vmin, visible=True) plt.show(block=False) gui_event = event.guiEvent pkg = type(gui_event).__module__.split(".")[0] if pkg == "gi": from gi.repository import Gtk menu = Gtk.Menu() item = Gtk.MenuItem.new_with_label("Norm") menu.append(item) item.connect("activate", edit_norm) item.show() menu.popup_at_pointer(gui_event) elif pkg.startswith(("PyQt", "PySide")): from matplotlib.backends.qt_compat import QtWidgets menu = QtWidgets.QMenu() menu.addAction("Norm", edit_norm) menu.exec(gui_event.globalPos()) elif pkg == "tkinter": from tkinter import Menu menu = Menu(gui_event.widget, tearoff=0) menu.add_command(label="Norm", command=edit_norm) try: menu.tk_popup(gui_event.x_root, gui_event.y_root) finally: menu.grab_release() elif pkg == "wx": import wx menu = wx.Menu() item = menu.Append(wx.ID_ANY, "Norm") gui_event.EventObject.Bind(wx.EVT_MENU, edit_norm, id=item.Id) gui_event.EventObject.PopupMenu(menu) else: raise NotImplementedError("The current backend is not supported")