class GuiTestManager(Tk): """Manager for GUI tests. Use `add_test` method to add a test class.""" def __init__(self): """Initialise manager.""" Tk.__init__(self) self.title("GUI Test Manager") self.geometry("400x300") ## Dictionary of Toplevel tests who are current active. self.active_tests = {} ## List of all available test classes. self.all_tests = [] # Create widgets to show list of available tests. Label(self, text="Available Tests", font=("Comic Sans MS", "24")).pack(padx=3, pady=3) Label(self, text="Click a test to open it, and again to close it.", font=["Comic Sans MS"]).pack() # Create container for listbox and scrollbar. list_frame = Frame(self) list_frame.pack(fill="both", expand=1, padx=3, pady=3) # Add scrollbar for Listbox. list_scrollbar = Scrollbar(list_frame, orient="vertical") list_scrollbar.pack(side="right", fill="y") # Create Listbox next to scrollbar. self.all_tests_list = Listbox(list_frame, selectmode="multiple", yscrollcommand=list_scrollbar.set, selectborderwidth=5, font=("Comic Sans MS", "16", "italic"), activestyle="none", takefocus=1, cursor="pirate") # Bind the event for 0ms after a click, so the listbox can process first. self.all_tests_list.bind( "<ButtonPress-1>", lambda e: self.after(0, lambda e=e: self.on_test_list_pressed(e))) self.all_tests_list.pack(side="left", fill="both", expand=1) # Link scrollbar and listbox scroll commands. list_scrollbar.config(command=self.all_tests_list.yview) # Perform initial refresh. self.refresh_available() def add_test(self, test_class): """ Add a GUI test class to the test manager. Will do nothing if already added this test. """ if test_class in self.all_tests: return self.all_tests.append(test_class) self.refresh_available() def refresh_available(self): """Refresh list of available tests.""" # Delete old options. old_selection = self.all_tests_list.curselection() self.all_tests_list.delete(0, "end") # Show new options in Listbox from set. for test_class in self.all_tests: self.all_tests_list.insert("end", test_class.get_test_name()) # Maintain previous selection. for i in old_selection: self.all_tests_list.select_set(i) def on_test_list_pressed(self, event): """Called when mouse button 1 pressed on all_tests_list""" # All selected indexes. now_selected = set(self.all_tests_list.curselection()) # Check all options in Listbox. for i, test_class in enumerate(self.all_tests): if i in now_selected and i not in self.active_tests: # Index has been newly selected. Make the widget. new_wgt = test_class(self) new_wgt.protocol("WM_DELETE_WINDOW", lambda i=i: self.on_toplevel_destroyed(i)) self.active_tests[i] = new_wgt elif i not in now_selected and i in self.active_tests: # Index has been newly deselected. Destroy the widget. self.active_tests.pop(i).destroy() def on_toplevel_destroyed(self, index): """Called when initialised test window is manually destroyed.""" self.active_tests.pop(index).destroy() self.all_tests_list.select_clear(index)
class ChooseFilesPage(Frame): """Page for output files choice""" def __init__(self, parent, controller, *files): """ Arguments: `parent` (Frame): Parent page `controller` (Tk): Main controller page `files` (list): Available .out files """ super().__init__(parent) self.controller = controller self.files = sorted(files[0][0]) self.init_UI() # Create main GUI window def init_UI(self): txt = "Select the file(s) you want to post-process" label = Label(self, text=txt, font=LARGE_FONT) label.grid(row=0, columnspan=2, sticky='w') label_entry = Label(self, text='Filter:') label_entry.grid(row=1, column=0, sticky='w') self.search_var = StringVar() self.search_var.trace("w", lambda name, index, mode: self.update_list()) self.entry = Entry(self, textvariable=self.search_var, width=13) self.entry.grid(row=1, column=1, sticky='w') self.lbox = Listbox(self, width=45, height=15, selectmode='multiple') self.lbox.grid(row=2, columnspan=2) bu = ttk.Button(self, text='Select all', command=self.select_all) bu.grid(row=3, columnspan=2, sticky='w') bu = ttk.Button(self, text='Unselect all', command=self.unselect_all) bu.grid(row=4, columnspan=2, sticky='w') txt = "Display selected files" # Command allowing comunication to controller (Tk), calling # raise_displayer_files method with selected files in self.data cmd = partial(self.controller.raise_displayer_files) bu = ttk.Button(self, text=txt, command=cmd) bu.grid(row=5, columnspan=2, sticky='w') # update_list needs to be called here to populate the listbox self.update_list() def update_list(self): """ Update the list while doing the search with the filter Warning: the selection is reset when the listbox is updated! """ search_term = self.search_var.get() # Generic list to populate the listbox lbox_list = self.files self.lbox.delete(0, END) for item in lbox_list: if search_term.lower() in item.lower(): self.lbox.insert(END, item) def select_all(self): """Select all the file names""" self.lbox.select_set(0, END) def unselect_all(self): """Unselect all the file names""" self.lbox.select_clear(0, END)
class InstanceEditor(Toplevel): def __init__(self): Toplevel.__init__(self) self.focus_set() self.grab_set() self.result = None self.module_data = None self.mod_applis = None self.title(ugettext("Instance editor")) self.grid_columnconfigure(0, weight=1) self.grid_rowconfigure(0, weight=1) self.ntbk = ttk.Notebook(self) self.ntbk.grid(row=0, column=0, columnspan=1, sticky=(N, S, E, W)) self.frm_general = Frame(self.ntbk, width=350, height=150) self.frm_general.grid_columnconfigure(0, weight=0) self.frm_general.grid_columnconfigure(1, weight=1) self._general_tabs() self.ntbk.add(self.frm_general, text=ugettext('General')) self.frm_database = Frame(self.ntbk, width=350, height=150) self.frm_database.grid_columnconfigure(0, weight=0) self.frm_database.grid_columnconfigure(1, weight=1) self._database_tabs() self.ntbk.add(self.frm_database, text=ugettext('Database')) btnframe = Frame(self, bd=1) btnframe.grid(row=1, column=0, columnspan=1) Button(btnframe, text=ugettext("OK"), width=10, command=self.apply).grid( row=0, column=0, sticky=(N, S, E)) Button(btnframe, text=ugettext("Cancel"), width=10, command=self.destroy).grid( row=0, column=1, sticky=(N, S, W)) def _database_tabs(self): Label(self.frm_database, text=ugettext("Type")).grid( row=0, column=0, sticky=(N, W), padx=5, pady=3) self.typedb = ttk.Combobox( self.frm_database, textvariable=StringVar(), state=READLONY) self.typedb.bind("<<ComboboxSelected>>", self.typedb_selection) self.typedb.grid(row=0, column=1, sticky=(N, S, E, W), padx=5, pady=3) Label(self.frm_database, text=ugettext("Name")).grid( row=1, column=0, sticky=(N, W), padx=5, pady=3) self.namedb = Entry(self.frm_database) self.namedb.grid(row=1, column=1, sticky=(N, S, E, W), padx=5, pady=3) Label(self.frm_database, text=ugettext("User")).grid( row=2, column=0, sticky=(N, W), padx=5, pady=3) self.userdb = Entry(self.frm_database) self.userdb.grid(row=2, column=1, sticky=(N, S, E, W), padx=5, pady=3) Label(self.frm_database, text=ugettext("Password")).grid( row=3, column=0, sticky=(N, W), padx=5, pady=3) self.pwddb = Entry(self.frm_database) self.pwddb.grid(row=3, column=1, sticky=(N, S, E, W), padx=5, pady=3) def _general_tabs(self): Label(self.frm_general, text=ugettext("Name")).grid( row=0, column=0, sticky=(N, W), padx=5, pady=3) self.name = Entry(self.frm_general) self.name.grid(row=0, column=1, sticky=(N, S, E, W), padx=5, pady=3) Label(self.frm_general, text=ugettext("Appli")).grid( row=1, column=0, sticky=(N, W), padx=5, pady=3) self.applis = ttk.Combobox( self.frm_general, textvariable=StringVar(), state=READLONY) self.applis.bind("<<ComboboxSelected>>", self.appli_selection) self.applis.grid(row=1, column=1, sticky=(N, S, E, W), padx=5, pady=3) Label(self.frm_general, text=ugettext("Modules")).grid( row=2, column=0, sticky=(N, W), padx=5, pady=3) self.modules = Listbox(self.frm_general, selectmode=EXTENDED) self.modules.configure(exportselection=False) self.modules.grid(row=2, column=1, sticky=(N, S, E, W), padx=5, pady=3) Label(self.frm_general, text=ugettext("Language")).grid( row=3, column=0, sticky=(N, W), padx=5, pady=3) self.language = ttk.Combobox( self.frm_general, textvariable=StringVar(), state=READLONY) self.language.grid( row=3, column=1, sticky=(N, S, E, W), padx=5, pady=3) Label(self.frm_general, text=ugettext("CORE-connectmode") ).grid(row=4, column=0, sticky=(N, W), padx=5, pady=3) self.mode = ttk.Combobox( self.frm_general, textvariable=StringVar(), state=READLONY) self.mode.bind("<<ComboboxSelected>>", self.mode_selection) self.mode.grid(row=4, column=1, sticky=(N, S, E, W), padx=5, pady=3) Label(self.frm_general, text=ugettext("Password")).grid( row=5, column=0, sticky=(N, W), padx=5, pady=3) self.password = Entry(self.frm_general, show="*") self.password.grid( row=5, column=1, sticky=(N, S, E, W), padx=5, pady=3) def typedb_selection(self, event): visible = list(self.typedb[VALUES]).index(self.typedb.get()) != 0 for child_cmp in self.frm_database.winfo_children()[2:]: if visible: child_cmp.config(state=NORMAL) else: child_cmp.config(state=DISABLED) def appli_selection(self, event): if self.applis.get() != '': appli_id = list(self.applis[VALUES]).index(self.applis.get()) luct_glo = LucteriosGlobal() current_inst_names = luct_glo.listing() appli_root_name = self.mod_applis[appli_id][0].split('.')[-1] default_name_idx = 1 while appli_root_name + six.text_type(default_name_idx) in current_inst_names: default_name_idx += 1 self.name.delete(0, END) self.name.insert( 0, appli_root_name + six.text_type(default_name_idx)) mod_depended = self.mod_applis[appli_id][2] self.modules.select_clear(0, self.modules.size()) for mod_idx in range(len(self.module_data)): current_mod = self.module_data[mod_idx] if current_mod in mod_depended: self.modules.selection_set(mod_idx) def mode_selection(self, event): visible = list(self.mode[VALUES]).index(self.mode.get()) != 2 for child_cmp in self.frm_general.winfo_children()[-2:]: if visible: child_cmp.config(state=NORMAL) else: child_cmp.config(state=DISABLED) def apply(self): from lucterios.framework.settings import DEFAULT_LANGUAGES, get_locale_lang if self.name.get() == '': showerror(ugettext("Instance editor"), ugettext("Name empty!")) return if self.applis.get() == '': showerror(ugettext("Instance editor"), ugettext("No application!")) return db_param = "%s:name=%s,user=%s,password=%s" % ( self.typedb.get(), self.namedb.get(), self.userdb.get(), self.pwddb.get()) security = "MODE=%s" % list( self.mode[VALUES]).index(self.mode.get()) if self.password.get() != '': security += ",PASSWORD=%s" % self.password.get() module_list = [ self.module_data[int(item)] for item in self.modules.curselection()] appli_id = list(self.applis[VALUES]).index(self.applis.get()) current_lang = get_locale_lang() for lang in DEFAULT_LANGUAGES: if lang[1] == self.language.get(): current_lang = lang[0] self.result = (self.name.get(), self.mod_applis[appli_id][ 0], ",".join(module_list), security, db_param, current_lang) self.destroy() def _load_current_data(self, instance_name): from lucterios.framework.settings import DEFAULT_LANGUAGES, get_locale_lang lct_inst = LucteriosInstance(instance_name) lct_inst.read() self.name.delete(0, END) self.name.insert(0, lct_inst.name) self.name.config(state=DISABLED) applis_id = 0 for appli_iter in range(len(self.mod_applis)): if self.mod_applis[appli_iter][0] == lct_inst.appli_name: applis_id = appli_iter break self.applis.current(applis_id) if lct_inst.extra['']['mode'] is not None: self.mode.current(lct_inst.extra['']['mode'][0]) else: self.mode.current(2) self.mode_selection(None) typedb_index = 0 for typedb_idx in range(len(self.typedb[VALUES])): if self.typedb[VALUES][typedb_idx].lower() == lct_inst.database[0].lower(): typedb_index = typedb_idx break self.typedb.current(typedb_index) self.typedb.config(state=DISABLED) self.typedb_selection(None) self.namedb.delete(0, END) if 'name' in lct_inst.database[1].keys(): self.namedb.insert(0, lct_inst.database[1]['name']) self.userdb.delete(0, END) if 'user' in lct_inst.database[1].keys(): self.userdb.insert(0, lct_inst.database[1]['user']) self.pwddb.delete(0, END) if 'password' in lct_inst.database[1].keys(): self.pwddb.insert(0, lct_inst.database[1]['password']) self.modules.select_clear(0, self.modules.size()) for mod_idx in range(len(self.module_data)): current_mod = self.module_data[mod_idx] if current_mod in lct_inst.modules: self.modules.select_set(mod_idx) current_lang = get_locale_lang() if 'LANGUAGE_CODE' in lct_inst.extra.keys(): current_lang = lct_inst.extra['LANGUAGE_CODE'] for lang in DEFAULT_LANGUAGES: if lang[0] == current_lang: self.language.current(self.language[VALUES].index(lang[1])) def execute(self, instance_name=None): from lucterios.framework.settings import DEFAULT_LANGUAGES, get_locale_lang self.mode[VALUES] = [ugettext( "CORE-connectmode.0"), ugettext("CORE-connectmode.1"), ugettext("CORE-connectmode.2")] self.language[VALUES] = [lang[1] for lang in DEFAULT_LANGUAGES] self.typedb[VALUES] = ["SQLite", "MySQL", "PostgreSQL"] lct_glob = LucteriosGlobal() _, self.mod_applis, mod_modules = lct_glob.installed() self.mod_applis.sort(key=lambda item: get_module_title(item[0])) self.modules.delete(0, END) self.module_data = [] module_list = [] for mod_module_item in mod_modules: module_list.append( (get_module_title(mod_module_item[0]), mod_module_item[0])) module_list.sort(key=lambda module: module[0]) for module_title, module_name in module_list: self.modules.insert(END, module_title) self.module_data.append(module_name) appli_list = [] for mod_appli_item in self.mod_applis: appli_list.append(get_module_title(mod_appli_item[0])) self.applis[VALUES] = appli_list if instance_name is not None: self._load_current_data(instance_name) else: self.typedb.current(0) self.mode.current(2) if len(appli_list) > 0: self.applis.current(0) self.appli_selection(None) self.mode_selection(None) self.typedb_selection(None) for lang in DEFAULT_LANGUAGES: if lang[0] == get_locale_lang(): self.language.current(self.language[VALUES].index(lang[1])) center(self)
class FileChoice(object): def __init__(self, master=None, title=None, prefix=None, list=[], start='', ext="txt", new=False): self.master = master self.value = None self.prefix = prefix self.list = list if prefix and start: self.start = relpath(start, prefix) else: self.start = start self.ext = ext self.new = new self.modalPane = Toplevel(self.master, highlightbackground=BGCOLOR, background=BGCOLOR) if master: logger.debug('winfo: {0}, {1}; {2}, {3}'.format( master.winfo_rootx(), type(master.winfo_rootx()), master.winfo_rooty(), type(master.winfo_rooty()))) self.modalPane.geometry( "+%d+%d" % (master.winfo_rootx() + 50, master.winfo_rooty() + 50)) self.modalPane.transient(self.master) self.modalPane.grab_set() self.modalPane.bind("<Return>", self._choose) self.modalPane.bind("<Escape>", self._cancel) if title: self.modalPane.title(title) if new: nameFrame = Frame(self.modalPane, highlightbackground=BGCOLOR, background=BGCOLOR) nameFrame.pack(side="top", padx=18, pady=2, fill="x") nameLabel = Label(nameFrame, text=_("file:"), bd=1, relief="flat", anchor="w", padx=0, pady=0, highlightbackground=BGCOLOR, background=BGCOLOR) nameLabel.pack(side="left") self.fileName = StringVar(self.modalPane) self.fileName.set("untitled.{0}".format(ext)) self.fileName.trace_variable("w", self.onSelect) self.fname = Entry(nameFrame, textvariable=self.fileName, bd=1, highlightbackground=BGCOLOR) self.fname.pack(side="left", fill="x", expand=1, padx=0, pady=0) self.fname.icursor(END) self.fname.bind("<Up>", self.cursorUp) self.fname.bind("<Down>", self.cursorDown) filterFrame = Frame(self.modalPane, highlightbackground=BGCOLOR, background=BGCOLOR) filterFrame.pack(side="top", padx=18, pady=4, fill="x") filterLabel = Label(filterFrame, text=_("filter:"), bd=1, relief="flat", anchor="w", padx=0, pady=0, highlightbackground=BGCOLOR, background=BGCOLOR) filterLabel.pack(side="left") self.filterValue = StringVar(self.modalPane) self.filterValue.set("") self.filterValue.trace_variable("w", self.setMatching) self.fltr = Entry(filterFrame, textvariable=self.filterValue, bd=1, highlightbackground=BGCOLOR) self.fltr.pack(side="left", fill="x", expand=1, padx=0, pady=0) self.fltr.icursor(END) prefixFrame = Frame(self.modalPane, highlightbackground=BGCOLOR, background=BGCOLOR) prefixFrame.pack(side="top", padx=8, pady=2, fill="x") self.prefixLabel = Label(prefixFrame, text=_("{0}:").format(prefix), bd=1, highlightbackground=BGCOLOR, background=BGCOLOR) self.prefixLabel.pack(side="left", expand=0, padx=0, pady=0) buttonFrame = Frame(self.modalPane, highlightbackground=BGCOLOR, background=BGCOLOR) buttonFrame.pack(side="bottom", padx=10, pady=2) chooseButton = Button(buttonFrame, text="Choose", command=self._choose, highlightbackground=BGCOLOR, background=BGCOLOR, pady=2) chooseButton.pack(side="right", padx=10) cancelButton = Button(buttonFrame, text="Cancel", command=self._cancel, highlightbackground=BGCOLOR, background=BGCOLOR, pady=2) cancelButton.pack(side="left") selectionFrame = Frame(self.modalPane, highlightbackground=BGCOLOR, background=BGCOLOR) selectionFrame.pack(side="bottom", padx=8, pady=2, fill="x") self.selectionValue = StringVar(self.modalPane) self.selectionValue.set("") self.selection = Label(selectionFrame, textvariable=self.selectionValue, bd=1, highlightbackground=BGCOLOR, background=BGCOLOR) self.selection.pack(side="left", fill="x", expand=1, padx=0, pady=0) listFrame = Frame(self.modalPane, highlightbackground=BGCOLOR, background=BGCOLOR, width=40) listFrame.pack(side="top", fill="both", expand=1, padx=5, pady=2) scrollBar = Scrollbar(listFrame, width=8) scrollBar.pack(side="right", fill="y") self.listBox = Listbox(listFrame, selectmode=BROWSE, width=36) self.listBox.pack(side="left", fill="both", expand=1, ipadx=4, padx=2, pady=0) self.listBox.bind('<<ListboxSelect>>', self.onSelect) self.listBox.bind("<Double-1>", self._choose) self.modalPane.bind("<Return>", self._choose) self.modalPane.bind("<Escape>", self._cancel) # self.modalPane.bind("<Up>", self.cursorUp) # self.modalPane.bind("<Down>", self.cursorDown) self.fltr.bind("<Up>", self.cursorUp) self.fltr.bind("<Down>", self.cursorDown) scrollBar.config(command=self.listBox.yview) self.listBox.config(yscrollcommand=scrollBar.set) self.setMatching() def ignore(self, e=None): return "break" def onSelect(self, *args): # Note here that Tkinter passes an event object to onselect() if self.listBox.curselection(): firstIndex = self.listBox.curselection()[0] value = self.matches[int(firstIndex)] r = value[1] p = os.path.join(self.prefix, r) if self.new: if os.path.isfile(p): p = os.path.split(p)[0] r = os.path.split(r)[0] f = self.fileName.get() r = os.path.join(r, f) p = os.path.join(p, f) self.selectionValue.set(r) self.value = p return "break" def cursorUp(self, event=None): cursel = int(self.listBox.curselection()[0]) newsel = max(0, cursel - 1) self.listBox.select_clear(cursel) self.listBox.select_set(newsel) self.listBox.see(newsel) self.onSelect() return "break" def cursorDown(self, event=None): cursel = int(self.listBox.curselection()[0]) newsel = min(len(self.list) - 1, cursel + 1) self.listBox.select_clear(cursel) self.listBox.select_set(newsel) self.listBox.see(newsel) self.onSelect() return "break" def setMatching(self, *args): # disabled = "#BADEC3" # disabled = "#91CC9E" disabled = "#62B374" match = self.filterValue.get() if match: self.matches = matches = [ x for x in self.list if x and match.lower() in x[1].lower() ] else: self.matches = matches = self.list self.listBox.delete(0, END) index = 0 init_index = 0 for item in matches: if type(item) is tuple: # only show the label # (label, value, disabled)FF self.listBox.insert(END, item[0]) if self.new: if not item[-1]: self.listBox.itemconfig(index, fg=disabled) else: self.listBox.itemconfig(index, fg="blue") if self.start and item[1] == self.start: init_index = index else: if item[-1]: self.listBox.itemconfig(index, fg=disabled) else: self.listBox.itemconfig(index, fg="blue") if self.start and item[1] == self.start: init_index = index # elif files: else: self.listBox.insert(END, item) index += 1 self.listBox.select_set(init_index) self.listBox.see(init_index) self.fltr.focus_set() self.onSelect() def _choose(self, event=None): try: if self.listBox.curselection(): firstIndex = self.listBox.curselection()[0] if self.new: if not self.value or os.path.isfile(self.value): return else: tup = self.matches[int(firstIndex)] if tup[-1]: return self.value = os.path.join(self.prefix, tup[1]) else: return except IndexError: self.value = None self.modalPane.destroy() def _cancel(self, event=None): self.value = None self.modalPane.destroy() def returnValue(self): self.master.wait_window(self.modalPane) return self.value
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 GetKeysDialog(Toplevel): # Dialog title for invalid key sequence keyerror_title = 'Key Sequence Error' def __init__(self, parent, title, action, current_key_sequences, *, _htest=False, _utest=False): """ parent - parent of this dialog title - string which is the title of the popup dialog action - string, the name of the virtual event these keys will be mapped to current_key_sequences - list, a list of all key sequence lists currently mapped to virtual events, for overlap checking _htest - bool, change box location when running htest _utest - bool, do not wait when running unittest """ Toplevel.__init__(self, parent) self.withdraw() # Hide while setting geometry. self.configure(borderwidth=5) self.resizable(height=False, width=False) self.title(title) self.transient(parent) self.grab_set() self.protocol("WM_DELETE_WINDOW", self.cancel) self.parent = parent self.action = action self.current_key_sequences = current_key_sequences self.result = '' self.key_string = StringVar(self) self.key_string.set('') # Set self.modifiers, self.modifier_label. self.set_modifiers_for_platform() self.modifier_vars = [] for modifier in self.modifiers: variable = StringVar(self) variable.set('') self.modifier_vars.append(variable) self.advanced = False self.create_widgets() self.update_idletasks() self.geometry("+%d+%d" % (parent.winfo_rootx() + (parent.winfo_width() / 2 - self.winfo_reqwidth() / 2), parent.winfo_rooty() + ((parent.winfo_height() / 2 - self.winfo_reqheight() / 2) if not _htest else 150)) ) # Center dialog over parent (or below htest box). if not _utest: self.deiconify() # Geometry set, unhide. self.wait_window() def showerror(self, *args, **kwargs): # Make testing easier. Replace in #30751. messagebox.showerror(*args, **kwargs) def create_widgets(self): self.frame = frame = Frame(self, borderwidth=2, relief='sunken') frame.pack(side='top', expand=True, fill='both') frame_buttons = Frame(self) frame_buttons.pack(side='bottom', fill='x') self.button_ok = Button(frame_buttons, text='OK', width=8, command=self.ok) self.button_ok.grid(row=0, column=0, padx=5, pady=5) self.button_cancel = Button(frame_buttons, text='Cancel', width=8, command=self.cancel) self.button_cancel.grid(row=0, column=1, padx=5, pady=5) # Basic entry key sequence. self.frame_keyseq_basic = Frame(frame, name='keyseq_basic') self.frame_keyseq_basic.grid(row=0, column=0, sticky='nsew', padx=5, pady=5) basic_title = Label(self.frame_keyseq_basic, text=f"New keys for '{self.action}' :") basic_title.pack(anchor='w') basic_keys = Label(self.frame_keyseq_basic, justify='left', textvariable=self.key_string, relief='groove', borderwidth=2) basic_keys.pack(ipadx=5, ipady=5, fill='x') # Basic entry controls. self.frame_controls_basic = Frame(frame) self.frame_controls_basic.grid(row=1, column=0, sticky='nsew', padx=5) # Basic entry modifiers. self.modifier_checkbuttons = {} column = 0 for modifier, variable in zip(self.modifiers, self.modifier_vars): label = self.modifier_label.get(modifier, modifier) check = Checkbutton(self.frame_controls_basic, command=self.build_key_string, text=label, variable=variable, onvalue=modifier, offvalue='') check.grid(row=0, column=column, padx=2, sticky='w') self.modifier_checkbuttons[modifier] = check column += 1 # Basic entry help text. help_basic = Label(self.frame_controls_basic, justify='left', text="Select the desired modifier keys\n" + "above, and the final key from the\n" + "list on the right.\n\n" + "Use upper case Symbols when using\n" + "the Shift modifier. (Letters will be\n" + "converted automatically.)") help_basic.grid(row=1, column=0, columnspan=4, padx=2, sticky='w') # Basic entry key list. self.list_keys_final = Listbox(self.frame_controls_basic, width=15, height=10, selectmode='single') self.list_keys_final.insert('end', *AVAILABLE_KEYS) self.list_keys_final.bind('<ButtonRelease-1>', self.final_key_selected) self.list_keys_final.grid(row=0, column=4, rowspan=4, sticky='ns') scroll_keys_final = Scrollbar(self.frame_controls_basic, orient='vertical', command=self.list_keys_final.yview) self.list_keys_final.config(yscrollcommand=scroll_keys_final.set) scroll_keys_final.grid(row=0, column=5, rowspan=4, sticky='ns') self.button_clear = Button(self.frame_controls_basic, text='Clear Keys', command=self.clear_key_seq) self.button_clear.grid(row=2, column=0, columnspan=4) # Advanced entry key sequence. self.frame_keyseq_advanced = Frame(frame, name='keyseq_advanced') self.frame_keyseq_advanced.grid(row=0, column=0, sticky='nsew', padx=5, pady=5) advanced_title = Label( self.frame_keyseq_advanced, justify='left', text=f"Enter new binding(s) for '{self.action}' :\n" + "(These bindings will not be checked for validity!)") advanced_title.pack(anchor='w') self.advanced_keys = Entry(self.frame_keyseq_advanced, textvariable=self.key_string) self.advanced_keys.pack(fill='x') # Advanced entry help text. self.frame_help_advanced = Frame(frame) self.frame_help_advanced.grid(row=1, column=0, sticky='nsew', padx=5) help_advanced = Label( self.frame_help_advanced, justify='left', text="Key bindings are specified using Tkinter keysyms as\n" + "in these samples: <Control-f>, <Shift-F2>, <F12>,\n" "<Control-space>, <Meta-less>, <Control-Alt-Shift-X>.\n" "Upper case is used when the Shift modifier is present!\n\n" + "'Emacs style' multi-keystroke bindings are specified as\n" + "follows: <Control-x><Control-y>, where the first key\n" + "is the 'do-nothing' keybinding.\n\n" + "Multiple separate bindings for one action should be\n" + "separated by a space, eg., <Alt-v> <Meta-v>.") help_advanced.grid(row=0, column=0, sticky='nsew') # Switch between basic and advanced. self.button_level = Button(frame, command=self.toggle_level, text='<< Basic Key Binding Entry') self.button_level.grid(row=2, column=0, stick='ew', padx=5, pady=5) self.toggle_level() def set_modifiers_for_platform(self): """Determine list of names of key modifiers for this platform. The names are used to build Tk bindings -- it doesn't matter if the keyboard has these keys; it matters if Tk understands them. The order is also important: key binding equality depends on it, so config-keys.def must use the same ordering. """ if sys.platform == "darwin": self.modifiers = ['Shift', 'Control', 'Option', 'Command'] else: self.modifiers = ['Control', 'Alt', 'Shift'] self.modifier_label = {'Control': 'Ctrl'} # Short name. def toggle_level(self): "Toggle between basic and advanced keys." if self.button_level.cget('text').startswith('Advanced'): self.clear_key_seq() self.button_level.config(text='<< Basic Key Binding Entry') self.frame_keyseq_advanced.lift() self.frame_help_advanced.lift() self.advanced_keys.focus_set() self.advanced = True else: self.clear_key_seq() self.button_level.config(text='Advanced Key Binding Entry >>') self.frame_keyseq_basic.lift() self.frame_controls_basic.lift() self.advanced = False def final_key_selected(self, event=None): "Handler for clicking on key in basic settings list." self.build_key_string() def build_key_string(self): "Create formatted string of modifiers plus the key." keylist = modifiers = self.get_modifiers() final_key = self.list_keys_final.get('anchor') if final_key: final_key = translate_key(final_key, modifiers) keylist.append(final_key) self.key_string.set(f"<{'-'.join(keylist)}>") def get_modifiers(self): "Return ordered list of modifiers that have been selected." mod_list = [variable.get() for variable in self.modifier_vars] return [mod for mod in mod_list if mod] def clear_key_seq(self): "Clear modifiers and keys selection." self.list_keys_final.select_clear(0, 'end') self.list_keys_final.yview('moveto', '0.0') for variable in self.modifier_vars: variable.set('') self.key_string.set('') def ok(self, event=None): keys = self.key_string.get().strip() if not keys: self.showerror(title=self.keyerror_title, parent=self, message="No key specified.") return if (self.advanced or self.keys_ok(keys)) and self.bind_ok(keys): self.result = keys self.grab_release() self.destroy() def cancel(self, event=None): self.result = '' self.grab_release() self.destroy() def keys_ok(self, keys): """Validity check on user's 'basic' keybinding selection. Doesn't check the string produced by the advanced dialog because 'modifiers' isn't set. """ final_key = self.list_keys_final.get('anchor') modifiers = self.get_modifiers() title = self.keyerror_title key_sequences = [ key for keylist in self.current_key_sequences for key in keylist ] if not keys.endswith('>'): self.showerror(title, parent=self, message='Missing the final Key') elif (not modifiers and final_key not in FUNCTION_KEYS + MOVE_KEYS): self.showerror(title=title, parent=self, message='No modifier key(s) specified.') elif (modifiers == ['Shift']) \ and (final_key not in FUNCTION_KEYS + MOVE_KEYS + ('Tab', 'Space')): msg = 'The shift modifier by itself may not be used with'\ ' this key symbol.' self.showerror(title=title, parent=self, message=msg) elif keys in key_sequences: msg = 'This key combination is already in use.' self.showerror(title=title, parent=self, message=msg) else: return True return False def bind_ok(self, keys): "Return True if Tcl accepts the new keys else show message." try: binding = self.bind(keys, lambda: None) except TclError as err: self.showerror( title=self.keyerror_title, parent=self, message=(f'The entered key sequence is not accepted.\n\n' f'Error: {err}')) return False else: self.unbind(keys, binding) return True
class ImageZip(Frame): def __init__(self, parent): # Bind Frame to self and begin UI Frame.__init__(self, parent) self.parent = parent self.onGetZipResults = {} self.imagetypes = [("Image file", "*.jpg"), ("Image file", "*.jpeg"), ("Image file", "*.jfif"), ("Image file", "*.jpe"), ("Image file", "*.jfi"), ("Image file", "*.jif")] self.initUI() def initUI(self): # Creating UI elements and action calls self.parent.title("JPEG 2 Zip Code") self.pack(fill=BOTH, expand=True) # Menu menubar = Menu(self.parent) fileMenu = Menu(menubar, tearoff=False) fileMenu.add_command(label="Open File(s)", command=self.onOpenFile) fileMenu.add_command(label="Exit", command=self.parent.quit) menubar.add_cascade(label="File", menu=fileMenu) self.editMenu = Menu(menubar, tearoff=False) self.editMenu.add_command(label="Select All", command=self.onSelectAll) self.editMenu.add_command(label="Deselect All", command=self.onDeselectAll) menubar.add_cascade(label="Edit", menu=self.editMenu) self.actionMenu = Menu(menubar, tearoff=False) self.actionMenu.add_command(label="Get ZIP Codes", command=self.onGetZIP) menubar.add_cascade(label="Action", menu=self.actionMenu) self.parent.config(menu=menubar) self.menuItemAccess( False) # Disable unneeded menu items until files loaded # Listbox which will hold opened file names and allow selection self.listboxFiles = Listbox(self.parent, selectmode=EXTENDED) self.listboxFiles.pack(fill=BOTH, expand=True) def onDeselectAll(self): self.listboxFiles.select_clear(0, END) def onSelectAll(self): self.listboxFiles.select_set(0, END) # Takes in boolean, TRUE = allow access, FALSE = disable access def menuItemAccess(self, viewable): if viewable == True: self.editMenu.entryconfig(0, state=NORMAL) self.editMenu.entryconfig(1, state=NORMAL) self.actionMenu.entryconfig(0, state=NORMAL) if viewable == False: self.editMenu.entryconfig(0, state=DISABLED) self.editMenu.entryconfig(1, state=DISABLED) self.actionMenu.entryconfig(0, state=DISABLED) def badImageDialog(self, badimagefiles): # Takes in a list of files and produces a warning dialog fileerrors = "" for file in badimagefiles: fileerrors += str(file) + '\n' messagebox.showwarning( "Error Loading All Images", "Not all images were found to be valid. The following files will not be loaded...\n" + fileerrors) def onGetZIP(self): # Produces GPS, then ZIP codes for all selected files in the UI. geolocator = Nominatim(user_agent="JPEG2ZIP") selectedfiles = self.listboxFiles.curselection() for item in selectedfiles: currentFile = self.listboxFiles.get(item) currentGPS = getEXIF().load(currentFile) print(currentGPS) try: temp = geolocator.reverse(currentGPS) currentZIP = temp.raw['address']['postcode'] except: # If ZIP code not found or coords are (0.0, 0.0) currentZIP = "Error" # Unused right now but still saved. # Adds {index: FileName, GPS Coords, ZIP code} to dictionary self.onGetZipResults.update( {item: (currentFile, getEXIF().load(currentFile), currentZIP)}) #Update UI self.listboxFiles.delete(item) self.listboxFiles.insert(item, currentFile + ' ' + currentZIP) #print(self.onGetZipResults) def onOpenFile(self): # TODO: Grab and display thumbnails with file name. fl = filedialog.askopenfilenames(filetypes=self.imagetypes) # Image validity check and update UI with file names print('Opening...') badimagefiles = [] if fl != '': for file in fl: if (self.isValidJPEG(file) == True): # is valid print('\t' + file) self.listboxFiles.insert(END, file) if (self.isValidJPEG(file) == False): # is invalid badimagefiles.append(file) if len(badimagefiles) > 0: # push bad images to dialog box self.badImageDialog(badimagefiles) # Enable Menu items self.menuItemAccess(True) def isValidJPEG(self, imageFile): # TODO: use library to check validity of image. No need to reinvent the wheel. try: data = open(imageFile, 'rb').read(11) #read first 11 bytes # All JPEG image files start off with SOI '0xff 0xd8'. # This is slightly unnecessary. See TODO above. if data[:2] != b'\xff\xd8': #Bad SOI return False return True except: print("Image Validation Error: Unable to open image " + imageFile) # sanity check (print to console) return False
class InstanceEditor(Toplevel, EditorInstance): def __init__(self): Toplevel.__init__(self) EditorInstance.__init__(self) self.focus_set() self.grab_set() self.result = None self.module_data = None self.mod_applis = None self.title(ugettext("Instance editor")) self.grid_columnconfigure(0, weight=1) self.grid_rowconfigure(0, weight=1) self.ntbk = ttk.Notebook(self) self.ntbk.grid(row=0, column=0, columnspan=1, sticky=(N, S, E, W)) self.frm_general = Frame(self.ntbk, width=350, height=150) self.frm_general.grid_columnconfigure(0, weight=0) self.frm_general.grid_columnconfigure(1, weight=1) self._general_tabs() self.ntbk.add(self.frm_general, text=ugettext('General')) self.frm_database = Frame(self.ntbk, width=350, height=150) self.frm_database.grid_columnconfigure(0, weight=0) self.frm_database.grid_columnconfigure(1, weight=1) self._database_tabs() self.ntbk.add(self.frm_database, text=ugettext('Database')) btnframe = Frame(self, bd=1) btnframe.grid(row=1, column=0, columnspan=1) Button(btnframe, text=ugettext("OK"), width=10, command=self.apply).grid(row=0, column=0, sticky=(N, S, E)) Button(btnframe, text=ugettext("Cancel"), width=10, command=self.destroy).grid(row=0, column=1, sticky=(N, S, W)) def _database_tabs(self): Label(self.frm_database, text=ugettext("Type")).grid(row=0, column=0, sticky=(N, W), padx=5, pady=3) self.typedb = ttk.Combobox(self.frm_database, textvariable=StringVar(), state=READLONY) self.typedb.bind("<<ComboboxSelected>>", self.typedb_selection) self.typedb.grid(row=0, column=1, sticky=(N, S, E, W), padx=5, pady=3) Label(self.frm_database, text=ugettext("Name")).grid(row=1, column=0, sticky=(N, W), padx=5, pady=3) self.namedb = Entry(self.frm_database) self.namedb.grid(row=1, column=1, sticky=(N, S, E, W), padx=5, pady=3) Label(self.frm_database, text=ugettext("User")).grid(row=2, column=0, sticky=(N, W), padx=5, pady=3) self.userdb = Entry(self.frm_database) self.userdb.grid(row=2, column=1, sticky=(N, S, E, W), padx=5, pady=3) Label(self.frm_database, text=ugettext("Password")).grid(row=3, column=0, sticky=(N, W), padx=5, pady=3) self.pwddb = Entry(self.frm_database) self.pwddb.grid(row=3, column=1, sticky=(N, S, E, W), padx=5, pady=3) def _general_tabs(self): Label(self.frm_general, text=ugettext("Name")).grid(row=0, column=0, sticky=(N, W), padx=5, pady=3) self.name = Entry(self.frm_general) self.name.grid(row=0, column=1, sticky=(N, S, E, W), padx=5, pady=3) Label(self.frm_general, text=ugettext("Appli")).grid(row=1, column=0, sticky=(N, W), padx=5, pady=3) self.applis = ttk.Combobox(self.frm_general, textvariable=StringVar(), state=READLONY) self.applis.bind("<<ComboboxSelected>>", self.appli_selection) self.applis.grid(row=1, column=1, sticky=(N, S, E, W), padx=5, pady=3) Label(self.frm_general, text=ugettext("Modules")).grid(row=2, column=0, sticky=(N, W), padx=5, pady=3) self.modules = Listbox(self.frm_general, selectmode=EXTENDED) self.modules.configure(exportselection=False) self.modules.grid(row=2, column=1, sticky=(N, S, E, W), padx=5, pady=3) Label(self.frm_general, text=ugettext("Language")).grid(row=3, column=0, sticky=(N, W), padx=5, pady=3) self.language = ttk.Combobox(self.frm_general, textvariable=StringVar(), state=READLONY) self.language.grid(row=3, column=1, sticky=(N, S, E, W), padx=5, pady=3) Label(self.frm_general, text=ugettext("CORE-connectmode")).grid(row=4, column=0, sticky=(N, W), padx=5, pady=3) self.mode = ttk.Combobox(self.frm_general, textvariable=StringVar(), state=READLONY) self.mode.bind("<<ComboboxSelected>>", self.mode_selection) self.mode.grid(row=4, column=1, sticky=(N, S, E, W), padx=5, pady=3) Label(self.frm_general, text=ugettext("Password")).grid(row=5, column=0, sticky=(N, W), padx=5, pady=3) self.password = Entry(self.frm_general, show="*") self.password.grid(row=5, column=1, sticky=(N, S, E, W), padx=5, pady=3) def typedb_selection(self, event): visible = list(self.typedb[VALUES]).index(self.typedb.get()) != 0 for child_cmp in self.frm_database.winfo_children()[2:]: if visible: child_cmp.config(state=NORMAL) else: child_cmp.config(state=DISABLED) def appli_selection(self, event): if self.applis.get() != '': appli_id = list(self.applis[VALUES]).index(self.applis.get()) luct_glo = LucteriosGlobal() current_inst_names = luct_glo.listing() appli_root_name = self.mod_applis[appli_id][0].split('.')[-1] default_name_idx = 1 while appli_root_name + six.text_type( default_name_idx) in current_inst_names: default_name_idx += 1 self.name.delete(0, END) self.name.insert(0, appli_root_name + six.text_type(default_name_idx)) mod_depended = self.mod_applis[appli_id][2] self.modules.select_clear(0, self.modules.size()) for mod_idx in range(len(self.module_data)): current_mod = self.module_data[mod_idx] if current_mod in mod_depended: self.modules.selection_set(mod_idx) def mode_selection(self, event): visible = list(self.mode[VALUES]).index(self.mode.get()) != 2 for child_cmp in self.frm_general.winfo_children()[-2:]: if visible: child_cmp.config(state=NORMAL) else: child_cmp.config(state=DISABLED) def apply(self): from lucterios.framework.settings import DEFAULT_LANGUAGES, get_locale_lang if self.is_new_instance and ( (self.name.get() == '') or (self.name_rull.match(self.name.get()) is None)): showerror(ugettext("Instance editor"), ugettext("Name invalid!")) return if self.applis.get() == '': showerror(ugettext("Instance editor"), ugettext("No application!")) return db_param = "%s:name=%s,user=%s,password=%s" % ( self.typedb.get(), self.namedb.get(), self.userdb.get(), self.pwddb.get()) security = "MODE=%s" % list(self.mode[VALUES]).index(self.mode.get()) if self.password.get() != '': security += ",PASSWORD=%s" % self.password.get() module_list = [ self.module_data[int(item)] for item in self.modules.curselection() ] appli_id = list(self.applis[VALUES]).index(self.applis.get()) current_lang = get_locale_lang() for lang in DEFAULT_LANGUAGES: if lang[1] == self.language.get(): current_lang = lang[0] self.result = (self.name.get(), self.mod_applis[appli_id][0], ",".join(module_list), security, db_param, current_lang) self.destroy() def _load_current_data(self, instance_name): from lucterios.framework.settings import DEFAULT_LANGUAGES lct_inst, applis_id, mode_id, typedb_index, current_lang = self._get_instance_elements( instance_name) self.is_new_instance = False self.name.delete(0, END) self.name.insert(0, lct_inst.name) self.name.config(state=DISABLED) self.applis.current(applis_id) self.mode.current(mode_id) self.mode_selection(None) self.typedb.current(typedb_index) self.typedb.config(state=DISABLED) self.typedb_selection(None) self.namedb.delete(0, END) if 'name' in lct_inst.database[1].keys(): self.namedb.insert(0, lct_inst.database[1]['name']) self.userdb.delete(0, END) if 'user' in lct_inst.database[1].keys(): self.userdb.insert(0, lct_inst.database[1]['user']) self.pwddb.delete(0, END) if 'password' in lct_inst.database[1].keys(): self.pwddb.insert(0, lct_inst.database[1]['password']) self.modules.select_clear(0, self.modules.size()) for mod_idx in range(len(self.module_data)): current_mod = self.module_data[mod_idx] if current_mod in lct_inst.modules: self.modules.select_set(mod_idx) for lang in DEFAULT_LANGUAGES: if lang[0] == current_lang: self.language.current(self.language[VALUES].index(lang[1])) def execute(self, instance_name=None): from lucterios.framework.settings import DEFAULT_LANGUAGES, get_locale_lang self._define_values() self.module_data = [] self.modules.delete(0, END) for module_title, module_name in self.module_list: self.modules.insert(END, module_title) self.module_data.append(module_name) self.mode[VALUES] = self.mode_values self.language[VALUES] = self.lang_values self.typedb[VALUES] = self.dbtype_values self.applis[VALUES] = self.appli_list if instance_name is not None: self._load_current_data(instance_name) else: self.typedb.current(0) self.mode.current(2) if len(self.appli_list) > 0: self.applis.current(0) self.appli_selection(None) self.mode_selection(None) self.typedb_selection(None) for lang in DEFAULT_LANGUAGES: if lang[0] == get_locale_lang(): self.language.current(self.language[VALUES].index(lang[1])) center(self)
class StaffFrame(LabelFrame): """Contains data of staffmeeteng""" def __init__(self, window, base, **kwargs): super().__init__(window, **kwargs) self.base = base self.staff_id = None self.all_staff = [i.name for i in Staff.select()] self.data_label = Label(self, text="Data zespołu") self.data_label.grid(row=0, column=0, padx=5, pady=1, sticky='e') self.data_entry = Entry(self, width=20) self.data_entry.grid(row=0, column=1, padx=5, pady=1, sticky='w') self.table = Treeview(self, columns=("name", "speciality")) self.table.heading('#1', text='imię i nazwisko') self.table.heading('#2', text='specjalizacja') self.table.column('#1', width=200) self.table.column('#2', width=200) self.table.grid(row=1, column=0, rowspan=1, columnspan=2, padx=5, pady=5) self.table['show'] = 'headings' self.table.bind('<<TreeviewSelect>>', self.on_treeview_selected) self.another_stuff_frame = LabelFrame(self, text="Inni specjaliści") self.another_stuff_frame.grid(row=2, column=0, columnspan=2, pady=5) self.another_staff = Listbox(self.another_stuff_frame, width=48, height=12) self.another_staff.grid(row=0, column=0, rowspan=2, padx=5, pady=5) self.another_staff.bind('<<ListboxSelect>>', self.on_listbox_select) self.add_button = Button(self, text="Dodaj członka", command=self.add_member) self.add_button.grid(row=3, column=0, padx=5, pady=5) self.delete_button = Button(self, text="Usuń członka", command=self.remove_member) self.delete_button.grid(row=3, column=1, padx=5, pady=5) def get_staff_from_table(self): '''return list of member of staff_meeting from table eg. [[name, speciality],[name, speciality]]''' staff_meeting_list = [] for child in self.table.get_children(): staff_meeting_list.append(self.table.item(child)["values"]) return staff_meeting_list def insert_staff(self, base, staff): self.base = base self.staff = staff self.staff_id = staff['id'] if not self.staff_id: self.tables_tidying() return self.data_entry.delete(0, 'end') self.data_entry.insert(0, staff['date']) self.table.delete(*self.table.get_children()) self.another_staff.delete(0, 'end') for i in staff['team']: self.table.insert('', 'end', values=(i[0], i[1])) self.tables_tidying() def on_listbox_select(self, event): '''Remove selection from table after clicking listbox.''' if self.table.selection(): self.table.selection_remove(self.table.selection()[0]) def on_treeview_selected(self, event): '''Remove selection from lisbox after clicking table''' self.another_staff.select_clear(0, 'end') def tables_tidying(self): '''Remove unused staff from table.''' self.another_staff.delete(0, 'end') used_staff = [x[0] for x in self.get_staff_from_table()] for member in Staff.select(): if member.name not in used_staff: self.another_staff.insert('end', member.name) def add_member(self): '''Add member from listbox to table.''' if not self.another_staff.curselection(): pass else: self.table.insert( '', 'end', values=(self.another_staff.selection_get(), Staff.get(Staff.name == self.another_staff. selection_get()).speciality)) self.tables_tidying() def remove_member(self): '''Removes member from table to listbox.''' selected_item = self.table.selection() if selected_item: self.table.delete(selected_item) self.tables_tidying() def clear(self): self.table.delete(*self.table.get_children()) self.tables_tidying()
class Player: def __init__(self, master): self.master = master pygame.init() pygame.mixer.init() #===Empty thread list=====# self.threads = [] #=====show an icon for the player===# def get_icon(): self.winicon = PhotoImage(file="best (2).png") master.iconphoto(False, self.winicon) #=====run the get_icon on a different thread from the gui=====# def icon(): mythreads = threading.Thread(target=get_icon) self.threads.append(mythreads) mythreads.start() icon() #=======all Button symbols and variables======# PLAY = "►" PAUSE = "║║" RWD = "⏮" FWD = "⏭" STOP = "■" UNPAUSE = "||" mute = "🔇" unmute = u"\U0001F50A" vol_mute = 0.0 vol_unmute = 1 #==========music playlist listbox=========# self.scroll = Scrollbar(master) self.play_list = Listbox(master, font="Sansarif 12 bold", bd=5, bg="white", width=37, height=19, selectbackground="black") self.play_list.place(x=600, y=77) self.scroll.place(x=946, y=80, height=389, width=15) self.scroll.config(command=self.play_list.yview) self.play_list.config(yscrollcommand=self.scroll.set) files = 'best (2).png' self.img1 = Image.open(files) self.img1 = self.img1.resize((600, 470), Image.ANTIALIAS) self.img = ImageTk.PhotoImage(self.img1) self.lab = Label(master) self.lab.grid(row=0, column=0) self.lab["compound"] = LEFT self.lab["image"] = self.img #=====show the song playing==========# self.var = StringVar() self.var.set( ".............................................................................." ) self.song_title = Label(master, font="Helvetica 12 bold", bg="black", fg="white", width=60, textvariable=self.var) self.song_title.place(x=3, y=0) # =====add a music list to the listbox======" def append_listbox(): global song_list try: directory = askdirectory() os.chdir(directory) # it permits to change the current dir song_list = os.listdir() song_list.reverse() for item in song_list: # it returns the list of files song pos = 0 self.play_list.insert(pos, item) pos += 1 global size index = 0 size = len(song_list) self.play_list.selection_set(index) self.play_list.see(index) self.play_list.activate(index) self.play_list.selection_anchor(index) except: showerror("File selected error", "Please choose a file correctly") # =====run the append_listbox function on separate thread====== # def add_songs_playlist(): mythreads = threading.Thread(target=append_listbox) self.threads.append(mythreads) mythreads.start() #=====show music time=========# def get_time(): current_time = pygame.mixer.music.get_pos() / 1000 formated_time = time.strftime("%H:%M:%S", time.gmtime(current_time)) next_one = self.play_list.curselection() song = self.play_list.get(next_one) song_timer = MP3(song) song_length = int(song_timer.info.length) format_for_length = time.strftime("%H:%M:%S", time.gmtime(song_length)) self.label_time.config( text=f"{ format_for_length} / {formated_time}") self.progress["maximum"] = song_length self.progress["value"] = int(current_time) master.after(100, get_time) #=====play the music====# def Play_music(): try: track = self.play_list.get(ACTIVE) pygame.mixer.music.load(track) self.var.set(track) pygame.mixer.music.play() get_time() # iterate through all the songs in the playlist # there is a bug when closing the window except: showerror("No Music", "Please load the music you want to play") def playAll(): try: index = 0 for i in range(size): self.play_list.select_clear(0, END) self.play_list.selection_set(index, last=None) self.play_list.see(index) self.play_list.activate(index) self.play_list.selection_anchor(index) track = self.play_list.get(index) pygame.mixer.music.load(track) self.var.set(track) pygame.mixer.music.play() current_song = self.play_list.curselection() song = self.play_list.get(current_song) song_timer = MP3(song) song_length = int(song_timer.info.length) * 1000 get_time() index += 1 except: showerror("No songs in playlist", "Please add music") def play_all(): mythreads = threading.Thread(target=playAll) self.threads.append(mythreads) mythreads.start() # ===pause and unpause == # def pause_unpause(): if self.button_pause['text'] == PAUSE: pygame.mixer.music.pause() self.button_pause['text'] = UNPAUSE elif self.button_pause['text'] == UNPAUSE: pygame.mixer.music.unpause() self.button_pause['text'] = PAUSE # ==play the music on a diffent thread from the gui == # def play_thread(): mythreads = threading.Thread(target=Play_music) self.threads.append(mythreads) mythreads.start() master.bind("<space>", lambda x: play_thread()) # ===stop=== def stop(): pygame.mixer.music.stop() #====increase and decrease volume when slider is moved()==# def volume(x): pygame.mixer.music.set_volume(self.volume_slider.get()) # ====mute and unmute the song while the song plays== # def muted(): if self.button_mute['text'] == unmute: pygame.mixer.music.set_volume(vol_mute) self.volume_slider.set(vol_mute) self.button_mute['fg'] = "red" self.button_mute['text'] = mute elif self.button_mute['text'] == mute: pygame.mixer.music.set_volume(vol_unmute) self.volume_slider.set(vol_unmute) self.button_mute['fg'] = "white" self.button_mute['text'] = unmute #===move to the next song===# def nextSong(): try: next_one = self.play_list.curselection() next_one = next_one[0] + 1 song = self.play_list.get(next_one) pygame.mixer.music.load(song) pygame.mixer.music.play() self.play_list.select_clear(0, END) self.play_list.activate(next_one) self.play_list.selection_set(next_one, last=None) self.var.set(song) get_time() self.play_list.see(next_one) except: showerror("No Next Song", "Please press the previous button") def next(): mythreads = threading.Thread(target=nextSong) self.threads.append(mythreads) mythreads.start() #===move to the previous song===# def prevSong(): try: next_one = self.play_list.curselection() next_one = next_one[0] - 1 song = self.play_list.get(next_one) pygame.mixer.music.load(song) pygame.mixer.music.play() self.play_list.select_clear(0, END) self.play_list.activate(next_one) self.play_list.selection_set(next_one, last=None) self.var.set(song) get_time() self.play_list.see(next_one) except: showerror("No previous Song", "Please press the Next button") def prev(): mythreads = threading.Thread(target=prevSong) self.threads.append(mythreads) mythreads.start() self.master.bind('<Left>', lambda x: prev()) self.master.bind('<Right>', lambda x: next()) #=====exit the application=====# def exit(): MsgBox = askquestion( 'Exit Application', 'Are you sure you want to exit the music player.', icon='warning') if MsgBox == 'yes': master.quit() master.after(100, exit) else: showinfo('Return', 'Continue playing your awesome music') return #=====Help window=====# def help(): top = Toplevel() top.title("Help") top.geometry("350x554+500+80") top.resizable(width=0, height=0) user_manual = [ " MUSIC PLAYER USER MANUAL: \n", "1. play button = ( ► )", "2. pause button = ║║ ", "3. unpause symbol = ||", "4. next button = ⏭ ", "5. previous button = ⏮", "6. mute button = '\U0001F50A' ", "7. unmute symbol = 🔇", "8. stop button = ■ ", "\n\n| Made by manucho | Copyright @ 2021 |\n" ] for i in user_manual: manual = Label(top, text=i, width=50, height=3, font="Helvetica, 11", bg="black", fg="white") manual.pack(side=TOP, fill=BOTH) #==============================================================================================# # THis part contains the menu, volume slider , music playlist label and the volume slider # #===============================================================================================# self.menu = Menu( self.lab, font="helvetica, 3", ) master.config(menu=self.menu) self.menu.add_command(label="HELP", command=help) self.menu.add_command(label="EXIT", command=exit) self.separator = ttk.Separator(self.lab, orient='horizontal') self.separator.place(relx=0, rely=0.87, relwidth=1, relheight=1) self.button_play = Button(master, text=PLAY, width=5, bd=5, bg="black", fg="white", font="Helvetica, 15", command=play_thread) self.button_play.place(x=150, y=415) self.button_stop = Button(master, text=STOP, width=5, bd=5, font="Helvetica, 15", bg="black", fg="white", command=stop) self.button_stop.place(x=225, y=415) self.button_prev = Button(master, text=FWD, width=5, bd=5, font="Helvetica, 15", bg="black", fg="white", command=next) self.button_prev.place(x=300, y=415) self.buttonPlayall = Button(self.master, text='\U0001F500', bg='black', fg='white', font='Helvetica, 15', bd=5, width=3, command=play_all) self.buttonPlayall.place(x=375, y=415) self.button_next = Button(master, text=RWD, width=5, bd=5, bg="black", fg="white", font="Helvetica, 15", command=prev) self.button_next.place(x=10, y=415) self.button_pause = Button(master, text=PAUSE, width=4, bd=5, font="Helvetica, 15", bg="black", fg="white", command=pause_unpause) self.button_pause.place(x=85, y=415) self.button_mute = Button(master, text=unmute, width=2, bd=5, font="Helvetica, 15", bg="black", fg="white", command=muted) self.button_mute.place(x=430, y=415) self.label_playlist = Label(master, text=u"♫ Music Playlist ♫ ", width=31, font="Helvetica, 15") self.label_playlist.place(x=610, y=5) self.button_load_music = Button( master, text="♫ Click Here To Load The Music ♫", width=43, bd=5, font="Helvetica, 10", bg="black", fg="white", command=add_songs_playlist) self.button_load_music.place(x=605, y=45) self.style = ttk.Style() self.style.configure("myStyle.Horizontal.TScale", background="#505050") self.volume_slider = ttk.Scale(self.lab, from_=0, to=1, orient=HORIZONTAL, value=1, length=120, command=volume, style="myStyle.Horizontal.TScale") self.volume_slider.place(x=475, y=424) self.progress = ttk.Progressbar(self.lab, orient=HORIZONTAL, value=0, length=453, mode='determinate') self.progress.place(x=0, y=385) self.label_time = Label(master, text="00:00:00 / 00:00:00", width=17, font="Helvetica, 10", bg="black", fg="white") self.label_time.place(x=460, y=387)
class GetKeysDialog(Toplevel): # Dialog title for invalid key sequence keyerror_title = 'Key Sequence Error' def __init__(self, parent, title, action, current_key_sequences, *, _htest=False, _utest=False): """ parent - parent of this dialog title - string which is the title of the popup dialog action - string, the name of the virtual event these keys will be mapped to current_key_sequences - list, a list of all key sequence lists currently mapped to virtual events, for overlap checking _htest - bool, change box location when running htest _utest - bool, do not wait when running unittest """ Toplevel.__init__(self, parent) self.withdraw() # Hide while setting geometry. self.configure(borderwidth=5) self.resizable(height=False, width=False) self.title(title) self.transient(parent) self.grab_set() self.protocol("WM_DELETE_WINDOW", self.cancel) self.parent = parent self.action = action self.current_key_sequences = current_key_sequences self.result = '' self.key_string = StringVar(self) self.key_string.set('') # Set self.modifiers, self.modifier_label. self.set_modifiers_for_platform() self.modifier_vars = [] for modifier in self.modifiers: variable = StringVar(self) variable.set('') self.modifier_vars.append(variable) self.advanced = False self.create_widgets() self.update_idletasks() self.geometry( "+%d+%d" % ( parent.winfo_rootx() + (parent.winfo_width()/2 - self.winfo_reqwidth()/2), parent.winfo_rooty() + ((parent.winfo_height()/2 - self.winfo_reqheight()/2) if not _htest else 150) ) ) # Center dialog over parent (or below htest box). if not _utest: self.deiconify() # Geometry set, unhide. self.wait_window() def showerror(self, *args, **kwargs): # Make testing easier. Replace in #30751. messagebox.showerror(*args, **kwargs) def create_widgets(self): self.frame = frame = Frame(self, borderwidth=2, relief='sunken') frame.pack(side='top', expand=True, fill='both') frame_buttons = Frame(self) frame_buttons.pack(side='bottom', fill='x') self.button_ok = Button(frame_buttons, text='OK', width=8, command=self.ok) self.button_ok.grid(row=0, column=0, padx=5, pady=5) self.button_cancel = Button(frame_buttons, text='Cancel', width=8, command=self.cancel) self.button_cancel.grid(row=0, column=1, padx=5, pady=5) # Basic entry key sequence. self.frame_keyseq_basic = Frame(frame, name='keyseq_basic') self.frame_keyseq_basic.grid(row=0, column=0, sticky='nsew', padx=5, pady=5) basic_title = Label(self.frame_keyseq_basic, text=f"New keys for '{self.action}' :") basic_title.pack(anchor='w') basic_keys = Label(self.frame_keyseq_basic, justify='left', textvariable=self.key_string, relief='groove', borderwidth=2) basic_keys.pack(ipadx=5, ipady=5, fill='x') # Basic entry controls. self.frame_controls_basic = Frame(frame) self.frame_controls_basic.grid(row=1, column=0, sticky='nsew', padx=5) # Basic entry modifiers. self.modifier_checkbuttons = {} column = 0 for modifier, variable in zip(self.modifiers, self.modifier_vars): label = self.modifier_label.get(modifier, modifier) check = Checkbutton(self.frame_controls_basic, command=self.build_key_string, text=label, variable=variable, onvalue=modifier, offvalue='') check.grid(row=0, column=column, padx=2, sticky='w') self.modifier_checkbuttons[modifier] = check column += 1 # Basic entry help text. help_basic = Label(self.frame_controls_basic, justify='left', text="Select the desired modifier keys\n"+ "above, and the final key from the\n"+ "list on the right.\n\n" + "Use upper case Symbols when using\n" + "the Shift modifier. (Letters will be\n" + "converted automatically.)") help_basic.grid(row=1, column=0, columnspan=4, padx=2, sticky='w') # Basic entry key list. self.list_keys_final = Listbox(self.frame_controls_basic, width=15, height=10, selectmode='single') self.list_keys_final.insert('end', *AVAILABLE_KEYS) self.list_keys_final.bind('<ButtonRelease-1>', self.final_key_selected) self.list_keys_final.grid(row=0, column=4, rowspan=4, sticky='ns') scroll_keys_final = Scrollbar(self.frame_controls_basic, orient='vertical', command=self.list_keys_final.yview) self.list_keys_final.config(yscrollcommand=scroll_keys_final.set) scroll_keys_final.grid(row=0, column=5, rowspan=4, sticky='ns') self.button_clear = Button(self.frame_controls_basic, text='Clear Keys', command=self.clear_key_seq) self.button_clear.grid(row=2, column=0, columnspan=4) # Advanced entry key sequence. self.frame_keyseq_advanced = Frame(frame, name='keyseq_advanced') self.frame_keyseq_advanced.grid(row=0, column=0, sticky='nsew', padx=5, pady=5) advanced_title = Label(self.frame_keyseq_advanced, justify='left', text=f"Enter new binding(s) for '{self.action}' :\n" + "(These bindings will not be checked for validity!)") advanced_title.pack(anchor='w') self.advanced_keys = Entry(self.frame_keyseq_advanced, textvariable=self.key_string) self.advanced_keys.pack(fill='x') # Advanced entry help text. self.frame_help_advanced = Frame(frame) self.frame_help_advanced.grid(row=1, column=0, sticky='nsew', padx=5) help_advanced = Label(self.frame_help_advanced, justify='left', text="Key bindings are specified using Tkinter keysyms as\n"+ "in these samples: <Control-f>, <Shift-F2>, <F12>,\n" "<Control-space>, <Meta-less>, <Control-Alt-Shift-X>.\n" "Upper case is used when the Shift modifier is present!\n\n" + "'Emacs style' multi-keystroke bindings are specified as\n" + "follows: <Control-x><Control-y>, where the first key\n" + "is the 'do-nothing' keybinding.\n\n" + "Multiple separate bindings for one action should be\n"+ "separated by a space, eg., <Alt-v> <Meta-v>." ) help_advanced.grid(row=0, column=0, sticky='nsew') # Switch between basic and advanced. self.button_level = Button(frame, command=self.toggle_level, text='<< Basic Key Binding Entry') self.button_level.grid(row=2, column=0, stick='ew', padx=5, pady=5) self.toggle_level() def set_modifiers_for_platform(self): """Determine list of names of key modifiers for this platform. The names are used to build Tk bindings -- it doesn't matter if the keyboard has these keys; it matters if Tk understands them. The order is also important: key binding equality depends on it, so config-keys.def must use the same ordering. """ if sys.platform == "darwin": self.modifiers = ['Shift', 'Control', 'Option', 'Command'] else: self.modifiers = ['Control', 'Alt', 'Shift'] self.modifier_label = {'Control': 'Ctrl'} # Short name. def toggle_level(self): "Toggle between basic and advanced keys." if self.button_level.cget('text').startswith('Advanced'): self.clear_key_seq() self.button_level.config(text='<< Basic Key Binding Entry') self.frame_keyseq_advanced.lift() self.frame_help_advanced.lift() self.advanced_keys.focus_set() self.advanced = True else: self.clear_key_seq() self.button_level.config(text='Advanced Key Binding Entry >>') self.frame_keyseq_basic.lift() self.frame_controls_basic.lift() self.advanced = False def final_key_selected(self, event=None): "Handler for clicking on key in basic settings list." self.build_key_string() def build_key_string(self): "Create formatted string of modifiers plus the key." keylist = modifiers = self.get_modifiers() final_key = self.list_keys_final.get('anchor') if final_key: final_key = translate_key(final_key, modifiers) keylist.append(final_key) self.key_string.set(f"<{'-'.join(keylist)}>") def get_modifiers(self): "Return ordered list of modifiers that have been selected." mod_list = [variable.get() for variable in self.modifier_vars] return [mod for mod in mod_list if mod] def clear_key_seq(self): "Clear modifiers and keys selection." self.list_keys_final.select_clear(0, 'end') self.list_keys_final.yview('moveto', '0.0') for variable in self.modifier_vars: variable.set('') self.key_string.set('') def ok(self, event=None): keys = self.key_string.get().strip() if not keys: self.showerror(title=self.keyerror_title, parent=self, message="No key specified.") return if (self.advanced or self.keys_ok(keys)) and self.bind_ok(keys): self.result = keys self.grab_release() self.destroy() def cancel(self, event=None): self.result = '' self.grab_release() self.destroy() def keys_ok(self, keys): """Validity check on user's 'basic' keybinding selection. Doesn't check the string produced by the advanced dialog because 'modifiers' isn't set. """ final_key = self.list_keys_final.get('anchor') modifiers = self.get_modifiers() title = self.keyerror_title key_sequences = [key for keylist in self.current_key_sequences for key in keylist] if not keys.endswith('>'): self.showerror(title, parent=self, message='Missing the final Key') elif (not modifiers and final_key not in FUNCTION_KEYS + MOVE_KEYS): self.showerror(title=title, parent=self, message='No modifier key(s) specified.') elif (modifiers == ['Shift']) \ and (final_key not in FUNCTION_KEYS + MOVE_KEYS + ('Tab', 'Space')): msg = 'The shift modifier by itself may not be used with'\ ' this key symbol.' self.showerror(title=title, parent=self, message=msg) elif keys in key_sequences: msg = 'This key combination is already in use.' self.showerror(title=title, parent=self, message=msg) else: return True return False def bind_ok(self, keys): "Return True if Tcl accepts the new keys else show message." try: binding = self.bind(keys, lambda: None) except TclError as err: self.showerror( title=self.keyerror_title, parent=self, message=(f'The entered key sequence is not accepted.\n\n' f'Error: {err}')) return False else: self.unbind(keys, binding) return True
class TPolygonWindow(simpledialog.Dialog): """ Class represents a polygon vertices edit window. :param master: master window object. :type master: tkinter.Tk :param app: main app object. :type app: TApp :param polygon: edited polygon object. :type polygon: TPolygon """ def __init__(self, master, app, polygon): """ Initialise object variables and call the parent class constructor. """ self._app = app self._polygon = polygon super().__init__(master) def body(self, master): """ Initialise widgets. :param master: master window object. :type master: tkinter.Tk """ # Frame for widgets self.main_frame = Frame(self) # Listbox self.vertices_list = Listbox(self.main_frame, exportselection = False, \ width = 40) self.vertices_list.config(exportselection=0) self.vertices_list.pack(expand=True, fill=BOTH, side=LEFT) self.vertices_list.bind("<Double-Button-1>", self.vertices_list_selected_item) # Listbox's yscrollbar self.vertices_list_scrollbar = Scrollbar(self.main_frame, orient = VERTICAL, \ command = self.vertices_list.yview) self.vertices_list_scrollbar.pack(expand=True, fill=Y, side=LEFT) self.vertices_list.config( yscrollcommand=self.vertices_list_scrollbar.set) self.main_frame.pack(expand=True, fill=BOTH) # Fill list with vertices data self.update_vertices_list() def buttonbox(self): """ Redefine default Ok/Cancel buttons in the bottom of the window with Apply/Add/Delete. """ self.bbox = Frame(self) self.apply_button = Button(self.bbox, text = "Apply", width = 10, \ command = self.apply) self.apply_button.pack(side=LEFT, padx=5, pady=5) self.add_button = Button(self.bbox, text = "Add", width = 10, \ command = self.add_vertex) self.add_button.pack(side=LEFT, padx=5, pady=5) self.delete_button = Button(self.bbox, text = "Delete", width = 10, \ command = self.delete_vertex) self.delete_button.pack(side=LEFT, padx=5, pady=5) self.bbox.pack() def get_current_selection(self): """ Retrieve the selected vertex index. :rtype: integer """ try: cursel = self.vertices_list.curselection()[0] except: cursel = 0 return cursel def vertices_list_selected_item(self, event): """ Display and edit selected vertex parameters. :param event: listbox LMB click event. :type event: tkinter.Event """ try: vertex_num = (self.vertices_list.curselection())[0] except IndexError: return except Exception as message: messagebox.showerror("Error while picking shape!", message) if (vertex_num < 0): return else: try: vertex = self._polygon.points_mod[vertex_num] except Exception as message: messagebox.showerror("Materials list error", message) return initialvalue = str(vertex.x) + " " + str(vertex.y) input_str = simpledialog.askstring("Input coordinates", "Give vertex coordinates", \ initialvalue = initialvalue) try: new_x, new_y = input_str.split() except AttributeError: pass except ValueError as e: messagebox.showerror("Wrong input!", e) else: edited_point = self._polygon.points_mod[vertex_num] edited_point.x, edited_point.y = float(new_x), float(new_y) self._polygon.update_window_positions() self._app.main_canvas.delete("all") self._app.canvas_refresh() finally: self.update_vertices_list() self.vertices_list.select_clear(0, END) self.vertices_list.selection_set(vertex_num) self.vertices_list.activate(vertex_num) self.vertices_list.focus_set() def update_vertices_list(self): """ Update entries in the vertices listbox. """ cursel = self.get_current_selection() self.vertices_list.delete(0, END) for i, v in enumerate(self._polygon.points_mod): self.vertices_list.insert(i, str(i + 1) + ". (" + str(v.x) + ", " + \ str(v.y) + ")") self.vertices_list.select_clear(0, END) if (cursel >= self.vertices_list.size()): self.vertices_list.selection_set(cursel - 1) self.vertices_list.activate(cursel) else: self.vertices_list.selection_set(cursel) self.vertices_list.activate(cursel) def add_vertex(self): """ Add a vertex to the polygon. """ cursel = self.get_current_selection() input_str = simpledialog.askstring("Input coordinates", "Give vertex coordinates") try: new_x, new_y = input_str.split() except AttributeError: pass except ValueError as e: messagebox.showerror("Wrong input", e) else: self._polygon.add_vertex(x_mod=float(new_x), y_mod=float(new_y)) self._app.main_canvas.delete("all") self._app.canvas_refresh() finally: self.update_vertices_list() self.vertices_list.select_clear(0, END) self.vertices_list.selection_set(cursel) self.vertices_list.activate(cursel) self.vertices_list.focus_set() def delete_vertex(self): """ Delete a vertex from the polygon. """ cursel = self.get_current_selection() self._polygon.remove_vertex(cursel) self._app.main_canvas.delete("all") self._app.canvas_refresh() self.update_vertices_list() self.vertices_list.select_clear(0, END) self.vertices_list.selection_set(cursel) self.vertices_list.activate(cursel) self.vertices_list.focus_set() def apply(self): """ Destroy window upon clicking Apply button. """ self.destroy()
class MainApplication(tk.Frame): """Main class of application""" def __init__(self, master): super().__init__(master) self.master = master self.configure_gui() self.create_widgets() self.setup_layout() self.bind_widgets() # Init selected item var self.selected_item = 0 # Populate initial list self.populate_list() def configure_gui(self): """Setting general configurations of the application""" self.master.title("Hardware Manager") self.master.geometry("700x350") self.master.resizable(0, 0) def create_widgets(self): """Creating the widgets of the application""" # Part self.part_text = StringVar() self.part_label = Label( self.master, text="Part Name", font=("bold", 14), pady=20) self.part_entry = Entry(self.master, textvariable=self.part_text) # Customer self.customer_text = StringVar() self.customer_label = Label( self.master, text="Customer", font=("bold", 14)) self.customer_entry = Entry( self.master, textvariable=self.customer_text) # Retailer self.retailer_text = StringVar() self.retailer_label = Label( self.master, text="Retailer", font=("bold", 14)) self.retailer_entry = Entry( self.master, textvariable=self.retailer_text) # Price self.price_text = StringVar() self.price_label = Label(self.master, text="Price", font=("bold", 14)) self.price_entry = Entry(self.master, textvariable=self.price_text) # Part List (ListBox) self.parts_list = Listbox(self.master, height=8, width=100, border=0) # Create scrollbar self.scrollbar = Scrollbar(self.master) # Buttons self.add_btn = Button(self.master, text="Add Part", width=12, command=self.add_item) self.remove_btn = Button(self.master, text="Remove Part", width=12, command=self.remove_item) self.update_btn = Button(self.master, text="Update Part", width=12, command=self.update_item) self.clear_btn = Button(self.master, text="Clear Input", width=12, command=self.clear_text) def setup_layout(self): """Setup grid system""" self.part_label.grid(row=0, column=0, sticky=tk.W) self.part_entry.grid(row=0, column=1) self.customer_label.grid(row=0, column=2, sticky=tk.W) self.customer_entry.grid(row=0, column=3) self.retailer_label.grid(row=1, column=0, sticky=tk.W) self.retailer_entry.grid(row=1, column=1) self.price_label.grid(row=1, column=2, sticky=tk.W) self.price_entry.grid(row=1, column=3) self.parts_list.grid(row=3, column=0, columnspan=4, rowspan=6, pady=20, padx=20) self.scrollbar.grid(row=3, column=4, rowspan=6, sticky=tk.N+tk.S) self.add_btn.grid(row=2, column=0, pady=20) self.remove_btn.grid(row=2, column=1) self.update_btn.grid(row=2, column=2) self.clear_btn.grid(row=2, column=3) def bind_widgets(self): """Binding widgets when it needed""" # Set scroll to listbox self.scrollbar.configure(command=self.parts_list.yview) self.parts_list.configure(yscrollcommand=self.scrollbar.set) # Bind select self.parts_list.bind("<<ListboxSelect>>", self.select_item) def populate_list(self): """Delete items before update. So when you keep pressing it doesnt keep getting (pretending by calling this twice)""" self.parts_list.delete(0, tk.END) # Loop through records for row in db.fetch(): self.parts_list.insert(tk.END, row) def select_item(self, event): """Runs when some item in the Listbox is selected""" try: # Get index index = self.parts_list.curselection()[0] # Get selected item self.selected_item = self.parts_list.get(index) # Add text to entries self.part_entry.delete(0, tk.END) self.part_entry.insert(tk.END, self.selected_item[1]) self.customer_entry.delete(0, tk.END) self.customer_entry.insert(tk.END, self.selected_item[2]) self.retailer_entry.delete(0, tk.END) self.retailer_entry.insert(tk.END, self.selected_item[3]) self.price_entry.delete(0, tk.END) self.price_entry.insert(tk.END, self.selected_item[4]) except IndexError: pass def add_item(self): """Add new item""" if self.part_text.get() == "" or self.customer_text.get() == "" or self.retailer_text.get() == "" or self.price_text.get() == "": messagebox.showerror( "Required Fields", "Please include all fields") return None # Insert into DB db.insert(self.part_text.get(), self.customer_text.get(), self.retailer_text.get(), self.price_text.get()) # Clear list self.parts_list.delete(0, tk.END) # Insert into list self.parts_list.insert(tk.END, (self.part_text.get(), self.customer_text.get(), self.retailer_text.get(), self.price_text.get())) self.clear_text() self.populate_list() def remove_item(self): """Remove selected item""" db.remove(self.selected_item[0]) self.clear_text() self.populate_list() def update_item(self): """Update selected item""" db.update(self.selected_item[0], self.part_text.get(), self.customer_text.get(), self.retailer_text.get(), self.price_text.get()) self.populate_list() def clear_text(self): """Clear all text fields""" self.part_entry.delete(0, tk.END) self.customer_entry.delete(0, tk.END) self.retailer_entry.delete(0, tk.END) self.price_entry.delete(0, tk.END) self.parts_list.select_clear(0, tk.END)
class PiScreen(tkinter.Frame): def __init__(self, master: 'tkinter.Tk'): global client, status, theme # host = '192.168.1.120' host = 'localhost' if sys.platform.startswith('linux'): host = 'localhost' client.connect(host, 6600) tkinter.Frame.__init__(self, master, padx=0, pady=0) self.pack() self.place(height=240, width=320, x=0, y=0) status = client.status() self.volume = int(status["volume"]) self.screen_data = { "1": [ "QUEUE", "PLAYLISTS", "LIBRARY", "SETUP", "CLEAR PLAYLIST", "RANDOM " + status['random'], "REPEAT " + status['repeat'], "SINGLE " + status['single'], "CONSUME " + status['consume'] ], "1.1": { "ACTION": "QUEUE" }, "1.2": { "ACTION": "PLAYLISTS" }, "1.3": ["ARTISTS", "ALBUMS", "GENRES"], "1.3.1": { "ACTION": "ARTISTS" }, "1.3.2": { "ACTION": "ALBUMS" }, "1.3.3": { "ACTION": "GENRES" }, "1.4": ["UPDATE LIBRARY", "THEMES"], "1.4.1": { "ACTION": "UPDATE_LIBRARY" }, "1.4.2": { "ACTION": "THEMES" }, "1.5": { "ACTION": "CLEAR" }, "1.6": { "ACTION": "RANDOM" }, "1.7": { "ACTION": "REPEAT" }, "1.8": { "ACTION": "SINGLE" }, "1.9": { "ACTION": "CONSUME" } } self.screen_format = {"1.Q": "SONG", "1.P": "PLAYLIST"} self.current_song_var = tkinter.StringVar() self.footer_text_var = tkinter.StringVar() # Screens self.playerScreen = Canvas(self, width=320, height=240, bg=theme['PLAYER']['background'], borderwidth=0, highlightthickness=0) self.menuScreen = Frame(self, width=320, height=240, bg="white") self.menuScreen.place(height=240, width=320, x=0, y=0) # Menu Screen items self.headerFrame = Frame(self.menuScreen, width=320, height=20, bg=theme['HEADER']['background']) self.headerFrame.pack(side=tkinter.TOP, fill=X) self.currentSongLabel = Label(self.headerFrame, font=(theme['HEADER']['font'], 12, 'bold'), bg=theme['HEADER']['background'], foreground=theme['HEADER']['foreground'], textvariable=self.current_song_var, justify=tkinter.LEFT, anchor=tkinter.W) self.currentSongLabel.place(x=0, y=0, width=300, height=20, anchor=tkinter.NW) self.volumeLabel = Label(self.headerFrame, font=(theme['HEADER']['font'], 10, 'bold'), bg=theme['HEADER']['background'], foreground=theme['HEADER']['foreground'], text='') self.volumeLabel.place(x=300, y=0, anchor=tkinter.NW) self.mainFrame = Frame(self.menuScreen, width=320, height=200) self.mainFrame.pack(side=tkinter.TOP, fill=Y) self.listbox = Listbox(self.mainFrame, selectmode=tkinter.SINGLE, font=(theme['MAIN']['font'], 11), bg=theme['MAIN']['background'], fg=theme['MAIN']['foreground'], height=10, activestyle="none", borderwidth=0, highlightthickness=0, selectbackground=theme['MAIN']['selected'], selectforeground=theme['MAIN']['foreground']) self.listbox.bind("<Key>", self.handle_keys) self.listbox.configure(width=320, height=11) self.listbox.pack(side=tkinter.TOP, expand=1, ipadx=0, ipady=0, padx=0, pady=0) self.listbox.focus_set() self.footer = Label(self.menuScreen, textvariable=self.footer_text_var, font=(theme['FOOTER']['font'], 10, 'bold'), bg=theme['FOOTER']['background'], foreground=theme['FOOTER']['foreground'], justify=tkinter.LEFT, anchor=tkinter.W) self.footer.configure(width=320, height=1) self.footer.pack(side=tkinter.BOTTOM) self.focus_set() self.bind("<Key>", self.handle_keys) self.screen = "1" self.show_screen() self.tick() def tick(self): global awayCount, keyMode, footerMessage, footerMessageCount self.update_header() if keyMode != 'PLAYER': awayCount += 1 if awayCount > 120: awayCount = 0 self.screen = '' self.show_screen() else: awayCount = 0 if footerMessage == self.footer_text_var.get(): footerMessageCount += 1 if footerMessageCount > 8: footerMessageCount = 0 self.footer_text_var.set("") else: footerMessage = self.footer_text_var.get() footerMessageCount = 0 self.after(800, self.tick) def update_header(self): global status, keyMode, songChanged, currentSong, songName, songTicker, minTickerLength, songTickerCount status = client.status() self.volume = int(status["volume"]) self.volumeLabel.configure(text=status["volume"]) if status["state"] == "play": currentSong = client.currentsong() song = currentSong["artist"] + " - " + currentSong["title"] if songName != song: songChanged = True songName = song if keyMode != 'PLAYER': # song changed, refresh ui if len(songName) >= minTickerLength: songTicker = True songTickerCount = -1 else: songTicker = False songTickerCount = 0 if keyMode != 'PLAYER': if songTicker: songTickerCount += 1 if songTickerCount == len(songName) + 5: songTickerCount = 0 song = songName + " " new_song = song[songTickerCount:] + song[:songTickerCount] self.current_song_var.set(new_song) elif keyMode == 'PLAYER': self.show_player() else: if songName != '': self.current_song_var.set('') songName = '' songChanged = True if keyMode == 'PLAYER': self.show_player() def show_screen(self): global keyMode if self.screen == '': keyMode = 'PLAYER' self.menuScreen.place_forget() self.playerScreen.place(height=240, width=320, x=0, y=0) self.show_player() self.update() self.screen = '1' return self.listbox.delete(0, self.listbox.size() - 1) format_name = "string" if self.screen in self.screen_format: format_name = self.screen_format[self.screen] if isinstance(self.screen_data[self.screen], list): for item in self.screen_data[self.screen]: if format_name == "string": if not item: self.listbox.insert(tkinter.END, "") else: self.listbox.insert(tkinter.END, item[:36]) if format_name == "SONG": songname = '' if 'artist' in item: songname = item['artist'][:18] songname += " - " if 'title' in item: max = 36 - len(songname) songname += item['title'][:max] self.listbox.insert(tkinter.END, songname) if format_name == "PLAYLIST": playlist_name = '' if isinstance(item, str): playlist_name = item else: playlist_name = item['playlist'] self.listbox.insert(tkinter.END, playlist_name) self.listbox.select_set(0) # This only sets focus on the first item. self.listbox.event_generate("<<ListboxSelect>>") self.update() return def show_player(self): global image, bg, songChanged, volumeChanged if songChanged or image is None: if sys.platform.startswith('linux'): process = subprocess.Popen( "./coverart.sh", shell=True, stdout=subprocess.PIPE).stdout.read() else: process = "./icons/ic_album_white_48dp.png" image = ImageTk.PhotoImage( Image.open(process).resize((136, 136), Image.ANTIALIAS)) if bg is None: process = "./icons/bg.png" if 'img_background' in theme['PLAYER']: process = theme['PLAYER']['img_background'] bg = ImageTk.PhotoImage( Image.open(process).resize((320, 240), Image.ANTIALIAS)) if icon_random is None: self.load_icons() if status["state"] == "play": if songChanged: self.playerScreen.delete(tkinter.ALL) self.playerScreen.create_image(160, 120, image=bg) self.playerScreen.create_rectangle( 10, 10, 150, 150, fill=theme['PLAYER']['foreground']) self.playerScreen.create_image(80, 80, image=image) self.playerScreen.create_image(178, 132, image=icon_random) self.playerScreen.create_image(224, 132, image=icon_repeat) self.playerScreen.create_image(270, 132, image=icon_single) self.playerScreen.create_rectangle( 298, 146, 308, 92, fill=theme['PLAYER']['background'], outline=theme['PLAYER']['foreground'], width=1) self.playerScreen.create_line( 303, 144, 303, 144 - int(self.volume / 2), fill=theme['PLAYER']['foreground'], width=7) self.playerScreen.create_text( 10, 160, text=currentSong['artist'], anchor=tkinter.NW, fill=theme['PLAYER']['foreground'], font=(theme['PLAYER']['font'], 14, 'bold')) self.playerScreen.create_text( 10, 185, text=currentSong['title'], anchor=tkinter.NW, fill=theme['PLAYER']['foreground'], font=(theme['PLAYER']['font'], 12, 'bold')) self.playerScreen.create_text( 10, 210, text=currentSong['album'], anchor=tkinter.NW, fill=theme['PLAYER']['foreground'], font=(theme['PLAYER']['font'], 10, 'bold')) else: time = str(status['time']).split(":") played = int((float(time[0]) / float(time[1])) * 320) if played < 3: # bug self.playerScreen.create_rectangle( 0, 236, 320, 240, fill=theme['PLAYER']['background']) self.playerScreen.create_rectangle( 0, 236, played, 240, fill=theme['PLAYER']['foreground']) if volumeChanged: volumeChanged = False self.playerScreen.create_rectangle( 298, 146, 308, 92, fill=theme['PLAYER']['background'], outline=theme['PLAYER']['foreground'], width=1) self.playerScreen.create_line( 303, 144, 303, 144 - int(self.volume / 2), fill=theme['PLAYER']['foreground'], width=7) else: # Blank Screen self.playerScreen.delete(tkinter.ALL) self.playerScreen.create_image(160, 120, image=bg) self.playerScreen.create_text( 20, 20, text=theme['PLAYER']['default_message'], anchor=tkinter.NW, fill=theme['PLAYER']['foreground'], font=(theme['PLAYER']['font'], 20, 'bold')) songChanged = False return def handle_keys(self, event): global config, client, selectedAlbum, selectedArtist, selectedGenre global keyMode, textEntry, textBackAction, textSaveAction, awayCount, theme_name global albums, artists, queue, songs, playlists, status, genres, songChanged, volumeChanged awayCount = 0 keycode = str(event.keycode) # self.footer_text_var.set(str("Key Pressed : "+keycode)) if keyMode == 'PLAYER' and keycode != config["PISCREEN_KEYS"]["vol_up"] \ and keycode != config["PISCREEN_KEYS"]["vol_down"] \ and keycode != config["PISCREEN_KEYS"]["play"] \ and keycode != config["PISCREEN_KEYS"]["next"] \ and keycode != config["PISCREEN_KEYS"]["prev"] \ and keycode != config["PISCREEN_KEYS"]["power"] \ and keycode != config["PISCREEN_KEYS"]["left"]: keyMode = 'MENU' self.playerScreen.place_forget() self.menuScreen.place(height=240, width=320, x=0, y=0) self.show_screen() self.update() return if keyMode == 'TEXT': if keycode == config["PISCREEN_KEYS"]["back"]: # back keyMode = 'MENU' self.run_command(textBackAction) if keycode == config["PISCREEN_KEYS"]["ok"]: # ok keyMode = 'MENU' self.run_command(textSaveAction) if event.keysym in '0123456789-abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ': textEntry += event.keysym self.footer_text_var.set(str("Entry : " + textEntry)) return # self.footer.configure(text=str('Key Pressed ' + str(event.keycode))) if keycode == config["PISCREEN_KEYS"]["menu"]: if self.screen == "1.P": selection = int(self.listbox.curselection()[0]) + 1 if selection > 1: self.footer_text_var.set( str("Press 1 + OK to Delete Playlist")) keyMode = 'TEXT' textBackAction = "PLAYLISTS" textSaveAction = "DELETE_PLAYLIST" if self.screen == "1.Q": self.footer_text_var.set(str("Press OK to remove Song")) keyMode = 'TEXT' textBackAction = "QUEUE" textSaveAction = "DELETE_SONG" return if keycode == config["PISCREEN_KEYS"]["down"]: # down if self.listbox.size() > 0: selection = int(self.listbox.curselection()[0]) count = self.listbox.size() if selection < (count - 1): self.listbox.select_clear(selection) self.listbox.selection_set(selection + 1) self.listbox.event_generate("<<ListboxSelect>>") return if keycode == config["PISCREEN_KEYS"]["up"]: # up if self.listbox.size() > 0: selection = int(self.listbox.curselection()[0]) if selection > 0: self.listbox.select_clear(selection) self.listbox.selection_set(selection - 1) self.listbox.event_generate("<<ListboxSelect>>") return if keycode == config["PISCREEN_KEYS"]["left"] or keycode == config[ "PISCREEN_KEYS"]["back"]: # left or escape if self.screen != "1": menu = self.screen.rsplit(".", maxsplit=1) new_screen = menu[0] self.screen = new_screen self.show_screen() else: self.screen = '' songChanged = True self.show_screen() return if keycode == config["PISCREEN_KEYS"]["right"] or keycode == config[ "PISCREEN_KEYS"]["ok"]: # right or return if self.listbox.size() > 0: selection = int(self.listbox.curselection()[0]) + 1 new_screen = self.screen + "." + str(selection) if new_screen in self.screen_data: if type(self.screen_data[new_screen]) is list: self.screen = new_screen self.show_screen() else: self.run_command( self.screen_data[new_screen]["ACTION"]) else: if str(new_screen).startswith("1.Q."): menu = new_screen.rsplit(".", maxsplit=1) client.playid(int(queue[int(menu[1]) - 1]["id"])) return if str(new_screen).startswith("1.P."): menu = new_screen.rsplit(".", maxsplit=1) if menu[1] == "1": keyMode = 'TEXT' textBackAction = 'PLAYLISTS' textSaveAction = 'SAVE_PLAYLIST' textEntry = '' self.footer_text_var.set( 'Back to Cancel, Ok to Save') else: playlist = playlists[int(menu[1]) - 1]['playlist'] client.clear() client.load(playlist) client.play() return if str(new_screen).startswith("1.3.A"): if new_screen.count(".") == 3: menu = new_screen.rsplit(".", maxsplit=1) selectedArtist = artists[int(menu[1]) - 1] albums = [] albums = client.list("album", selectedArtist) albums[:0] = ["Add All"] self.footer_text_var.set("SELECTED Artist " + selectedArtist) self.screen = new_screen self.screen_data[new_screen] = albums self.show_screen() return elif new_screen.count(".") == 4: menu = new_screen.rsplit(".", maxsplit=1) if menu[1] == "1": # add all client.findadd("artist", selectedArtist) self.footer_text_var.set("Added All for " + selectedArtist) self.screen = menu[0].rsplit(".", maxsplit=1)[0] self.show_screen() else: selectedAlbum = albums[int(menu[1]) - 1] songs = client.list("title", "album", selectedAlbum, "artist", selectedArtist) songs[:0] = ["Add All"] self.screen = new_screen self.screen_data[new_screen] = songs self.show_screen() self.footer_text_var.set("Album Selected " + selectedAlbum) return elif new_screen.count(".") == 5: menu = new_screen.rsplit(".", maxsplit=1) if menu[1] == "1": # add all client.findadd("album", selectedAlbum, "artist", selectedArtist) self.footer_text_var.set("Added All for " + selectedAlbum + "/" + selectedArtist) self.screen = menu[0].rsplit(".", maxsplit=1)[0] self.show_screen() else: selected_song = songs[int(menu[1]) - 1] client.findadd("title", selected_song, "album", selectedAlbum, "artist", selectedArtist) self.footer_text_var.set("Added " + selected_song + "/" + selectedAlbum + "/" + selectedArtist) return if str(new_screen).startswith("1.3.B"): menu = new_screen.rsplit(".", maxsplit=1) if new_screen.count(".") == 3: selectedAlbum = albums[int(menu[1]) - 1] songs = client.list("title", "album", selectedAlbum) songs[:0] = ["Add All"] self.screen = new_screen self.screen_data[new_screen] = songs self.show_screen() self.footer_text_var.set("Album Selected " + selectedAlbum) if new_screen.count(".") == 4: if menu[1] == "1": # add all client.findadd("album", selectedAlbum) self.footer_text_var.set( "Added All for album " + selectedAlbum) self.screen = menu[0].rsplit(".", maxsplit=1)[0] self.show_screen() else: selected_song = songs[int(menu[1]) - 1] client.findadd("title", selected_song, "album", selectedAlbum) self.footer_text_var.set("Added " + selected_song + "/" + selectedAlbum) return if str(new_screen).startswith("1.3.C"): menu = new_screen.rsplit(".", maxsplit=1) if new_screen.count(".") == 3: selectedGenre = genres[int(menu[1]) - 1] songs = client.list("title", "genre", selectedGenre) self.screen = new_screen self.screen_data[new_screen] = songs self.show_screen() self.footer_text_var.set("Genre Selected " + selectedAlbum) if new_screen.count(".") == 4: selected_song = songs[int(menu[1]) - 1] client.findadd("title", selected_song, "genre", selectedGenre) self.footer_text_var.set("Added " + selected_song + selectedGenre) return if str(new_screen).startswith("1.4.T"): menu = new_screen.rsplit(".", maxsplit=1) theme_name = themes[int(menu[1]) - 1] self.footer_text_var.set("Applying Theme " + theme_name) self.apply_theme() return if keycode == config["PISCREEN_KEYS"]["vol_up"]: if self.volume < 100: self.volume += 1 client.setvol(self.volume) volumeChanged = True self.footer_text_var.set("Volume Up") else: self.footer_text_var.set("Volume Max!!") return if keycode == config["PISCREEN_KEYS"]["vol_down"]: if self.volume > 0: self.volume -= 1 client.setvol(self.volume) volumeChanged = True self.footer_text_var.set("Volume Down") else: self.footer_text_var.set("Volume Zero!!") return if keycode == config["PISCREEN_KEYS"]["play"]: if status["state"] == "play": client.pause() self.footer_text_var.set("Paused") else: client.play() self.footer_text_var.set("Playing") return if keycode == config["PISCREEN_KEYS"]["next"]: client.next() self.footer_text_var.set("Next Song") return if keycode == config["PISCREEN_KEYS"]["prev"]: client.previous() self.footer_text_var.set("Previous Song") return if keycode == config["PISCREEN_KEYS"]["home"]: self.screen = '' self.show_screen() return if keycode == config["PISCREEN_KEYS"]["power"]: if sys.platform.startswith('linux'): call("sudo nohup shutdown -h now", shell=True) else: self.footer_text_var.set("Can't PowerOff from remote") return self.footer_text_var.set("UNKNOWN " + keycode) def run_command(self, action): global client, keyMode, textEntry, status global albums, artists, queue, songs, playlists, genres, themes if action == "QUEUE": local_queue = client.playlistinfo() queue.clear() for item in local_queue: queue.append(item) self.screen = "1.Q" self.screen_data["1.Q"] = queue self.footer_text_var.set("Right to play Song, Menu to delete") self.show_screen() elif action == "PLAYLISTS": playlists = client.listplaylists() playlists[:0] = ["SAVE PLAYLIST"] self.screen = "1.P" self.screen_data["1.P"] = playlists self.footer_text_var.set("Right to play Playlist, Menu to delete") self.show_screen() elif action == "ARTISTS": artists = client.list("artist") self.screen = "1.3.A" self.screen_data["1.3.A"] = artists self.show_screen() elif action == "ALBUMS": albums = client.list("album") self.screen = "1.3.B" self.screen_data["1.3.B"] = albums self.show_screen() elif action == "GENRES": genres = client.list("genre") self.screen = "1.3.C" self.screen_data["1.3.C"] = genres self.show_screen() elif action == "UPDATE_LIBRARY": self.footer_text_var.set("Updating library") client.update() elif action == "THEMES": self.footer_text_var.set("Select Theme") themes = ["default", "foofighters", "light"] self.screen = "1.4.T" self.screen_data["1.4.T"] = themes self.show_screen() elif action == "SAVE_PLAYLIST": keyMode = 'MENU' found = False if textEntry == '': self.footer_text_var.set("Name Empty!!") return for playlist in playlists: if isinstance( playlist, str) is False and textEntry == playlist['playlist']: found = True if found: client.rm(textEntry) client.save(textEntry) else: client.save(textEntry) self.footer_text_var.set("Saved Playlist " + textEntry) textEntry = '' self.run_command("PLAYLISTS") elif action == "DELETE_PLAYLIST": keyMode = 'MENU' if textEntry == '1': selection = int(self.listbox.curselection()[0]) client.rm(playlists[selection]['playlist']) textEntry = '' self.run_command("PLAYLISTS") elif action == "DELETE_SONG": keyMode = 'MENU' client.delete(int(self.listbox.curselection()[0])) textEntry = '' self.run_command("QUEUE") elif action == "CLEAR": self.footer_text_var.set("Clearing Queue") client.clear() elif action == "RANDOM": if status['random'] == '0': client.random('1') else: client.random('0') status = client.status() self.screen_data['1'][5] = "RANDOM " + status['random'] self.update_random() self.show_screen() elif action == "REPEAT": if status['repeat'] == '0': client.repeat('1') else: client.repeat('0') status = client.status() self.screen_data['1'][6] = "REPEAT " + status['repeat'] self.update_repeat() self.show_screen() elif action == "SINGLE": if status['single'] == '0': client.single('1') else: client.single('0') status = client.status() self.screen_data['1'][7] = "SINGLE " + status['single'] self.update_single() self.show_screen() elif action == "CONSUME": if status['consume'] == '0': client.consume('1') else: client.consume('0') status = client.status() self.screen_data['1'][8] = "CONSUME " + status['consume'] self.show_screen() self.update() return def load_icons(self): self.update_random() self.update_repeat() self.update_single() def update_random(self): global status, theme, icon_random fgcolor = ImageColor.getrgb(theme['PLAYER']['foreground']) bgcolor = ImageColor.getrgb(theme['PLAYER']['background']) fgcolor += (255, ) bgcolor += (255, ) icon_random = Image.open('./icons/ic_shuffle_white_36dp.png') if icon_random.mode != 'RGBA': icon_random = icon_random.convert('RGBA') data = list(icon_random.getdata()) newData = list() for pixel in data: if pixel[3] != 0: if status['random'] == '1': newData.append(fgcolor) else: newData.append(bgcolor) else: newData.append(pixel) icon_random.putdata(newData) icon_random = ImageTk.PhotoImage( icon_random.resize((36, 36), Image.ANTIALIAS)) def update_single(self): global status, theme, icon_single fgcolor = ImageColor.getrgb(theme['PLAYER']['foreground']) bgcolor = ImageColor.getrgb(theme['PLAYER']['background']) fgcolor += (255, ) bgcolor += (255, ) icon_single = Image.open('./icons/ic_repeat_one_white_36dp.png') if icon_single.mode != 'RGBA': icon_single = icon_single.convert('RGBA') data = list(icon_single.getdata()) newData = list() for pixel in data: if pixel[3] != 0: if status['single'] == '1': newData.append(fgcolor) else: newData.append(bgcolor) else: newData.append(pixel) icon_single.putdata(newData) icon_single = ImageTk.PhotoImage( icon_single.resize((36, 36), Image.ANTIALIAS)) def update_repeat(self): global status, theme, icon_repeat fgcolor = ImageColor.getrgb(theme['PLAYER']['foreground']) bgcolor = ImageColor.getrgb(theme['PLAYER']['background']) fgcolor += (255, ) bgcolor += (255, ) icon_repeat = Image.open('./icons/ic_repeat_white_36dp.png') if icon_repeat.mode != 'RGBA': icon_repeat = icon_repeat.convert('RGBA') data = list(icon_repeat.getdata()) newData = list() for pixel in data: if pixel[3] != 0: if status['repeat'] == '1': newData.append(fgcolor) else: newData.append(bgcolor) else: newData.append(pixel) icon_repeat.putdata(newData) icon_repeat = ImageTk.PhotoImage( icon_repeat.resize((36, 36), Image.ANTIALIAS)) def apply_theme(self): global theme_name, theme, config, bg my_file = Path('./theme/' + theme_name + '/theme.ini') if my_file.is_file(): theme = configparser.ConfigParser() theme.read('./theme/' + theme_name + '/theme.ini') # player related settings bg = None self.playerScreen.configure(bg=theme['PLAYER']['background']) self.load_icons() # menu related settings self.headerFrame.configure(bg=theme['HEADER']['background']) self.currentSongLabel.configure( font=(theme['HEADER']['font'], 12, 'bold'), bg=theme['HEADER']['background'], foreground=theme['HEADER']['foreground']) self.volumeLabel.configure( font=(theme['HEADER']['font'], 10, 'bold'), bg=theme['HEADER']['background'], foreground=theme['HEADER']['foreground']) self.listbox.configure( font=(theme['MAIN']['font'], 11), bg=theme['MAIN']['background'], fg=theme['MAIN']['foreground'], selectbackground=theme['MAIN']['selected'], selectforeground=theme['MAIN']['foreground']) self.footer.configure(font=(theme['FOOTER']['font'], 10, 'bold'), bg=theme['FOOTER']['background'], foreground=theme['FOOTER']['foreground']) # write theme to config.ini config["THEME"]["theme"] = theme_name with open('config.ini', 'w') as configfile: config.write(configfile) else: self.footer_text_var.set("Theme Not Found") theme_name = config["THEME"]["theme"]
class MessageMakerListFrame: def __init__(self, messageMakerPartFrame): self.frame = Frame(messageMakerPartFrame.frame) self.scrollbar = Scrollbar(self.frame, orient=VERTICAL) self.listBox = Listbox(self.frame, activestyle="none", width=40, height=12, yscrollcommand=self.scrollbar.set) self.scrollbar.config(command=self.listBox.yview) self.scrollbar.grid(row=0, column=1, sticky=NS) self.populateListbox(messageMakerPartFrame.parent.message.parts) self.window = messageMakerPartFrame.parent self.messageMakerPartFrame = messageMakerPartFrame self.listBox.grid(row=0, column=0) def moveSelectedUp(self): current = self.listBox.curselection() if current and current[0] != 0: index = current[0] text = self.listBox.get(index) self.listBox.delete(index) self.listBox.insert(index - 1, text) self.listBox.selection_set(index - 1) self.listBox.see(index - 2) self.window.message.parts[index], self.window.message.parts[ index - 1] = self.window.message.parts[ index - 1], self.window.message.parts[index] def moveSelectedDown(self): current = self.listBox.curselection() if current and current[0] != self.listBox.size() - 1: index = current[0] text = self.listBox.get(index) self.listBox.delete(index) self.listBox.insert(index + 1, text) self.listBox.selection_set(index + 1) self.listBox.see(index + 2) self.window.message.parts[index], self.window.message.parts[ index + 1] = self.window.message.parts[ index + 1], self.window.message.parts[index] def deleteSelected(self): current = self.listBox.curselection() if current: index = current[0] self.listBox.delete(index) self.listBox.selection_set(index) self.listBox.see(index) del self.window.message.parts[index] for part in self.window.message.parts: part.sortOrder = self.window.message.parts.index(part) + 1 def copySelected(self): current = self.listBox.curselection() if current: index = current[0] copiedPart = deepcopy(self.window.message.parts[index]) copiedPart.sortOrder = len(self.window.message.parts) self.window.message.parts.append(copiedPart) self.listBox.select_clear(0, END) self.listBox.insert(END, copiedPart.partType + ": " + copiedPart.value) self.listBox.selection_set(END) self.listBox.see(END) def populateListbox(self, parts): self.listBox.delete(0, END) index = 1 for part in parts: self.listBox.insert(index, part.partType + ": " + part.value) index += 1 def getMessageComponentWindow(self, isEditButton): if isEditButton: current = self.listBox.curselection() if current: index = current[0] MessageComponentWindow(self, self.window.message.parts[index], index) else: return else: MessageComponentWindow(self, None, len(self.window.message.parts) + 1)