class DateWidget(Frame): """Gets a date from the user.""" def __init__(self, master): """Make boxes, register callbacks etc.""" Frame.__init__(self, master) self.label = Label(self, text="När är du född?") self.label.pack() self.entry_text = StringVar() self.entry_text.trace("w", lambda *args: self.onEntryChanged()) self.entry = Entry(self, width=date_entry_width, textvariable=self.entry_text) self.entry.insert(0, "ÅÅÅÅ-MM-DD") self.entry.pack(pady=small_pad) self.button = Button(self, text="Uppdatera", command=lambda: self.onDateChanged()) self.button.pack() self.entry.focus_set() self.entry.select_range(0, END) self.entry.bind("<Return>", lambda x: self.onDateChanged()) def setListener(self, pred_view): """Select whom to notify when a new date is entered.""" self.pred_view = pred_view def onDateChanged(self): """Notifies the PredictionWidget that the date has been changed.""" try: date = datetime.datetime.strptime(self.entry.get(), "%Y-%m-%d").date() self.pred_view.update(date) except ValueError: self.entry.configure(foreground="red") def onEntryChanged(self): """Reset the text color.""" self.entry.configure(foreground="")
def add_task(self): def ajoute(event=None): task = nom.get() if task and not CONFIG.has_option("Tasks", task): index = len(CONFIG.options("Tasks")) self.menu_tasks.insert_radiobutton(index, label=task, value=task, variable=self.task) CONFIG.set("Tasks", task, CMAP[index % len(CMAP)]) top.destroy() with open(PATH_CONFIG, "w") as file: CONFIG.write(file) self.menu_tasks.invoke(index) else: nom.delete(0, "end") top = Toplevel(self) top.title(_("New task")) top.transient(self) top.grab_set() nom = Entry(top, width=20) nom.grid(row=0, columnspan=2, sticky="ew") nom.focus_set() nom.bind('<Key-Return>', ajoute) Button(top, text=_("Cancel"), command=top.destroy).grid(row=1, column=0) Button(top, text=_("Ok"), command=ajoute).grid(row=1, column=1) top.wait_window(top)
def ask_password(self): """Ask the master password in order to decrypt the mailbox config files.""" def ok(event=None): with open(os.path.join(LOCAL_PATH, '.pwd')) as fich: cryptedpwd = fich.read() pwd = getpwd.get() if crypt.crypt(pwd, cryptedpwd) == cryptedpwd: # passwords match top.destroy() logging.info('Authentication successful') self.pwd = pwd else: showerror(_('Error'), _('Incorrect password!')) logging.warning('Authentication failed') getpwd.delete(0, "end") top = Toplevel(self, class_="CheckMails") top.title(_("Password")) top.resizable(False, False) Label(top, text=_("Enter password")).pack(padx=10, pady=(10, 4)) getpwd = Entry(top, show='*', justify='center') getpwd.pack(padx=10, pady=4) Button(top, text="Ok", command=ok).pack(padx=10, pady=(4, 10)) getpwd.bind("<Key-Return>", ok) getpwd.focus_set() self.wait_window(top)
def set_password(self): """Set the master password used to encrypt the mailbox config files.""" def ok(event=None): pwd = getpwd.get() pwd2 = confpwd.get() if pwd == pwd2: # passwords match cryptedpwd = crypt.crypt(pwd, crypt.mksalt(crypt.METHOD_SHA512)) with open(os.path.join(LOCAL_PATH, '.pwd'), "w") as fich: fich.write(cryptedpwd) top.destroy() self.pwd = pwd logging.info('New password set') else: showerror(_('Error'), _('Passwords do not match!')) top = Toplevel(self, class_="CheckMails") top.iconphoto(True, self.im_icon) top.title(_("Set password")) top.resizable(False, False) Label(top, text=_("Enter master password")).pack(padx=10, pady=(4, 10)) getpwd = Entry(top, show='*', justify='center') getpwd.pack(padx=10, pady=4) Label(top, text=_("Confirm master password")).pack(padx=10, pady=4) confpwd = Entry(top, show='*', justify='center') confpwd.pack(padx=10, pady=4) Button(top, text="Ok", command=ok).pack(padx=10, pady=(4, 10)) confpwd.bind("<Key-Return>", ok) getpwd.focus_set() self.wait_window(top)
class Add(Toplevel): def __init__(self, master): Toplevel.__init__(self, master, class_=APP_NAME, padx=6, pady=6) self.title(_("Add Feed")) self.grab_set() self.resizable(True, False) self.columnconfigure(1, weight=1) Label(self, text=_('URL')).grid(row=0, column=0, sticky='e', pady=4, padx=4) self.url = "" self.url_entry = Entry(self, width=30) self.url_entry.grid(row=0, column=1, sticky='ew', pady=4, padx=4) self.url_entry.bind('<Return>', self.validate) frame = Frame(self) frame.grid(row=1, column=0, columnspan=2) Button(frame, text=_('Ok'), command=self.validate).grid(row=0, column=0, sticky='e', pady=4, padx=4) Button(frame, text=_('Cancel'), command=self.destroy).grid(row=0, column=1, sticky='w', pady=4, padx=4) self.url_entry.focus_set() def validate(self, event=None): self.url = self.url_entry.get().strip() self.destroy()
def load_login_page(): label_username = Label(frame_login, text="Username:"******"*", font=font) label_error = Label(frame_login, text="", font=font, foreground="red") label_password = Label(frame_login, text="Password:"******"Login", width=10, command=lambda: check_credentials(input_username.get(), input_password, label_error)) button_login.bind( '<Return>', lambda _: check_credentials(input_username.get(), input_password, label_error)) label_username.grid(column=1, row=1, pady=(0, 10)) input_username.grid(column=2, row=1, pady=(0, 10), sticky=W) label_password.grid(column=1, row=2) input_password.grid(column=2, row=2, sticky=W) input_password.bind( '<Return>', lambda _: check_credentials(input_username.get(), input_password, label_error)) label_error.grid(column=2, row=3, sticky=W) button_login.grid(column=2, row=4, pady=10, sticky=W) frame_login.grid()
def add_link(self): def ok(eveny=None): lien = link.get() txt = text.get() if lien: if not txt: txt = lien self.nb_links += 1 if self.txt.tag_ranges("sel"): index = self.txt.index("sel.first") self.txt.delete('sel.first', 'sel.last') else: index = "current" tags = self.txt.tag_names(index) + ("link", "link#%i" % self.nb_links) self.txt.insert("current", txt, tags) if not lien[:4] == "http": lien = "http://" + lien self.links[self.nb_links] = lien self.txt.tag_bind("link#%i" % self.nb_links, "<Button-1>", lambda e: open_url(lien)) top.destroy() top = Toplevel(self) top.transient(self) top.update_idletasks() top.geometry("+%i+%i" % top.winfo_pointerxy()) top.grab_set() top.resizable(True, False) top.title(_("Link")) top.columnconfigure(1, weight=1) text = Entry(top) link = Entry(top) if self.txt.tag_ranges('sel'): txt = self.txt.get('sel.first', 'sel.last') else: txt = '' text.insert(0, txt) text.icursor("end") Label(top, text=_("Text")).grid(row=0, column=0, sticky="e", padx=4, pady=4) Label(top, text=_("Link")).grid(row=1, column=0, sticky="e", padx=4, pady=4) text.grid(row=0, column=1, sticky="ew", padx=4, pady=4) link.grid(row=1, column=1, sticky="ew", padx=4, pady=4) Button(top, text="Ok", command=ok).grid(row=2, columnspan=2, padx=4, pady=4) text.focus_set() text.bind("<Return>", ok) link.bind("<Return>", ok)
def __init__(self, parent, structure, command_stack, on_get_focus): tk.Frame.__init__(self, parent) self.command_stack = command_stack self._structure = structure self._fill_var = tk.IntVar() self._fill_var.set(self._structure.fill) (Checkbutton(self, text="Fill", variable=self._fill_var).grid( row=EditZone._FILL_CHECK_ROW, column=0, columnspan=2)) self._fill_var.trace_add("write", self._set_fill) self._point_index = -1 self._point_index_var = tk.StringVar() top_label = Label(self, textvariable=self._point_index_var) top_label.grid(row=EditZone._POINT_INDEX_ROW, column=0, columnspan=2) top_label.bind("<Button-1>", on_get_focus) x_label = Label(self, text="\u21d5:") x_label.grid(row=EditZone._X_ROW, column=0, sticky=tk.E) x_label.bind("<Button-1>", on_get_focus) y_label = Label(self, text="\u21d4:") y_label.grid(row=EditZone._Y_ROW, column=0, sticky=tk.E) y_label.bind("<Button-1>", on_get_focus) #the updating_ booleans allow to detect if the stringvars are edited #because the point is selected #or if the user changed their value self.inhibit_callbacks = True self.editable_x = tk.StringVar() self.editable_y = tk.StringVar() setx = Entry(self, textvariable=self.editable_x, width=6) setx.grid(row=EditZone._X_ROW, column=1, sticky=tk.W) setx.bind("<FocusIn>", on_get_focus) sety = Entry(self, textvariable=self.editable_y, width=6) sety.grid(row=EditZone._Y_ROW, column=1, sticky=tk.W) sety.bind("<FocusIn>", on_get_focus) self.editable_x.trace_add("write", self._point_edited) self.editable_y.trace_add("write", self._point_edited) (Button(self, text="Add Vertex", command=self._add_point).grid(row=EditZone._ADD_ROW, column=0, columnspan=2, sticky=tk.E + tk.W)) (Button(self, text="Delete", command=self._delete_point).grid(row=EditZone._DEL_ROW, column=0, columnspan=2, sticky=tk.E + tk.W)) (Button(self, text="Symmetry", command=self._apply_symmetry).grid(row=EditZone._SYMM_ROW, column=0, columnspan=2, sticky=tk.E + tk.W))
def add_cat(self): """Add a category.""" top = Toplevel(self, class_='MyNotes') top.transient(self) top.grab_set() top.resizable(False, False) top.title(_("New Category")) def valide(event=None): cats = [l.cget('text').lower() for l in self.cat_labels.values()] cat = name.get().strip().lower() if cat and cat not in cats: c, i = self.frame_cat.grid_size() self.cat_labels[cat] = Label(self.frame_cat, text="%s" % cat.capitalize()) self.cat_labels[cat].grid(row=i, column=0, sticky="e") self.cat_colors[cat] = StringVar(self, _("Yellow")) self.cat_menus[cat] = OptionMenu( self.frame_cat, self.cat_colors[cat], _("Yellow"), *self.colors, command=lambda color, c=cat: self.change_menubutton_color( color, c), style="%s.TMenubutton" % cat) self.style.configure("%s.TMenubutton" % cat, background=COLORS[_("Yellow")]) optionmenu_patch(self.cat_menus[cat], self.cat_colors[cat]) self.cat_menus[cat].grid(row=i, column=1, padx=4, pady=4) self.cat_buttons[cat] = Button( self.frame_cat, image=self.im_delete, padding=0, command=lambda c=cat: self.del_cat(c)) self.cat_buttons[cat].grid(row=i, column=2, padx=4, pady=4, sticky='ns') self.cat_buttons[self.categories[0]].configure(state="normal") self.categories.append(cat) self.categories.sort() self.update_def_cat_menu() top.destroy() name = Entry(top, justify="center") name.grid(row=0, column=0, columnspan=2, sticky="ew") name.bind("<Return>", valide) name.bind("<Escape>", lambda e: top.destroy()) name.focus_set() Button(top, text="Ok", command=valide).grid(row=1, column=0, sticky="nswe") Button(top, text=_("Cancel"), command=top.destroy).grid(row=1, column=1, sticky="nswe")
class Attribute(TwoCells): def __init__(self, parent, text, value, callback=None, **kwargs): super().__init__(parent, **kwargs) self.callback = callback self.label_text = StringVar() self.label_text.set(text) self.label = Label(self.frame, textvariable=self.label_text) self.label.grid(column=0, row=0, padx=5, pady=5, sticky=W) self.current_value = StringVar(self.frame) self.current_value.set(value) self.value = Entry(self.frame, textvariable=self.current_value, validate="key", validatecommand=self.validate_command) self.value.grid(column=1, row=0, padx=5, pady=5, sticky=E) if self.callback: self.value.bind("<KeyRelease>", self._on_entry_changed) def _on_entry_changed(self, event): self.callback() def hide(self): self.label.grid_remove() self.value.grid_remove() return self def show(self, text): self.label_text.set(text) self.label.grid() self.value.grid() return self def disable(self): self.value.configure(state=DISABLED) return self def enable(self): self.value.configure(state=NORMAL) return self def set(self, value): self.current_value.set(value) if str(value) == "": self.disable() else: self.enable() def get(self): value = self.current_value.get() if self.validation_type in [ TwoCells.INTEGERS, TwoCells.NON_NEGATIVE_INTEGERS ]: return int(value) if value not in ["", "-"] else 0 else: return value
def change_password(self): """ Change the master password: decrypt all the mailbox config files using the old password and encrypt them with the new. """ def ok(event=None): with open(os.path.join(LOCAL_PATH, '.pwd')) as fich: cryptedpwd = fich.read() old = oldpwd.get() pwd = newpwd.get() pwd2 = confpwd.get() if crypt.crypt(old, cryptedpwd) == cryptedpwd: # passwords match if pwd == pwd2: # new passwords match cryptedpwd = crypt.crypt(pwd, crypt.mksalt(crypt.METHOD_SHA512)) with open(os.path.join(LOCAL_PATH, '.pwd'), "w") as fich: fich.write(cryptedpwd) mailboxes = CONFIG.get( "Mailboxes", "active").split(", ") + CONFIG.get( "Mailboxes", "inactive").split(", ") while "" in mailboxes: mailboxes.remove("") for mailbox in mailboxes: server, login, password, folder = decrypt(mailbox, old) if server is not None: encrypt(mailbox, pwd, server, login, password, folder) self.pwd = pwd top.destroy() logging.info('Password changed') return pwd else: showerror(_('Error'), _('Passwords do not match!')) else: showerror(_('Error'), _('Incorrect password!')) top = Toplevel(self, class_="CheckMails") top.iconphoto(True, self.im_icon) top.resizable(False, False) Label(top, text=_("Old password")).pack(padx=10, pady=(10, 4)) oldpwd = Entry(top, show='*', justify='center') oldpwd.pack(padx=10, pady=4) Label(top, text=_("New password")).pack(padx=10, pady=4) newpwd = Entry(top, show='*', justify='center') newpwd.pack(padx=10, pady=4) Label(top, text=_("Confirm password")).pack(padx=10, pady=4) confpwd = Entry(top, show='*', justify='center') confpwd.pack(padx=10, pady=4) Button(top, text="Ok", command=ok).pack(padx=10, pady=(4, 10)) confpwd.bind("<Key-Return>", ok) oldpwd.focus_set() self.wait_window(top)
class StudentIDDlg(Toplevel): def __init__(self, initialText, title, labeltext = '' ): Toplevel.__init__(self) self.initUI(initialText,title,labeltext) def initUI(self,initialText,title,labeltext=''): self.STID = initialText self.geometry("200x120") if len(title) > 0: self.title(title) self.style = Style() self.style.theme_use("default") # default style = Style() style.configure("Exit.TButton", foreground="red", background="white") style.configure("MainButton.TButton", foreground="yellow", background="red") if len(labeltext) == 0: labeltext = 'Please enter your ID..' self.bind("<Return>", self.ok) xpos = 40 ypos = 30 xpos2 = xpos+100 l1 = Label(self, text=initialText, foreground = "#ff0000", background = "light blue", font = "Arial 9") # Arial 12 bold italic l1.place(x=xpos, y=ypos) self.txtID = Entry(self) self.txtID.place(x=xpos2, y = ypos, width=70) self.txtID.bind("<Return>", self.ok) self.txtID.bind("<Escape>", self.cancel) self.txtID.focus_set() ypos += 30 okButton = Button(self, text="OK", background = "light blue", command=self.ok) #okButton.configure(style="ExitButton.TButton") # does not work okButton.place(x=xpos2, y=ypos) def getID(self): return self.STID def ok(self, event=None): self.STID = self.txtID.get() self.destroy() def cancel(self, event=None): self.destroy()
def add(self): def ok(event=None): txt = e.get() txt = txt.strip().replace(" ", "\ ") if txt and txt not in self.exclude_list: self.exclude_list.append(txt) self.listvar.set(" ".join(self.exclude_list)) top.destroy() top = Toplevel(self) top.transient(self) top.grab_set() e = Entry(top) e.pack(expand=True, fill="x", padx=10, pady=(10, 4)) e.focus_set() e.bind("<Key-Return>", ok) Button(top, text="Ok", command=ok).pack(padx=10, pady=(4, 10))
class SelectKernel(Toplevel): """About Toplevel.""" def __init__(self, master): """Create the Toplevel to select an existing Jupyter kernel.""" Toplevel.__init__(self, master, class_=master.winfo_class(), padx=10, pady=10) self.resizable(True, False) self.title("Select existing kernel") self.columnconfigure(0, minsize=22) self.columnconfigure(1, weight=1) self.columnconfigure(2, weight=1) self.selected_kernel = '' Label(self, text="Select the .json connection file or enter the existing kernel's id:").grid(columnspan=4, sticky='w', pady=4) self.entry = Entry(self, width=10) self.entry.grid(row=1, columnspan=3, sticky='ew', pady=4) self.entry.bind('<Return>', lambda e: self.validate()) Button(self, text='...', width=2, padding=0, command=self.select_file).grid(row=1, column=3, sticky='sn', pady=4) Button(self, text='Ok', command=self.validate).grid(row=2, column=1, padx=4, pady=4, sticky='e') Button(self, text='Cancel', command=self.destroy).grid(row=2, column=2, padx=4, pady=4, sticky='w') self.transient(master) self.entry.focus_set() self.update_idletasks() self.grab_set() def validate(self): self.selected_kernel = self.entry.get() self.destroy() def select_file(self): filename = askopenfilename(self, "Select connection file", initialdir=jupyter_runtime_dir(), defaultextension='.json', filetypes=[('JSON', '*.json'), ('All files', '*')]) if filename: self.entry.delete(0, 'end') self.entry.insert(0, filename)
def make_entry(self): """construct of Entry Parameters ---------- None Returns ------- None """ vcmd = self.lf0.register(self.is_okay) ent0 = Entry(self.lf0, validatecommand=(vcmd, '%P', '%S', '%i'), validate='key', textvariable=self.out_var) ent0.bind("<Return>", self.end_input) ent0.grid(row=1, column=0, padx=10) ent0.focus()
def add_task(self): def ajoute(event=None): task = nom.get().lower().strip() if task in self.tasks: showerror( _("Error"), _("The task {task} already exists.").format(task=task), parent=self) elif task: coul = CMAP[(len(self.tasks) + 1) % len(CMAP)] i = self.task_frame.grid_size()[1] + 1 self.tasks[task] = ColorFrame(self.task_frame, coul, task.capitalize()) self.tasks[task].grid(row=i, column=0, sticky='e', padx=4, pady=4) b = Button(self.task_frame, image=self.im_moins, padding=2, command=lambda t=task: self.del_task(t)) b.grid(row=i, column=1, sticky='w', padx=4, pady=4) self._tasks_btns[task] = b self._tasks_btns[CONFIG.options("PomodoroTasks")[0]].state( ['!disabled']) top.destroy() top = Toplevel(self) top.title(_("New task")) top.transient(self) top.grab_set() nom = Entry(top, width=20, justify='center') nom.grid(row=0, columnspan=2, sticky="ew") nom.focus_set() nom.bind('<Key-Return>', ajoute) Button(top, text=_("Cancel"), command=top.destroy).grid(row=1, column=0) Button(top, text=_("Ok"), command=ajoute).grid(row=1, column=1) top.wait_window(top)
def change_name(self, event): """Change category name.""" def ok(event): cats = [l.cget('text').lower() for l in self.cat_labels.values()] cat = name.get().strip().lower() if cat and cat not in cats: label.configure(text=cat.capitalize()) if old_cat == self.default_category.get(): self.default_category.set(cat.capitalize()) self.update_def_cat_menu() name.destroy() label = event.widget old_cat = label.cget('text') name = Entry(self, justify='center') name.insert(0, label.cget('text')) name.place(in_=label, relx=0, rely=0, anchor='nw', relwidth=1, relheight=1) name.bind('<FocusOut>', lambda e: name.destroy()) name.bind('<Escape>', lambda e: name.destroy()) name.bind('<Return>', ok) name.selection_range(0, 'end') name.focus_set()
def _create_validation_triangle( widget: ttk.Entry, option_name: str, tybe: Type[_StrOrInt], callback: Callable[[_StrOrInt], bool], ) -> ttk.Label: # TODO(typeshed): master attribute triangle: ttk.Label = ttk.Label( widget.master) # type: ignore[attr-defined] var = tkinter.StringVar() def var_changed(*junk: object) -> None: value_string = var.get() value: Optional[_StrOrInt] try: value = tybe(value_string) except ValueError: # e.g. int('foo') value = None else: if not callback(value): value = None if value is None: triangle.config(image=images.get('triangle')) else: triangle.config(image=_get_blank_triangle_sized_image()) set(option_name, value, from_config=True) def setting_changed(junk: object = None) -> None: var.set(str(_value_to_save(get(option_name, object)))) widget.bind(f'<<SettingChanged:{option_name}>>', setting_changed, add=True) var.trace_add('write', var_changed) setting_changed() widget.config(textvariable=var) return triangle
def initui(self): self.nombre = Nombre(0,10) self.master.title("convertisseur") self.pack(fill=BOTH, expand=1) frame1 = Frame(self, relief = RAISED, borderwidth = 1) frame1.pack(fill = BOTH) label1 = Label(frame1, text = "Valeur") label1.pack(side = LEFT) self.valeur = StringVar() self.ecriture = StringVar() disp_valeur = Entry(frame1, textvar = self.valeur ) disp_valeur.delete(0, END) self.valeur.set(str(self.nombre.valeur)) # disp_valeur.insert(0, self.nombre.valeur) disp_valeur.pack(side = RIGHT, expand = True) disp_valeur.bind("<Return>", self.update_valeur) frame2 = Frame(self, relief = RAISED, borderwidth = 1) frame2.pack(fill = BOTH) label2 = Label(frame2, text = "Base") self.base = StringVar() label2.pack(side = LEFT) disp_base = Entry(frame2, textvar = self.base) disp_base.delete(0, END) self.base.set(self.nombre.base) # disp_base.insert(0, self.nombre.base) disp_base.pack(side = RIGHT, expand=True) disp_base.bind("<Return>", self.update_base) frame3 = Frame(self, relief=RAISED, borderwidth=1) frame3.pack(fill=BOTH) self.ecriture = StringVar() label3 = Label(frame3, text="Ecriture") label3.pack(side=LEFT) disp_ecriture = Entry(frame3, textvar = self.ecriture) disp_ecriture.delete(0, END) self.ecriture.set(self.nombre.represente()) # disp_base.insert(0, self.nombre.represente()) disp_ecriture.pack(side=RIGHT, expand=True) disp_ecriture.bind("<Return>", self.update_ecriture)
class ClientSetUp(Frame): """ Dialog box that presents 3 inputs to the user: Username Server IP Port Extends the Frame class in tkinter. """ def __init__(self): super().__init__() self.name = '' self.ip = '' self.port = '' self.initUI() def initUI(self): """ Initialises the dialog box. The box will contain fields for the username, server ip and server port. A button is used to submit the data. """ self.master.title("Connection Details") self.pack(fill=BOTH, expand=True) # Prepare the username field frame1 = Frame(self) frame1.pack(fill=X) lbl1 = Label(frame1, text="Username", width=14) lbl1.pack(side=LEFT, padx=5, pady=10) self.entry1 = Entry(frame1, textvariable=self.name) self.entry1.pack(fill=X, padx=5, expand=True) # Prepare the server address field frame2 = Frame(self) frame2.pack(fill=X) lbl2 = Label(frame2, text="Server Address", width=14) lbl2.pack(side=LEFT, padx=5, pady=10) self.entry2 = Entry(frame2, textvariable=self.ip) self.entry2.pack(fill=X, padx=5, expand=True) # Prepare the server port field frame3 = Frame(self) frame3.pack(fill=X) lbl3 = Label(frame3, text="Server Port", width=14) lbl3.pack(side=LEFT, padx=5, pady=10) self.entry3 = Entry(frame3, textvariable=self.port) self.entry3.pack(fill=X, padx=5, expand=True) frame4 = Frame(self) frame4.pack(fill=X) # Command tells the form what to do when the button is clicked btn = Button(frame4, text="Submit", command=self.onSubmit) btn.pack(padx=5, pady=10) # Give entry1 focus self.entry1.focus() # Set up what happens when Return is pressed # All entries will move onto the next except port which will submit # Note: These didn't work if they weren't lambdas (don't know why) self.entry1.bind('<Return>', lambda event: self.entry2.focus()) self.entry2.bind('<Return>', lambda event: self.entry3.focus()) self.entry3.bind('<Return>', lambda event: self.onSubmit()) photo = PhotoImage(file=resource_path('icon.png')) self.master.iconphoto(False, photo) def onSubmit(self): """ When clicked, the user input is stored in the instance variables and the boxes are cleared. The widget is then destroyed. """ self.name = self.entry1.get() self.ip = self.entry2.get() self.port = self.entry3.get() self.entry1.delete(0, END) self.entry2.delete(0, END) self.entry3.delete(0, END) self.quit() def retry(self, name='', ip='', port=''): """ Used if the user enters incorrect data. It will repopulate the fields where the data was correct. The mainloop is started once the fields are populated. Parameters: name (str): Name of client ip (str): IP of server port (str): Port of server """ self.entry1.insert(0, name) self.entry2.insert(0, ip) self.entry3.insert(0, port) self.mainloop() self.quit() def on_close(self): self.destroy() sys.exit()
class DaxModelParameter(): '''The UI elements and logic to set model parameter values. For this application; all model parameters are assumed to be floats (or ints cast to floats). Strings and Logicals need not apply. ''' def __init__(self, parent, label_frame, sherpa_model_parameter): '''Create model parameter UI element''' self.sherpa_par = sherpa_model_parameter self.parent = parent self.label_frame = label_frame self.initial_value = {'val': self.sherpa_par.val, 'min': self.sherpa_par.min, 'max': self.sherpa_par.max} self.render_ui() def _freeze_thaw(self): '''ACTION: set the freeze() or thaw() based on the checkbox value.''' if 1 == self.fz_box.get(): self.sherpa_par.freeze() else: self.sherpa_par.thaw() @staticmethod def __format_val(val): 'Format parameter values' retval = "{:.5g}".format(val) return retval def reset(self): """Reset values to original""" for field in ['max', 'min', 'val']: to_mod = getattr(self, field) to_mod.delete(0, END) to_mod.insert(0, self.__format_val(self.initial_value[field])) to_mod.configure(foreground="black") setattr(self.sherpa_par, field, self.initial_value[field]) def update(self): """Reset values to original""" for field in ['max', 'min', 'val']: to_mod = getattr(self, field) newval = getattr(self.sherpa_par, field) to_mod.delete(0, END) to_mod.insert(0, self.__format_val(newval)) # ~ to_mod.configure(foreground="black") # ~ setattr(self.sherpa_par, field, self.initial_value[field]) def entry_callback(self, keyevt, field): '''ACTION: set the model parameter value when the user type <<Return>>. Otherwise, when user edits value it turns red so user knows it hasn't been set yet. All values are cast|set to doubles. There is no validation in the UI against the min|max values. Sherpa raises an exception if you try to go beyond the limits so the color remains red until valid value is entered. ''' from sherpa.utils.err import ParameterErr # Note: use .char instead of .keysym because Return # and Enter on the keypad are different keysym's but both # generate CR. This makes sense since can remap keyboard # keys -- the action we want is CR, whichever key generates it. # Update: Unfortunately the .char field is cleared # in newer versions of python in the KeyRelease callback, and # the Key callback doesn't work (order of callback doesn't change # text color correctly). So, I'm back to using the keysym. to_mod = getattr(self, field) if keyevt.keysym in ['Return', 'KP_Enter', 'Enter']: try: fval = float(to_mod.get()) setattr(self.sherpa_par, field, fval) to_mod.configure(foreground="black") to_mod.last_value = to_mod.get() except (ValueError, ParameterErr) as val_err: messagebox.showerror("DAX Model Editor", str(val_err)) else: if to_mod.get() != to_mod.last_value: to_mod.configure(foreground="red") def render_ui(self): '''Render the parameter UI elements and attach bindings''' row = self.parent.get_row() win = self.label_frame # The parameter name lab = Label(win, text=self.sherpa_par.name, width=12, anchor="e") lab.grid(row=row, column=0, padx=(5, 5), pady=2) # The current parameter value self.val_str = StringVar() self.val = Entry(win, textvariable=self.val_str, foreground="black", width=12, justify="right") self.val.grid(row=row, column=1, padx=(5, 5), pady=2) self.val.delete(0, END) self.val.insert(0, self.__format_val(self.sherpa_par.val)) self.val.last_value = self.val.get() self.val.bind("<KeyRelease>", lambda x: self.entry_callback(x, field='val')) # Frozen|Thawed checkbox. Checked if frozen. self.fz_box = IntVar() if self.sherpa_par.frozen is True: self.fz_box.set(1) else: self.fz_box.set(0) fzbtn = Checkbutton(win, text="", variable=self.fz_box, command=self._freeze_thaw) fzbtn.grid(row=row, column=2, padx=(5, 5), pady=2) # The min value self.min_str = StringVar() self.min = Entry(win, textvariable=self.min_str, foreground="black", width=12, justify="right") self.min.grid(row=row, column=3, padx=(5, 5), pady=2) self.min.delete(0, END) self.min.insert(0, self.__format_val(self.sherpa_par.min)) self.min.last_value = self.min.get() self.min.bind("<KeyRelease>", lambda x: self.entry_callback(x, field='min')) # The max value self.max_str = StringVar() self.max = Entry(win, textvariable=self.max_str, foreground="black", width=12, justify="right") self.max.grid(row=row, column=4, padx=(5, 5), pady=2) self.max.delete(0, END) self.max.insert(0, self.__format_val(self.sherpa_par.max)) self.max.last_value = self.max.get() self.max.bind("<KeyRelease>", lambda x: self.entry_callback(x, field='max')) # The units of the parameter par_units = Label(win, text="{}".format(self.sherpa_par.units), width=20, anchor="e") par_units.grid(row=row, column=5, padx=(5, 5), pady=2)
class Search(Module): def __init__(self, app): self.app = app self.window = None self.context_size = 3 self.results = [] self.regex = StringVar(self.app) # if anything ever changes the contents of any intervals # it should call SearchModule.loadIntervals() self.intervals = [] self.loadIntervals() def handleClose(self, event=None): self.window.destroy() self.window = None def createWindow(self): self.window = Toplevel(self.app) self.window.title('Search') self.window.protocol("WM_DELETE_WINDOW", self.handleClose) self.input = Entry(self.window, textvariable=self.regex) self.input.grid(row=0, column=0) self.input.bind('<Return>', self.search) self.input.bind('<Escape>', lambda ev: self.window.focus()) self.searchButton = Button(self.window, text='Search', command=self.search, takefocus=0) self.searchButton.grid(row=0, column=1) self.resultCount = Label(self.window, text='0 results') self.resultCount.grid(row=0, column=2) cols = ('File', 'Tier', 'Time', 'Text') self.scroll = Scrollbar(self.window, orient='vertical') self.resultList = Treeview(self.window, columns=cols, show="headings", yscrollcommand=self.scroll.set, selectmode='browse') self.scroll.config(command=self.resultList.yview) for col in cols: self.resultList.heading(col, text=col) self.resultList.grid(row=2, column=0, columnspan=3, sticky='news') self.resultList.bind('<Double-1>', self.onClick) Grid.rowconfigure(self.window, 2, weight=1) Grid.columnconfigure(self.window, 0, weight=1) self.scroll.grid(row=2, column=3, sticky='ns') def openSearch(self): if self.window == None: self.createWindow() self.window.lift() self.input.focus() def loadIntervals(self): filecount = len(self.app.Data.getTopLevel('files')) self.intervals = [] for f in range(filecount): filename = self.app.Data.getFileLevel('name', f) tg = self.app.Data.checkFileLevel('.TextGrid', f, shoulderror=False) if tg: grid = self.app.TextGrid.fromFile(tg) for tier in grid: if TextGrid.isIntervalTier(tier): for el in tier: if el.mark: self.intervals.append( (el, tier.name, filename)) def search(self, event=None): if self.regex.get() == '': self.results = [] else: pat = re.compile(self.regex.get(), re.IGNORECASE | re.MULTILINE | re.DOTALL) self.results = [] for i in self.intervals: s = pat.search(i[0].mark) if s: disp = i[0].mark a = max(0, s.start() - self.context_size) b = min(s.end() + self.context_size, len(disp)) self.results.append(i + (('...' if a > 0 else '') + disp[a:b] + ('...' if b < len(disp) else ''), )) self.resultCount.configure(text='%s results' % len(self.results)) for kid in self.resultList.get_children(): self.resultList.delete(kid) for row, res in enumerate(self.results): ls = (res[2], res[1], '%s-%s' % (res[0].minTime, res[0].maxTime), res[3]) self.resultList.insert('', 'end', iid=str(row), values=ls) def onClick(self, event=None): self.jumpTo(int(self.resultList.selection()[0])) def jumpTo(self, index): self.app.filesJumpTo(self.results[index][2]) self.app.TextGrid.selectedTier.set(self.results[index][1]) self.app.TextGrid.start = self.results[index][0].minTime self.app.TextGrid.end = self.results[index][0].maxTime for i, f in enumerate(self.app.TextGrid.frameTier): if f.time >= self.results[index][0].minTime: self.app.frameSV.set(str(i)) self.app.framesJumpTo() break self.app.TextGrid.fillCanvases() def reset(self, *args, **kwargs): raise NotImplementedError('cannot call SearchModule::reset') def update(self, *args, **kwargs): raise NotImplementedError('cannot call SearchModule::update') def grid(self, *args, **kwargs): raise NotImplementedError('cannot call SearchModule::grid') def grid_remove(self, *args, **kwargs): raise NotImplementedError('cannot call SearchModule::grid_remove')
class MemberChecker(PanedWindow): def __init__(self, parent): PanedWindow.__init__(self, parent, background="white") self.parent = parent self.init_data() self.init_log() self.init_ui() self.update_status() def init_data(self): self.data_store = api.DataStore() def init_log(self): self.entrance_log = entrance_log.EntranceLog() def init_ui(self): self.parent.title("Member Checker") self.columnconfigure(3, weight=3) self.pack(fill=BOTH, expand=True) self.input = StringVar() self.input_entry = Entry(self, textvariable=self.input) self.input_entry.bind('<Return>', self.submit) self.input_entry.grid(row=0, column=0, columnspan=3, sticky=E + W) self.result = StringVar() self.result_label = Label(self, textvariable=self.result) self.result_label.grid(row=3, column=0, columnspan=3, sticky=E + W) self.name = StringVar() name_label = Label(self, textvariable=self.name) name_label.grid(row=2, column=0, columnspan=3, sticky=E + W) self.status = StringVar() status_label = Label(self, textvariable=self.status) status_label.grid(row=4, column=0, columnspan=4, sticky=E + W) submit_button = Button(self, text="Submit", command=self.submit) submit_button.grid(row=1, column=2) enter_without_card_button = Button(self, text="Enter without card", command=self.enter_without_card) enter_without_card_button.grid(row=1, column=0) enter_member_without_card_button = Button(self, text="Enter member without card", command=self.enter_member_without_card) enter_member_without_card_button.grid(row=1, column=1) self.entrance_log_list = Listbox(self) self.entrance_log_list.grid(row=0, column=3, rowspan=4, sticky=E + W + S + N) self.input_entry.focus() def load_data(self): if messagebox.askyesno("Load new API Data", "Are you sure you want to load the new API data? All previous data will be removed. The program might be unresponsive for a few seconds, but don't kill it, please! It has feelings too."): self.data_store.load_api_data() def enter_by_identification(self, identification): member = self.data_store.find_member_by_identification(identification) if member is None: if messagebox.askyesno("Not a member", "This university identification is not registered as a member. Do you want to let them in as a non-member?"): self.enter_non_member_by_identification(identification) else: self.enter_member(member) def enter_by_barcode(self, barcode): member = self.data_store.find_member_by_barcode(barcode) if member is None: if messagebox.askyesno("Not a member", "This barcode is not registered as a member. Do you want to let them in as a non-member?"): self.enter_non_member_by_barcode(barcode) else: self.enter_member(member) def enter_non_member_by_identification(self, identification): self.entrance_log.enter_non_member_by_identification(identification) self.enter_non_member() def enter_non_member_by_barcode(self, barcode): self.entrance_log.enter_non_member_by_barcode(barcode) self.enter_non_member() def enter_without_card(self): self.clear_result() self.entrance_log.enter_without_card() self.enter_non_member() self.input_entry.focus() def enter_member(self, member): inside_result = self.entrance_log.is_member_inside(member) if inside_result[0]: if not messagebox.askyesno("Already inside", "This membership card has already been used to enter at {}. Are you sure you want to register it again? Normally you should let this person enter without card (and bill them accordingly).".format( inside_result[1])): return self.entrance_log.enter_member(member) self.result.set('Member!') self.result_label.configure(background='green') self.name.set(member['firstName'] + ' ' + member['lastName']) self.update_status() def enter_non_member(self): self.result.set('Not a member!') self.result_label.configure(background='red') self.name.set('Not in the database') self.update_status() def enter_member_without_card(self): name = self.input.get() if len(name) == 0: messagebox.showinfo('Name required', 'Please enter the name of this person!') return self.entrance_log.enter_member_without_card(name) self.result.set('Member without card!') self.result_label.configure(background="orange") self.name.set('') self.input.set('') self.update_status() def clear_result(self): self.result.set('') self.result_label.configure(background='white') self.name.set('') def submit(self, event=None): self.clear_result() entry = self.input.get() if helpers.is_valid_identification(entry): self.enter_by_identification(entry) elif helpers.is_valid_barcode(entry): self.enter_by_barcode(entry) else: messagebox.showinfo('Invalid entry', 'The data entered was not recognized as a valid bar code or a valid university identification. You should click \'enter without card\' to let this person in.') return self.input.set('') self.input_entry.focus() def clear_log(self): if messagebox.askyesno("Clear log", "Are you sure you want to clear the log of all people who entered?"): self.entrance_log.clear_log() self.update_status() def update_status(self): self.status.set("{} members inside. Total: {}".format(self.entrance_log.members_inside_count(), self.entrance_log.inside_count())) logs = self.entrance_log.get_latest_logs(15) self.entrance_log_list.delete(0, 15) for l in logs: s = l['timestamp'] + ": " data = l['data'] if 'member_id' in data: member = self.data_store.find_member(data['member_id']) s += member['firstName'] + " " + member['lastName'] elif 'barcode' in data: s += data['barcode'] elif 'identification' in data: s += data['identification'] elif 'name' in data: s += '[no card]' + data['name'] else: s += "-" self.entrance_log_list.insert(0, s)
class Sync(Tk): """FolderSync main window.""" def __init__(self): Tk.__init__(self, className='FolderSync') self.title("FolderSync") self.geometry("%ix%i" % (self.winfo_screenwidth(), self.winfo_screenheight())) self.protocol("WM_DELETE_WINDOW", self.quitter) self.icon = PhotoImage(master=self, file=IM_ICON) self.iconphoto(True, self.icon) self.rowconfigure(2, weight=1) self.columnconfigure(0, weight=1) # --- icons self.img_about = PhotoImage(master=self, file=IM_ABOUT) self.img_open = PhotoImage(master=self, file=IM_OPEN) self.img_plus = PhotoImage(master=self, file=IM_PLUS) self.img_moins = PhotoImage(master=self, file=IM_MOINS) self.img_sync = PhotoImage(master=self, file=IM_SYNC) self.img_prev = PhotoImage(master=self, file=IM_PREV) self.img_expand = PhotoImage(master=self, file=IM_EXPAND) self.img_collapse = PhotoImage(master=self, file=IM_COLLAPSE) self.original = "" self.sauvegarde = "" # list of files / folders to delete before starting the copy because # they are not of the same type on the original and the backup self.pb_chemins = [] self.err_copie = False self.err_supp = False # --- init log files l = [f for f in listdir(PATH) if match(r"foldersync[0-9]+.pid", f)] nbs = [] for f in l: with open(join(PATH, f)) as fich: old_pid = fich.read().strip() if exists("/proc/%s" % old_pid): nbs.append(int(search(r"[0-9]+", f).group())) else: remove(join(PATH, f)) if not nbs: i = 0 else: nbs.sort() i = 0 while i in nbs: i += 1 self.pidfile = PID_FILE % i open(self.pidfile, 'w').write(str(getpid())) self.log_copie = LOG_COPIE % i self.log_supp = LOG_SUPP % i self.logger_copie = setup_logger("copie", self.log_copie) self.logger_supp = setup_logger("supp", self.log_supp) date = datetime.now().strftime('%d/%m/%Y %H:%M') self.logger_copie.info("\n### %s ###\n" % date) self.logger_supp.info("\n### %s ###\n" % date) # --- filenames and extensions that will not be copied exclude_list = split(r'(?<!\\) ', CONFIG.get("Defaults", "exclude_copie")) self.exclude_names = [] self.exclude_ext = [] for elt in exclude_list: if elt: if elt[:2] == "*.": self.exclude_ext.append(elt[1:]) else: self.exclude_names.append(elt.replace("\ ", " ")) # --- paths that will not be deleted self.exclude_path_supp = [ ch.replace("\ ", " ") for ch in split( r'(?<!\\) ', CONFIG.get("Defaults", "exclude_supp")) if ch ] # while "" in self.exclude_path_supp: # self.exclude_path_supp.remove("") self.q_copie = Queue() self.q_supp = Queue() # True if a copy / deletion is running self.is_running_copie = False self.is_running_supp = False self.style = Style(self) self.style.theme_use("clam") self.style.configure("TProgressbar", troughcolor='lightgray', background='#387EF5', lightcolor="#5D95F5", darkcolor="#2758AB") self.style.map("TProgressbar", lightcolor=[("disabled", "white")], darkcolor=[("disabled", "gray")]) self.style.configure("folder.TButton", padding=0) # --- menu self.menu = Menu(self, tearoff=False) self.configure(menu=self.menu) # -------- recents self.menu_recent = Menu(self.menu, tearoff=False) if RECENT: for ch_o, ch_s in RECENT: self.menu_recent.add_command( label="%s -> %s" % (ch_o, ch_s), command=lambda o=ch_o, s=ch_s: self.open(o, s)) else: self.menu.entryconfigure(0, state="disabled") # -------- favorites self.menu_fav = Menu(self.menu, tearoff=False) self.menu_fav_del = Menu(self.menu_fav, tearoff=False) self.menu_fav.add_command(label=_("Add"), image=self.img_plus, compound="left", command=self.add_fav) self.menu_fav.add_cascade(label=_("Remove"), image=self.img_moins, compound="left", menu=self.menu_fav_del) for ch_o, ch_s in FAVORIS: label = "%s -> %s" % (ch_o, ch_s) self.menu_fav.add_command( label=label, command=lambda o=ch_o, s=ch_s: self.open(o, s)) self.menu_fav_del.add_command( label=label, command=lambda nom=label: self.del_fav(nom)) if not FAVORIS: self.menu_fav.entryconfigure(1, state="disabled") # -------- log files menu_log = Menu(self.menu, tearoff=False) menu_log.add_command(label=_("Copy"), command=self.open_log_copie) menu_log.add_command(label=_("Removal"), command=self.open_log_suppression) # -------- settings menu_params = Menu(self.menu, tearoff=False) self.copy_links = BooleanVar(self, value=CONFIG.getboolean( "Defaults", "copy_links")) self.show_size = BooleanVar(self, value=CONFIG.getboolean( "Defaults", "show_size")) menu_params.add_checkbutton(label=_("Copy links"), variable=self.copy_links, command=self.toggle_copy_links) menu_params.add_checkbutton(label=_("Show total size"), variable=self.show_size, command=self.toggle_show_size) self.langue = StringVar(self, CONFIG.get("Defaults", "language")) menu_lang = Menu(menu_params, tearoff=False) menu_lang.add_radiobutton(label="English", value="en", variable=self.langue, command=self.change_language) menu_lang.add_radiobutton(label="Français", value="fr", variable=self.langue, command=self.change_language) menu_params.add_cascade(label=_("Language"), menu=menu_lang) menu_params.add_command(label=_("Exclude from copy"), command=self.exclusion_copie) menu_params.add_command(label=_("Exclude from removal"), command=self.exclusion_supp) self.menu.add_cascade(label=_("Recents"), menu=self.menu_recent) self.menu.add_cascade(label=_("Favorites"), menu=self.menu_fav) self.menu.add_cascade(label=_("Log"), menu=menu_log) self.menu.add_cascade(label=_("Settings"), menu=menu_params) self.menu.add_command(image=self.img_prev, compound="center", command=self.list_files_to_sync) self.menu.add_command(image=self.img_sync, compound="center", state="disabled", command=self.synchronise) self.menu.add_command(image=self.img_about, compound="center", command=lambda: About(self)) # --- tooltips wrapper = TooltipMenuWrapper(self.menu) wrapper.add_tooltip(4, _('Preview')) wrapper.add_tooltip(5, _('Sync')) wrapper.add_tooltip(6, _('About')) # --- path selection frame_paths = Frame(self) frame_paths.grid(row=0, sticky="ew", pady=(10, 0)) frame_paths.columnconfigure(0, weight=1) frame_paths.columnconfigure(1, weight=1) f1 = Frame(frame_paths, height=26) f2 = Frame(frame_paths, height=26) f1.grid(row=0, column=0, sticky="ew") f2.grid(row=0, column=1, sticky="ew") f1.grid_propagate(False) f2.grid_propagate(False) f1.columnconfigure(1, weight=1) f2.columnconfigure(1, weight=1) # -------- path to original Label(f1, text=_("Original")).grid(row=0, column=0, padx=(10, 4)) f11 = Frame(f1) f11.grid(row=0, column=1, sticky="nsew", padx=(4, 0)) self.entry_orig = Entry(f11) self.entry_orig.place(x=1, y=0, bordermode='outside', relwidth=1) self.b_open_orig = Button(f1, image=self.img_open, style="folder.TButton", command=self.open_orig) self.b_open_orig.grid(row=0, column=2, padx=(0, 7)) # -------- path to backup Label(f2, text=_("Backup")).grid(row=0, column=0, padx=(8, 4)) f22 = Frame(f2) f22.grid(row=0, column=1, sticky="nsew", padx=(4, 0)) self.entry_sauve = Entry(f22) self.entry_sauve.place(x=1, y=0, bordermode='outside', relwidth=1) self.b_open_sauve = Button(f2, image=self.img_open, width=2, style="folder.TButton", command=self.open_sauve) self.b_open_sauve.grid(row=0, column=5, padx=(0, 10)) paned = PanedWindow(self, orient='horizontal') paned.grid(row=2, sticky="eswn") paned.rowconfigure(0, weight=1) paned.columnconfigure(1, weight=1) paned.columnconfigure(0, weight=1) # --- left side frame_left = Frame(paned) paned.add(frame_left, weight=1) frame_left.rowconfigure(3, weight=1) frame_left.columnconfigure(0, weight=1) # -------- files to copy f_left = Frame(frame_left) f_left.columnconfigure(2, weight=1) f_left.grid(row=2, columnspan=2, pady=(4, 2), padx=(10, 4), sticky="ew") Label(f_left, text=_("To copy")).grid(row=0, column=2) frame_copie = Frame(frame_left) frame_copie.rowconfigure(0, weight=1) frame_copie.columnconfigure(0, weight=1) frame_copie.grid(row=3, column=0, sticky="eswn", columnspan=2, pady=(2, 4), padx=(10, 4)) self.tree_copie = CheckboxTreeview(frame_copie, selectmode='none', show='tree') self.b_expand_copie = Button(f_left, image=self.img_expand, style="folder.TButton", command=self.tree_copie.expand_all) TooltipWrapper(self.b_expand_copie, text=_("Expand all")) self.b_expand_copie.grid(row=0, column=0) self.b_expand_copie.state(("disabled", )) self.b_collapse_copie = Button(f_left, image=self.img_collapse, style="folder.TButton", command=self.tree_copie.collapse_all) TooltipWrapper(self.b_collapse_copie, text=_("Collapse all")) self.b_collapse_copie.grid(row=0, column=1, padx=4) self.b_collapse_copie.state(("disabled", )) self.tree_copie.tag_configure("warning", foreground="red") self.tree_copie.tag_configure("link", font="tkDefaultFont 9 italic", foreground="blue") self.tree_copie.tag_bind("warning", "<Button-1>", self.show_warning) self.tree_copie.grid(row=0, column=0, sticky="eswn") self.scroll_y_copie = Scrollbar(frame_copie, orient="vertical", command=self.tree_copie.yview) self.scroll_y_copie.grid(row=0, column=1, sticky="ns") self.scroll_x_copie = Scrollbar(frame_copie, orient="horizontal", command=self.tree_copie.xview) self.scroll_x_copie.grid(row=1, column=0, sticky="ew") self.tree_copie.configure(yscrollcommand=self.scroll_y_copie.set, xscrollcommand=self.scroll_x_copie.set) self.pbar_copie = Progressbar(frame_left, orient="horizontal", mode="determinate") self.pbar_copie.grid(row=4, columnspan=2, sticky="ew", padx=(10, 4), pady=4) self.pbar_copie.state(("disabled", )) # --- right side frame_right = Frame(paned) paned.add(frame_right, weight=1) frame_right.rowconfigure(3, weight=1) frame_right.columnconfigure(0, weight=1) # -------- files to delete f_right = Frame(frame_right) f_right.columnconfigure(2, weight=1) f_right.grid(row=2, columnspan=2, pady=(4, 2), padx=(4, 10), sticky="ew") Label(f_right, text=_("To remove")).grid(row=0, column=2) frame_supp = Frame(frame_right) frame_supp.rowconfigure(0, weight=1) frame_supp.columnconfigure(0, weight=1) frame_supp.grid(row=3, columnspan=2, sticky="eswn", pady=(2, 4), padx=(4, 10)) self.tree_supp = CheckboxTreeview(frame_supp, selectmode='none', show='tree') self.b_expand_supp = Button(f_right, image=self.img_expand, style="folder.TButton", command=self.tree_supp.expand_all) TooltipWrapper(self.b_expand_supp, text=_("Expand all")) self.b_expand_supp.grid(row=0, column=0) self.b_expand_supp.state(("disabled", )) self.b_collapse_supp = Button(f_right, image=self.img_collapse, style="folder.TButton", command=self.tree_supp.collapse_all) TooltipWrapper(self.b_collapse_supp, text=_("Collapse all")) self.b_collapse_supp.grid(row=0, column=1, padx=4) self.b_collapse_supp.state(("disabled", )) self.tree_supp.grid(row=0, column=0, sticky="eswn") self.scroll_y_supp = Scrollbar(frame_supp, orient="vertical", command=self.tree_supp.yview) self.scroll_y_supp.grid(row=0, column=1, sticky="ns") self.scroll_x_supp = Scrollbar(frame_supp, orient="horizontal", command=self.tree_supp.xview) self.scroll_x_supp.grid(row=1, column=0, sticky="ew") self.tree_supp.configure(yscrollcommand=self.scroll_y_supp.set, xscrollcommand=self.scroll_x_supp.set) self.pbar_supp = Progressbar(frame_right, orient="horizontal", mode="determinate") self.pbar_supp.grid(row=4, columnspan=2, sticky="ew", padx=(4, 10), pady=4) self.pbar_supp.state(("disabled", )) # --- bindings self.entry_orig.bind("<Key-Return>", self.list_files_to_sync) self.entry_sauve.bind("<Key-Return>", self.list_files_to_sync) def exclusion_supp(self): excl = ExclusionsSupp(self) self.wait_window(excl) # paths that will not be deleted self.exclude_path_supp = [ ch.replace("\ ", " ") for ch in split( r'(?<!\\) ', CONFIG.get("Defaults", "exclude_supp")) if ch ] def exclusion_copie(self): excl = ExclusionsCopie(self) self.wait_window(excl) exclude_list = CONFIG.get("Defaults", "exclude_copie").split(" ") self.exclude_names = [] self.exclude_ext = [] for elt in exclude_list: if elt: if elt[:2] == "*.": self.exclude_ext.append(elt[2:]) else: self.exclude_names.append(elt) def toggle_copy_links(self): CONFIG.set("Defaults", "copy_links", str(self.copy_links.get())) def toggle_show_size(self): CONFIG.set("Defaults", "show_size", str(self.show_size.get())) def open_log_copie(self): open_file(self.log_copie) def open_log_suppression(self): open_file(self.log_supp) def quitter(self): rep = True if self.is_running_copie or self.is_running_supp: rep = askokcancel( _("Confirmation"), _("A synchronization is ongoing, do you really want to quit?"), parent=self) if rep: self.destroy() def del_fav(self, nom): self.menu_fav.delete(nom) self.menu_fav_del.delete(nom) FAVORIS.remove(tuple(nom.split(" -> "))) save_config() if not FAVORIS: self.menu_fav.entryconfigure(1, state="disabled") def add_fav(self): sauvegarde = self.entry_sauve.get() original = self.entry_orig.get() if original != sauvegarde and original and sauvegarde: if exists(original) and exists(sauvegarde): if not (original, sauvegarde) in FAVORIS: FAVORIS.append((original, sauvegarde)) save_config() label = "%s -> %s" % (original, sauvegarde) self.menu_fav.entryconfigure(1, state="normal") self.menu_fav.add_command(label=label, command=lambda o=original, s= sauvegarde: self.open(o, s)) self.menu_fav_del.add_command( label=label, command=lambda nom=label: self.del_fav(nom)) def open(self, ch_o, ch_s): self.entry_orig.delete(0, "end") self.entry_orig.insert(0, ch_o) self.entry_sauve.delete(0, "end") self.entry_sauve.insert(0, ch_s) self.list_files_to_sync() def open_sauve(self): sauvegarde = askdirectory(self.entry_sauve.get(), parent=self) if sauvegarde: self.entry_sauve.delete(0, "end") self.entry_sauve.insert(0, sauvegarde) def open_orig(self): original = askdirectory(self.entry_orig.get(), parent=self) if original: self.entry_orig.delete(0, "end") self.entry_orig.insert(0, original) def sync(self, original, sauvegarde): """ peuple tree_copie avec l'arborescence des fichiers d'original à copier vers sauvegarde et tree_supp avec celle des fichiers de sauvegarde à supprimer """ errors = [] copy_links = self.copy_links.get() excl_supp = [ path for path in self.exclude_path_supp if commonpath([path, sauvegarde]) == sauvegarde ] def get_name(elt): return elt.name.lower() def lower(char): return char.lower() def arbo(tree, parent, n): """ affiche l'arborescence complète de parent et renvoie la longueur maximale des items (pour gérer la scrollbar horizontale) """ m = 0 try: with scandir(parent) as content: l = sorted(content, key=get_name) for item in l: chemin = item.path nom = item.name if item.is_symlink(): if copy_links: tree.insert(parent, 'end', chemin, text=nom, tags=("whole", "link")) m = max(m, len(nom) * 9 + 20 * (n + 1)) elif ((nom not in self.exclude_names) and (splitext(nom)[-1] not in self.exclude_ext)): tree.insert(parent, 'end', chemin, text=nom, tags=("whole", )) m = max(m, len(nom) * 9 + 20 * (n + 1)) if item.is_dir(): m = max(m, arbo(tree, chemin, n + 1)) except NotADirectoryError: pass except Exception as e: errors.append(str(e)) return m def aux(orig, sauve, n, search_supp): m_copie = 0 m_supp = 0 try: lo = listdir(orig) ls = listdir(sauve) except Exception as e: errors.append(str(e)) lo = [] ls = [] lo.sort(key=lambda x: x.lower()) ls.sort(key=lambda x: x.lower()) supp = False copie = False if search_supp: for item in ls: chemin_s = join(sauve, item) if chemin_s not in excl_supp and item not in lo: supp = True self.tree_supp.insert(sauve, 'end', chemin_s, text=item, tags=("whole", )) m_supp = max(m_supp, int(len(item) * 9 + 20 * (n + 1)), arbo(self.tree_supp, chemin_s, n + 1)) for item in lo: chemin_o = join(orig, item) chemin_s = join(sauve, item) if ((item not in self.exclude_names) and (splitext(item)[-1] not in self.exclude_ext)): if item not in ls: # le dossier / fichier n'est pas dans la sauvegarde if islink(chemin_o): if copy_links: copie = True self.tree_copie.insert(orig, 'end', chemin_o, text=item, tags=("whole", "link")) m_copie = max( m_copie, (int(len(item) * 9 + 20 * (n + 1)))) else: copie = True self.tree_copie.insert(orig, 'end', chemin_o, text=item, tags=("whole", )) m_copie = max( m_copie, (int(len(item) * 9 + 20 * (n + 1))), arbo(self.tree_copie, chemin_o, n + 1)) elif islink(chemin_o) and exists(chemin_o): # checking the existence prevent from copying broken links if copy_links: if not islink(chemin_s): self.pb_chemins.append(chemin_o) tags = ("whole", "warning", "link") else: tags = ("whole", "link") self.tree_copie.insert(orig, 'end', chemin_o, text=item, tags=tags) m_copie = max(m_copie, int(len(item) * 9 + 20 * (n + 1))) copie = True elif isfile(chemin_o): # first check if chemin_s is also a file if isfile(chemin_s): if getmtime(chemin_o) // 60 > getmtime( chemin_s) // 60: # le fichier f a été modifié depuis la dernière sauvegarde copie = True self.tree_copie.insert(orig, 'end', chemin_o, text=item, tags=("whole", )) else: self.pb_chemins.append(chemin_o) self.tree_copie.insert(orig, 'end', chemin_o, text=item, tags=("whole", "warning")) elif isdir(chemin_o): # to avoid errors due to unrecognized item types (neither file nor folder nor link) if isdir(chemin_s): self.tree_copie.insert(orig, 'end', chemin_o, text=item) self.tree_supp.insert(sauve, 'end', chemin_s, text=item) c, s, mc, ms = aux( chemin_o, chemin_s, n + 1, search_supp and (chemin_s not in excl_supp)) supp = supp or s copie = copie or c if not c: # nothing to copy self.tree_copie.delete(chemin_o) else: m_copie = max( m_copie, mc, int(len(item) * 9 + 20 * (n + 1))) if not s: # nothing to delete self.tree_supp.delete(chemin_s) else: m_supp = max(m_supp, ms, int(len(item) * 9 + 20 * (n + 1))) else: copie = True self.pb_chemins.append(chemin_o) self.tree_copie.insert(orig, 'end', chemin_o, text=item, tags=("whole", "warning")) m_copie = max( m_copie, (int(len(item) * 9 + 20 * (n + 1))), arbo(self.tree_copie, chemin_o, n + 1)) return copie, supp, m_copie, m_supp self.tree_copie.insert("", 0, original, text=original, tags=("checked", ), open=True) self.tree_supp.insert("", 0, sauvegarde, text=sauvegarde, tags=("checked", ), open=True) c, s, mc, ms = aux(original, sauvegarde, 1, True) if not c: self.tree_copie.delete(original) self.tree_copie.column("#0", minwidth=0, width=0) else: mc = max(len(original) * 9 + 20, mc) self.tree_copie.column("#0", minwidth=mc, width=mc) if not s: self.tree_supp.delete(sauvegarde) self.tree_supp.column("#0", minwidth=0, width=0) else: ms = max(len(sauvegarde) * 9 + 20, mc) self.tree_supp.column("#0", minwidth=ms, width=ms) return errors def show_warning(self, event): if "disabled" not in self.b_open_orig.state(): x, y = event.x, event.y elem = event.widget.identify("element", x, y) if elem == "padding": orig = self.tree_copie.identify_row(y) sauve = orig.replace(self.original, self.sauvegarde) showwarning( _("Warning"), _("%(original)s and %(backup)s are not of the same kind (folder/file/link)" ) % { 'original': orig, 'backup': sauve }, master=self) def list_files_to_sync(self, event=None): """Display in a treeview the file to copy and the one to delete.""" self.pbar_copie.configure(value=0) self.pbar_supp.configure(value=0) self.sauvegarde = self.entry_sauve.get() self.original = self.entry_orig.get() if self.original != self.sauvegarde and self.original and self.sauvegarde: if exists(self.original) and exists(self.sauvegarde): o_s = (self.original, self.sauvegarde) if o_s in RECENT: RECENT.remove(o_s) self.menu_recent.delete("%s -> %s" % o_s) RECENT.insert(0, o_s) self.menu_recent.insert_command( 0, label="%s -> %s" % o_s, command=lambda o=self.original, s=self.sauvegarde: self. open(o, s)) if len(RECENT) == 10: del (RECENT[-1]) self.menu_recent.delete(9) save_config() self.menu.entryconfigure(0, state="normal") self.configure(cursor="watch") self.toggle_state_gui() self.update_idletasks() self.update() self.efface_tree() err = self.sync(self.original, self.sauvegarde) self.configure(cursor="") self.toggle_state_gui() c = self.tree_copie.get_children("") s = self.tree_supp.get_children("") if not (c or s): self.menu.entryconfigure(5, state="disabled") self.b_collapse_copie.state(("disabled", )) self.b_expand_copie.state(("disabled", )) self.b_collapse_supp.state(("disabled", )) self.b_expand_supp.state(("disabled", )) elif not c: self.b_collapse_copie.state(("disabled", )) self.b_expand_copie.state(("disabled", )) elif not s: self.b_collapse_supp.state(("disabled", )) self.b_expand_supp.state(("disabled", )) if err: showerror(_("Errors"), "\n".join(err), master=self) notification_send(_("Scan is finished.")) warnings = self.tree_copie.tag_has('warning') if warnings: showwarning( _("Warning"), _("Some elements to copy (in red) are not of the same kind on the original and the backup." ), master=self) else: showerror(_("Error"), _("Invalid path!"), master=self) def efface_tree(self): """Clear both trees.""" c = self.tree_copie.get_children("") for item in c: self.tree_copie.delete(item) s = self.tree_supp.get_children("") for item in s: self.tree_supp.delete(item) self.b_collapse_copie.state(("disabled", )) self.b_expand_copie.state(("disabled", )) self.b_collapse_supp.state(("disabled", )) self.b_expand_supp.state(("disabled", )) def toggle_state_gui(self): """Toggle the state (normal/disabled) of key elements of the GUI.""" if "disabled" in self.b_open_orig.state(): state = "!disabled" for i in range(7): self.menu.entryconfigure(i, state="normal") else: state = "disabled" for i in range(7): self.menu.entryconfigure(i, state="disabled") self.tree_copie.state((state, )) self.tree_supp.state((state, )) self.entry_orig.state((state, )) self.entry_sauve.state((state, )) self.b_expand_copie.state((state, )) self.b_collapse_copie.state((state, )) self.b_expand_supp.state((state, )) self.b_collapse_supp.state((state, )) self.b_open_orig.state((state, )) self.b_open_sauve.state((state, )) def update_pbar(self): """ Dislay the progress of the copy and deletion and put the GUI back in normal state once both processes are done. """ if not self.is_running_copie and not self.is_running_supp: notification_send(_("Sync is finished.")) self.toggle_state_gui() self.pbar_copie.configure(value=self.pbar_copie.cget("maximum")) self.pbar_supp.configure(value=self.pbar_supp.cget("maximum")) self.menu.entryconfigure(5, state="disabled") self.configure(cursor="") self.efface_tree() msg = "" if self.err_copie: msg += _( "There were errors during the copy, see %(file)s for more details.\n" ) % { 'file': self.log_copie } if self.err_supp: msg += _( "There were errors during the removal, see %(file)s for more details.\n" ) % { 'file': self.log_supp } if msg: showerror(_("Error"), msg, master=self) else: if not self.q_copie.empty(): self.pbar_copie.configure(value=self.q_copie.get()) if not self.q_supp.empty(): self.pbar_supp.configure(value=self.q_supp.get()) self.update() self.after(50, self.update_pbar) @staticmethod def get_list(tree): """Return the list of files/folders to copy/delete (depending on the tree).""" selected = [] def aux(item): tags = tree.item(item, "tags") if "checked" in tags and "whole" in tags: selected.append(item) elif "checked" in tags or "tristate" in tags: ch = tree.get_children(item) for c in ch: aux(c) ch = tree.get_children("") for c in ch: aux(c) return selected def synchronise(self): """ Display the list of files/folders that will be copied / deleted and launch the copy and deletion if the user validates the sync. """ # get files to delete and folder to delete if they are empty a_supp = self.get_list(self.tree_supp) # get files to copy a_copier = self.get_list(self.tree_copie) a_supp_avant_cp = [] for ch in self.pb_chemins: if ch in a_copier: a_supp_avant_cp.append( ch.replace(self.original, self.sauvegarde)) if a_supp or a_copier: Confirmation(self, a_copier, a_supp, a_supp_avant_cp, self.original, self.sauvegarde, self.show_size.get()) def copie_supp(self, a_copier, a_supp, a_supp_avant_cp): """Launch sync.""" self.toggle_state_gui() self.configure(cursor="watch") self.update() self.pbar_copie.state(("!disabled", )) self.pbar_supp.state(("!disabled", )) nbtot_copie = len(a_copier) + len(a_supp_avant_cp) self.pbar_copie.configure(maximum=nbtot_copie, value=0) nbtot_supp = len(a_supp) self.pbar_supp.configure(maximum=nbtot_supp, value=0) self.is_running_copie = True self.is_running_supp = True process_copie = Thread(target=self.copie, name="copie", daemon=True, args=(a_copier, a_supp_avant_cp)) process_supp = Thread(target=self.supp, daemon=True, name="suppression", args=(a_supp, )) process_copie.start() process_supp.start() self.pbar_copie.configure(value=0) self.pbar_supp.configure(value=0) self.update_pbar() def copie(self, a_copier, a_supp_avant_cp): """ Copie tous les fichiers/dossiers de a_copier de original vers sauvegarde en utilisant la commande système cp. Les erreurs rencontrées au cours du processus sont inscrites dans ~/.foldersync/copie.log """ self.err_copie = False orig = abspath(self.original) + "/" sauve = abspath(self.sauvegarde) + "/" chdir(orig) self.logger_copie.info( _("\n###### Copy: %(original)s -> %(backup)s\n") % { 'original': self.original, 'backup': self.sauvegarde }) n = len(a_supp_avant_cp) self.logger_copie.info(_("Removal before copy:")) for i, ch in zip(range(1, n + 1), a_supp_avant_cp): self.logger_copie.info(ch) p_copie = run(["rm", "-r", ch], stderr=PIPE) self.q_copie.put(i) err = p_copie.stderr.decode() if err: self.err_copie = True self.logger_copie.error(err.strip()) self.logger_copie.info(_("Copy:")) for i, ch in zip(range(n + 1, n + 1 + len(a_copier)), a_copier): ch_o = ch.replace(orig, "") self.logger_copie.info("%s -> %s" % (ch_o, sauve)) p_copie = run(["cp", "-ra", "--parents", ch_o, sauve], stderr=PIPE) self.q_copie.put(i) err = p_copie.stderr.decode() if err: self.err_copie = True self.logger_copie.error(err.strip()) self.is_running_copie = False def supp(self, a_supp): """ Supprime tous les fichiers/dossiers de a_supp de original vers sauvegarde en utilisant la commande système rm. Les erreurs rencontrées au cours du processus sont inscrites dans ~/.foldersync/suppression.log. """ self.err_supp = False self.logger_supp.info( _("\n###### Removal: %(original)s -> %(backup)s\n") % { 'original': self.original, 'backup': self.sauvegarde }) for i, ch in enumerate(a_supp): self.logger_supp.info(ch) p_supp = run(["rm", "-r", ch], stderr=PIPE) self.q_supp.put(i + 1) err = p_supp.stderr.decode() if err: self.logger_supp.error(err.strip()) self.err_supp = True self.is_running_supp = False def unlink(self): """Unlink pidfile.""" unlink(self.pidfile) def change_language(self): """Change app language.""" CONFIG.set("Defaults", "language", self.langue.get()) showinfo( _("Information"), _("The language setting will take effect after restarting the application" ))
""" print(text) index = int(index) if text.isupper() and index == 0: return True if input in (",", ".", "'", " ") and index > 0: return True if inp.isalnum() and index > 0: return True if text == "": return True else: return False vcmd = root.register(is_okay) entsv = StringVar() ent0 = Entry(lf0, validate='key', validatecommand=(vcmd, '%P', '%S', '%i'), textvariable=entsv) ent0.bind("<Return>", end_input) ent0.grid(row=1, column=0, padx=10) ent0.focus() mess_lbl = Label(lf0, text='Start with capital letter, <Return> to confirm') mess_lbl.grid(row=2, column=0, pady=10, padx=10) root.mainloop()
class SettingsUI: def __init__(self, mainFrame): "initiates settings and creates the interface" self.playerList = [] self.gameList = ("301", "501", "Clock") self.initUI(mainFrame) def buildPlayerHeaderString(self): """Build a connection string from a dictionary of parameters. Returns string.""" return "Players: " + ", ".join(["%s" % player.name for player in self.playerList]) def addPlayerText(self, name): self.playerList.append(Player(name)) #bind add player click event def onAddPlayerClick(self, event): "callback method for the add player button" self.addPlayer() def onAddPlayerEnter(self, event): "callback method for the add player button" if event.keycode == 13: self.addPlayer() def addPlayer(self): name = self.playerNameEntry.get() if name: self.addPlayerText(name) self.playerString.set(self.buildPlayerHeaderString()) self.nameFieldVar.set("") self.playerNameEntry.focus() return("break") def initUI(self, mainFrame): """initialize the User Interface""" # styles style = Style() style.configure("GRN.TLabel", background="#ACF059") style.configure("GRN.TFrame", background="#ACF059") style.configure("BLK.TFrame", background="#595959") # create top frame topFrame = Frame(mainFrame, style="GRN.TFrame", padding=8) topFrame.pack(fill=BOTH, side=TOP) # create black border borderFrame = Frame(mainFrame, style="BLK.TFrame") borderFrame.pack(fill=BOTH, side=TOP) # create add player frame addPlayerFrame = Frame(mainFrame, padding=8) addPlayerFrame.pack(side=TOP) # create text field for add button self.nameFieldVar = StringVar() self.playerNameEntry = Entry(addPlayerFrame, textvariable = self.nameFieldVar) self.playerNameEntry.pack(side=LEFT) # create add player button addButton = Button(addPlayerFrame, text="Add player") addButton.pack(side=LEFT) # create choose game list self.currentGame = StringVar() self.currentGame.set(self.gameList[0]) gameDropDown = OptionMenu(mainFrame, self.currentGame, self.gameList[0], *self.gameList) gameDropDown.pack(side=TOP) # create start game button startGameButton = Button(mainFrame, text="Start") startGameButton.bind("<Button-1>", self.startGame) startGameButton.pack(side=TOP) # create label and set text self.playerString = StringVar() self.playerString.set(self.buildPlayerHeaderString()) headerLabel = Label(topFrame, textvariable=self.playerString, style="GRN.TLabel") headerLabel.pack(side=TOP) addButton.bind("<Button-1>", self.onAddPlayerClick) self.playerNameEntry.bind("<Key>", self.onAddPlayerEnter) #set focus self.playerNameEntry.focus() def startGame(self,event): "starts the selected game" if self.playerList: mainFrame.pack_forget() gameFrame = Frame(root) gameFrame.pack(fill=BOTH, expand=1) game = self.currentGame.get() if game == "301": gameX01.GameX01(gameFrame, self.playerList) elif game == "501": gameX01.GameX01(gameFrame, self.playerList, 501) elif game == "Clock": gameClock.GameClock(gameFrame, self.playerList) else: gameX01.GameX01(gameFrame, self.playerList)
def __init__(self, master=None): Frame.__init__(self, master) self.player = StringVar() self.character = StringVar() self.dm = StringVar() self.str = StringVar() self.int = StringVar() self.wis = StringVar() self.dex = StringVar() self.con = StringVar() self.cha = StringVar() self.JPpoison = StringVar() self.JPwands = StringVar() self.JPparalysis = StringVar() self.JPbreath = StringVar() self.JPspell = StringVar() self.class_ = StringVar() self.race = StringVar() self.align = StringVar() self.AC = StringVar() self.HP = StringVar() self.maxHP = StringVar() self.XP_to_add = StringVar() self.XPbonus = StringVar() self.XPtotal = IntVar() self.level = StringVar() self.init_once() ( self.baseXP, self.mainCarRace, self.mainCarClass) = self.classDifferenciation() self.remainingXP = StringVar() self.remainingXP.set(self.getRemainingXP()) self.bonusXP = StringVar() self.bonusXP.set(self.getBonusXP()) self.freeze = IntVar() self.freeze.set(1) Label(self, text="Player Name:").grid(row=0, column=0, columnspan=2) Label(self, text="Character Name :").grid( row=0, column=4, columnspan=2) Label(self, text="DM Name:").grid(row=0, column=8, columnspan=2) Label(self, text="STR:").grid(row=1, column=0) Label(self, text="INT:").grid(row=2, column=0) Label(self, text="WIS:").grid(row=3, column=0) Label(self, text="DEX:").grid(row=4, column=0) Label(self, text="CON:").grid(row=5, column=0) Label(self, text="CHA:").grid(row=6, column=0) Label(self, text="Poison/Deathray:").grid(row=1, column=2) Label(self, text="Wands:").grid(row=2, column=2) Label(self, text="Paralysis:").grid(row=3, column=2) Label(self, text="Dragon Breath:").grid(row=4, column=2) Label(self, text="Spells:").grid(row=5, column=2) Label(self, text="Armor Class").grid(row=1, column=4, columnspan=1) Label(self, text="Health Points").grid(row=1, column=5, columnspan=3) Label(self, text=" / ").grid(row=2, column=6) Label(self, text="Class :").grid(row=3, column=4) Label(self, text="Race :").grid(row=4, column=4) Label(self, text="XP to add :").grid(row=7, column=0) Label(self, text="Remaining :").grid(row=8, column=0) Label(self, text="Bonus :").grid(row=7, column=2) Label(self, text="Alignment :").grid(row=3, column=6) Label(self, text="Level :").grid(row=9, column=0, columnspan=2) self.remainingLabel = Label( self, textvariable=self.remainingXP, relief=SUNKEN, width=5) self.remainingLabel.grid(row=8, column=1) self.bonusLabel = Label( self, textvariable=self.bonusXP, relief=SUNKEN, width=5) self.bonusLabel.grid(row=7, column=3) self.levelLabel = Label( self, textvariable=self.level, relief=SUNKEN, width=5) self.levelLabel.grid(row=9, column=2, columnspan=2) Eplayer = Entry(self, textvariable=self.player) Eplayer.grid(row=0, column=2, columnspan=2) Eplayer.bind(sequence='<KeyRelease>', func=self.refresh) Echaracter = Entry(self, textvariable=self.character) Echaracter.grid(row=0, column=6, columnspan=2) Echaracter.bind(sequence='<KeyRelease>', func=self.refresh) EDM = Entry(self, textvariable=self.dm) EDM.grid(row=0, column=10, columnspan=2) EDM.bind(sequence='<KeyRelease>', func=self.refresh) Estr = Entry(self, textvariable=self.str) Estr.grid(row=1, column=1) Estr.bind(sequence='<KeyRelease>', func=self.refresh) Eint = Entry(self, textvariable=self.int) Eint.grid(row=2, column=1) Eint.bind(sequence='<KeyRelease>', func=self.refresh) Ewis = Entry(self, textvariable=self.wis) Ewis.grid(row=3, column=1) Ewis.bind(sequence='<KeyRelease>', func=self.refresh) Edex = Entry(self, textvariable=self.dex) Edex.grid(row=4, column=1) Edex.bind(sequence='<KeyRelease>', func=self.refresh) Econ = Entry(self, textvariable=self.con) Econ.grid(row=5, column=1) Econ.bind(sequence='<KeyRelease>', func=self.refresh) Echa = Entry(self, textvariable=self.cha) Echa.grid(row=6, column=1) Echa.bind(sequence='<KeyRelease>', func=self.refresh) Entry(self, textvariable=self.JPpoison).grid(row=1, column=3) Entry(self, textvariable=self.JPwands).grid(row=2, column=3) Entry(self, textvariable=self.JPparalysis).grid(row=3, column=3) Entry(self, textvariable=self.JPbreath).grid(row=4, column=3) Entry(self, textvariable=self.JPspell).grid(row=5, column=3) Entry(self, textvariable=self.AC).grid(row=2, column=4) Entry(self, textvariable=self.HP).grid(row=2, column=5) Entry(self, textvariable=self.maxHP).grid(row=2, column=7) EXP = Entry(self, textvariable=self.XP_to_add) EXP.grid(row=7, column=1) EXP.bind(sequence='<KeyPress-Return>', func=self.addXP) OptionMenu( self, self.class_, "Class", "Warrior", "Wizard", "Thief", "Cleric").grid(row=3, column=5) OptionMenu( self, self.align, "Alignment", "Lawful Good", "Lawful Neutral", "Lawful Evil", "Neutral Good", "Neutral Neutral", "Neutral Evil", "Chaotic Good", "Chaotic Neutral", "Chaotic Evil").grid(row=3, column=7) OptionMenu( self, self.race, "Race", "Human", "Elf", "Dwarf", "Halfelin").grid(row=4, column=5) Button( self, text="Add XP", command=self.refresh, width=6).grid(row=10, column=3)
def _gui(): try: from tkinter import Tk, ttk, filedialog, messagebox, StringVar, IntVar from tkinter.ttk import Button, Entry, Frame, Label, LabelFrame, Notebook, Radiobutton, Style except: sys.exit("Unable to load tkinter. Aborting.") def _check_single(): #check the input and accordingly give the output... for the f_single tab if txt_f_single_entry.get()=="": lbl_f_single_result.config(text="", style="TLabel") elif check_afm(txt_f_single_entry.get()): lbl_f_single_result.config(text="Έγκυρο ΑΦΜ.", style="valid.TLabel") else: lbl_f_single_result.config(text="Άκυρο ΑΦΜ.", style="invalid.TLabel") def _select_input_file(): strv_f_file_input.set(filedialog.askopenfilename(title="Άνοιγμα αρχείου")) if strv_f_file_input.get() != "" and strv_f_file_output.get() != "": btn_f_file_submit.config(state="normal") else: btn_f_file_submit.config(state="disabled") #TODO a much better mechanism to enable / disable btn_f_file_submit is needed. def _select_output_file(): strv_f_file_output.set(filedialog.asksaveasfilename(title="Αποθήκευση ως...")) if strv_f_file_input.get() != "" and strv_f_file_output.get() != "": btn_f_file_submit.config(state="normal") else: btn_f_file_submit.config(state="disabled") def _check_file():#TODO this could / should be merged with the TUI version... input_filepath = strv_f_file_input.get() output_filepath = strv_f_file_output.get() filter_output = intvar_filter_sel.get() try: input_file = open(input_filepath, "r") output_file = open(output_filepath, "w") except: messagebox.showerror(title="Σφάλμα", message="Αδυναμία διαχείρησης των αρχείων που ορίσατε.\n\nΠαρακαλώ επιβεβαιώστε πως το αρχείο με τα δεδομένα υπάρχει, πως έχετε δικαιώματα ανάγνωσης, και πως έχετε δικαιώματα εγγραφής στον κατάλογο εξαγωγής των αποτελεσμάτων.") return counter = {True:0, False:0} for entry in input_file: validation = check_afm(entry.strip()) counter[validation]+=1 if filter_output == 3 and validation == False: output_file.write(entry) elif filter_output == 2 and validation == True: output_file.write(entry) elif filter_output == 1: output_file.write(entry.strip() + "\t" + str(validation) + "\n\r") lbl_f_file_result.config(text="Σύνολο: "+str(counter[True]+counter[False])+"\nΈγκυρα: "+str(counter[True])+"\nΆκυρα: "+str(counter[False])) #create the window main_window = Tk() main_window.title("Έλεγχος εγκυρότητας Α.Φ.Μ. (v 2.0)") main_window.geometry("600x180") main_window.minsize(600,180) #fool arround with styling style = ttk.Style() style.configure("valid.TLabel", background="green") style.configure("empty.TLabel", background="white") style.configure("invalid.TLabel", background="red") style.configure("TNotebook", padding = 10) #create the Notebook tabs = Notebook(main_window) f_single = Frame(tabs) f_file = Frame(tabs) tabs.add(f_single, text="Μεμονομένα Α.Φ.Μ.") tabs.add(f_file, text="Λίστα από αρχείο")#add state="disabled" prior to git push until ready tabs.pack(anchor="nw") #add some widgets in f_single tab lbl_f_single_instructions = Label(f_single, text="Εισάγετε έναν ΑΦΜ για έλεγχο") lbl_f_single_instructions.grid(column=0, row=0) lbl_f_single_result = Label(f_single, text="", width=10, justify="center") lbl_f_single_result.grid(column=1, row=0, rowspan=2, sticky="ewns") txt_f_single_entry = Entry(f_single, width=11) txt_f_single_entry.focus() txt_f_single_entry.bind("<KeyRelease>", lambda e: _check_single() ) txt_f_single_entry.grid(column=0,row=1) #btn_f_single_submit = Button(f_single, text="Έλεγχος", command=_check_single) #btn_f_single_submit.grid(column=0,row=2) #add some widgets in f_file tab lbl_f_file_finput = Label(f_file, text="Άνοιγμα...") lbl_f_file_finput.grid(column=0, row=0) strv_f_file_input = StringVar() txt_f_file_finput = Entry(f_file, textvariable = strv_f_file_input) txt_f_file_finput.grid(column=1, row=0) btn_f_file_finput = Button(f_file, text="...", width=3, command=_select_input_file) btn_f_file_finput.grid(column=2, row=0, sticky="W") lbl_f_file_foutput = Label(f_file, text="Αποθήκευση ως...") lbl_f_file_foutput.grid(column=0, row=1) strv_f_file_output = StringVar() txt_f_file_foutput = Entry(f_file, textvariable = strv_f_file_output) txt_f_file_foutput.grid(column=1, row=1) btn_f_file_foutput = Button(f_file, text="...", width=3, command=_select_output_file) btn_f_file_foutput.grid(column=2, row=1, sticky="W") lf_filter = LabelFrame(f_file, text="Επιστροφή") lf_filter.grid(column=3, row=0, rowspan=2, sticky="ewns") intvar_filter_sel = IntVar() rb_filter_all = Radiobutton(lf_filter, text="Όλων", variable=intvar_filter_sel, value=1) #TODO maybe add command rb_filter_all.pack(anchor="w") rb_filter_all.invoke() rb_filter_true = Radiobutton(lf_filter, text="Έγκυρων", variable=intvar_filter_sel, value=2) rb_filter_true.pack(anchor="w") rb_filter_false = Radiobutton(lf_filter, text="Άκυρων", variable=intvar_filter_sel, value=3) rb_filter_false.pack(anchor="w") lf_result = LabelFrame(f_file, text="Σύνοψη") lf_result.grid(column=4, row=0, rowspan=2, sticky="ewns") lbl_f_file_result = Label(lf_result, text="", width=12)#TODO bring results lbl_f_file_result.pack() btn_f_file_submit = Button(f_file, text="Επεξεργασία", state="disabled", command=_check_file) btn_f_file_submit.grid(column=0, row=2, columnspan=3) btn_main_exit = Button(main_window, text="Έξοδος", command=sys.exit) btn_main_exit.pack(anchor="se") main_window.mainloop()
def __init__(self): """__init__ creates the tkinter gui""" self.__settings = {} self.__importer = CsvXmlImporter() # ***--*** main window and menu band ***---*** self.__root = ThemedTk(theme=theme) self.__root.title("Csv/Xml Importer") self.__root.minsize(560, 1) menu = Menu(self.__root) self.__root.config(menu=menu) filemenu = Menu(menu, tearoff=0) menu.add_cascade(label="File", menu=filemenu) filemenu.add_command(label="Add Files", command=self.add_files) filemenu.add_command(label="Remove All", command=self.remove_all) filemenu.add_separator() filemenu.add_command(label="Add xsl File", command=self.add_xslfile) filemenu.add_separator() filemenu.add_command(label="Exit", command=self.exit) helpmenu = Menu(menu, tearoff=0) menu.add_cascade(label="Help", menu=helpmenu) helpmenu.add_command(label="?", command=self.ask_help) helpmenu.add_command(label="About", command=self.ask_about) # ***---*** source file frame dialog ***---*** srcfilesframe = LabelFrame(self.__root, text="Sourcefiles") buttonframe = Frame(srcfilesframe) addbutton = Button(buttonframe, text="Add Files", command=self.add_files) addbutton.pack(fill=X) removefilesbutton = Button(buttonframe, text="Remove Selected", command=self.remove_files) removefilesbutton.pack(fill=X) removeallbutton = Button(buttonframe, text="Remove All", command=self.remove_all) removeallbutton.pack(fill=X) buttonframe.grid(column=1, row=1) self.__srcfileslistbox = Listbox(srcfilesframe, selectmode="extended", width=100, height=5) self.__srcfileslistbox.grid(column=2, row=1) Label(srcfilesframe, text="Encoding").grid(column=1, row=2, sticky=E) self.__settings["encoding"] = StringVar() self.__settings["encoding"].trace_add("write", self.update_settings) encCombobox = Combobox(srcfilesframe, textvariable=self.__settings["encoding"], values=encodings, state="readonly") encCombobox.bind("<FocusOut>", self.update_settings) encCombobox.grid(column=2, row=2, pady=10) srcfilesframe.pack(fill=X) # ***---*** xsl file dialog ***---*** xslfileframe = LabelFrame(self.__root, text="XSL-File") Button(xslfileframe, text="Add .xsl", command=self.add_xslfile).grid(column=1, row=1) self.__xsllistbox = Listbox(xslfileframe, width=100, height=1) self.__xsllistbox.grid(column=2, row=1, sticky="w") buttonframe = Frame(xslfileframe) Button(buttonframe, text="Apply Parameter", command=self.apply_xslparameter).pack(fill=X) Button(buttonframe, text="Restore Default", command=self.reset_xslparameter).pack(fill=X) buttonframe.grid(column=1, row=2) box = Frame(xslfileframe) self.__xslparametertext = Text(box, height=3, width=75) self.__xslparametertext.grid(column=0, row=1, sticky="nsew") scrollbar = Scrollbar(box, command=self.__xslparametertext.yview) scrollbar.grid(column=0, row=1, sticky="nse") box.grid(column=2, row=2, sticky="we") self.__xslparametertext["yscrollcommand"] = scrollbar.set xslfileframe.pack(fill=X) # ***---*** file format settings dialog ***---*** # small help function def limit_character(entry_text): """limit_characters cuts down the characters of an entry text to one""" if len(entry_text.get()) > 0: # take only last input character and throw away the rest entry_text.set(entry_text.get()[-1]) fileformatsettingsframe = LabelFrame(self.__root, text="File Format Settings") Label(fileformatsettingsframe, text="Delimiter").grid(column=1, row=1, sticky=E) self.__settings["delimiter"] = StringVar() seperatorentry = Entry(fileformatsettingsframe, textvariable=self.__settings["delimiter"], width=1) self.__settings["delimiter"].trace_add( "write", lambda *_: limit_character(self.__settings["delimiter"])) seperatorentry.bind("<Return>", self.update_settings) seperatorentry.bind("<FocusOut>", self.update_settings) seperatorentry.grid(column=2, row=1, sticky=W, padx=15) Label(fileformatsettingsframe, text="Quotechar").grid(column=1, row=2, sticky=E) self.__settings["quotechar"] = StringVar() quotecharentry = Entry(fileformatsettingsframe, textvariable=self.__settings["quotechar"], width=1) self.__settings["quotechar"].trace_add( "write", lambda *_: limit_character(self.__settings["quotechar"])) quotecharentry.bind("<Return>", self.update_settings) quotecharentry.bind("<FocusOut>", self.update_settings) quotecharentry.grid(column=2, row=2, sticky=W, padx=15) Label(fileformatsettingsframe, text="Doublequote").grid(column=1, row=3, sticky=E) self.__settings["doublequote"] = BooleanVar() Checkbutton(fileformatsettingsframe, variable=self.__settings["doublequote"], command=self.update_settings).grid(column=2, row=3, sticky=W, padx=10) Label(fileformatsettingsframe, text="Quoting").grid(column=1, row=5, sticky=E) quotingopt = {"minimal": 0, "all": 1, "non numeric": 2, "none": 3} self.__settings["quoting"] = IntVar() for i, (key, value) in enumerate(quotingopt.items()): Radiobutton( fileformatsettingsframe, text=key, value=value, variable=self.__settings["quoting"], command=self.update_settings, ).grid( column=2 + i, row=5, padx=10, sticky=W, ) Label(fileformatsettingsframe, text="Ignore spaces at beginning").grid(column=1, row=6, sticky=E) self.__settings["skipinitialspace"] = BooleanVar() self.__settings["skipinitialspace"].set(False) Checkbutton(fileformatsettingsframe, variable=self.__settings["skipinitialspace"], command=self.update_settings).grid(column=2, row=6, sticky=W, padx=10) fileformatsettingsframe.pack(fill=X) # ***---*** preview frame ***---*** previewframe = LabelFrame(self.__root, text="Preview") self.__pdtable = Table(parent=previewframe, dataframe=self.__importer.dfx) self.__pdtable.show() previewframe.pack(fill="both", expand=True) # ***---*** export button ***---*** exportframe = LabelFrame(self.__root, text="Export") Button(exportframe, text="Export", command=self.create_exportdialog).pack() exportframe.pack(fill="both", expand=True) # save settings to check for changes on update self.__prevsettings = self.__unpack_settings(self.__settings)
def entry_float(parent, lf_text, l_limit, u_limit, mess_text, out_var): """Float layout for entry Parameters ---------- parent : str parent handle lf_text : str text on LabelFrame l_limit : float lower limit u_limit : float upper limit mess_text : str message out_var : float tkvar handle Returns ------- float """ st1 = Style() st1.theme_use('default') st1.configure('brown.TLabelframe', background='#C9B99B') st1.configure('brown.TLabelframe.Label', background='#EDEF77') st1.configure('brown.TLabel', background='#EDEF77') st1.configure('lowr.TLabel', background='lightblue') st1.configure('upr.TLabel', background='red') lf0 = Labelframe(parent, text=lf_text, style='brown.TLabelframe') lf0.grid(row=0, column=0, padx=10, pady=10) ulab = Label(lf0, text=str(u_limit) + " upper limit", style='brown.TLabel') ulab.grid(row=0, column=1, padx=10) llab = Label(lf0, text=str(l_limit) + " lower limit", style='brown.TLabel') llab.grid(row=2, column=1, padx=10) def end_input(_evt): """limit on float Parameters ---------- evt : str bind handle Returns ------- None """ ulab['style'] = 'brown.TLabel' llab['style'] = 'brown.TLabel' if l_limit < entsv.get() < u_limit: messlbl['text'] = "That's OK" out_var.set(entsv.get()) elif l_limit >= entsv.get(): messlbl['text'] = "Input below lower limit" llab['style'] = 'lowr.TLabel' else: messlbl['text'] = "Input above upper limit" ulab['style'] = 'upr.TLabel' def is_okay(text): """ validation function Parameters ---------- text : str text if allowed Returns ------- boolean """ if text in ("", "-", ".", "-."): return True try: float(text) except ValueError: return False return True vcmd = lf0.register(is_okay) entsv = DoubleVar() ent0 = Entry(lf0, validate='key', validatecommand=(vcmd, '%P'), textvariable=entsv) ent0.bind("<Return>", end_input) ent0.grid(row=1, column=0, padx=10) ent0.focus() messlbl = Label(lf0, text=mess_text, style='brown.TLabel') messlbl.grid(row=2, column=0, pady=10, padx=10)
class Sticky(Toplevel): """ Sticky note class """ def __init__(self, master, key, **kwargs): """ Create a new sticky note. master: main app key: key identifying this note in master.note_data kwargs: dictionnary of the other arguments (title, txt, category, color, tags, geometry, locked, checkboxes, images, rolled) """ Toplevel.__init__(self, master) # --- window properties self.id = key self.is_locked = not (kwargs.get("locked", False)) self.images = [] self.links = {} self.latex = {} self.nb_links = 0 self.title('mynotes%s' % key) self.attributes("-type", "splash") self.attributes("-alpha", CONFIG.getint("General", "opacity") / 100) self.focus_force() # window geometry self.update_idletasks() self.geometry(kwargs.get("geometry", '220x235')) self.save_geometry = kwargs.get("geometry", '220x235') self.update() self.rowconfigure(1, weight=1) self.minsize(10, 10) self.protocol("WM_DELETE_WINDOW", self.hide) # --- style self.style = Style(self) self.style.configure(self.id + ".TCheckbutton", selectbackground="red") self.style.map('TEntry', selectbackground=[('!focus', '#c3c3c3')]) selectbg = self.style.lookup('TEntry', 'selectbackground', ('focus', )) self.style.configure("sel.TCheckbutton", background=selectbg) self.style.map("sel.TCheckbutton", background=[("active", selectbg)]) # --- note elements # title font_title = "%s %s" % (CONFIG.get("Font", "title_family").replace( " ", "\ "), CONFIG.get("Font", "title_size")) style = CONFIG.get("Font", "title_style").split(",") if style: font_title += " " font_title += " ".join(style) self.title_var = StringVar(master=self, value=kwargs.get("title", _("Title"))) self.title_label = Label(self, textvariable=self.title_var, anchor="center", style=self.id + ".TLabel", font=font_title) self.title_entry = Entry(self, textvariable=self.title_var, exportselection=False, justify="center", font=font_title) # buttons/icons self.roll = Label(self, image="img_roll", style=self.id + ".TLabel") self.close = Label(self, image="img_close", style=self.id + ".TLabel") self.im_lock = PhotoImage(master=self, file=IM_LOCK) self.cadenas = Label(self, style=self.id + ".TLabel") # corner grip self.corner = Sizegrip(self, style=self.id + ".TSizegrip") # texte font_text = "%s %s" % (CONFIG.get("Font", "text_family").replace( " ", "\ "), CONFIG.get("Font", "text_size")) self.txt = Text(self, wrap='word', undo=True, selectforeground='white', inactiveselectbackground=selectbg, selectbackground=selectbg, tabs=(10, 'right', 21, 'left'), relief="flat", borderwidth=0, highlightthickness=0, font=font_text) # tags self.txt.tag_configure("bold", font="%s bold" % font_text) self.txt.tag_configure("italic", font="%s italic" % font_text) self.txt.tag_configure("bold-italic", font="%s bold italic" % font_text) self.txt.tag_configure("underline", underline=True, selectforeground="white") self.txt.tag_configure("overstrike", overstrike=True, selectforeground="white") self.txt.tag_configure("center", justify="center") self.txt.tag_configure("left", justify="left") self.txt.tag_configure("right", justify="right") self.txt.tag_configure("link", foreground="blue", underline=True, selectforeground="white") self.txt.tag_configure("list", lmargin1=0, lmargin2=21, tabs=(10, 'right', 21, 'left')) self.txt.tag_configure("todolist", lmargin1=0, lmargin2=21, tabs=(10, 'right', 21, 'left')) margin = 2 * Font(self, font=font_text).measure("m") self.txt.tag_configure("enum", lmargin1=0, lmargin2=margin + 5, tabs=(margin, 'right', margin + 5, 'left')) for coul in TEXT_COLORS.values(): self.txt.tag_configure(coul, foreground=coul, selectforeground="white") self.txt.tag_configure(coul + "-underline", foreground=coul, selectforeground="white", underline=True) self.txt.tag_configure(coul + "-overstrike", foreground=coul, overstrike=True, selectforeground="white") # --- menus # --- * menu on title self.menu = Menu(self, tearoff=False) # note color menu_note_color = Menu(self.menu, tearoff=False) colors = list(COLORS.keys()) colors.sort() for coul in colors: menu_note_color.add_command( label=coul, command=lambda key=coul: self.change_color(key)) # category self.category = StringVar( self, kwargs.get("category", CONFIG.get("General", "default_category"))) self.menu_categories = Menu(self.menu, tearoff=False) categories = CONFIG.options("Categories") categories.sort() for cat in categories: self.menu_categories.add_radiobutton(label=cat.capitalize(), value=cat, variable=self.category, command=self.change_category) # position: normal, always above, always below self.position = StringVar( self, kwargs.get("position", CONFIG.get("General", "position"))) menu_position = Menu(self.menu, tearoff=False) menu_position.add_radiobutton(label=_("Always above"), value="above", variable=self.position, command=self.set_position_above) menu_position.add_radiobutton(label=_("Always below"), value="below", variable=self.position, command=self.set_position_below) menu_position.add_radiobutton(label=_("Normal"), value="normal", variable=self.position, command=self.set_position_normal) # mode: note, list, todo list menu_mode = Menu(self.menu, tearoff=False) self.mode = StringVar(self, kwargs.get("mode", "note")) menu_mode.add_radiobutton(label=_("Note"), value="note", variable=self.mode, command=self.set_mode_note) menu_mode.add_radiobutton(label=_("List"), value="list", variable=self.mode, command=self.set_mode_list) menu_mode.add_radiobutton(label=_("ToDo List"), value="todolist", variable=self.mode, command=self.set_mode_todolist) menu_mode.add_radiobutton(label=_("Enumeration"), value="enum", variable=self.mode, command=self.set_mode_enum) self.menu.add_command(label=_("Delete"), command=self.delete) self.menu.add_cascade(label=_("Category"), menu=self.menu_categories) self.menu.add_cascade(label=_("Color"), menu=menu_note_color) self.menu.add_command(label=_("Lock"), command=self.lock) self.menu.add_cascade(label=_("Position"), menu=menu_position) self.menu.add_cascade(label=_("Mode"), menu=menu_mode) # --- * menu on main text self.menu_txt = Menu(self.txt, tearoff=False) # style menu_style = Menu(self.menu_txt, tearoff=False) menu_style.add_command(label=_("Bold"), command=lambda: self.toggle_text_style("bold")) menu_style.add_command( label=_("Italic"), command=lambda: self.toggle_text_style("italic")) menu_style.add_command(label=_("Underline"), command=self.toggle_underline) menu_style.add_command(label=_("Overstrike"), command=self.toggle_overstrike) # text alignment menu_align = Menu(self.menu_txt, tearoff=False) menu_align.add_command(label=_("Left"), command=lambda: self.set_align("left")) menu_align.add_command(label=_("Right"), command=lambda: self.set_align("right")) menu_align.add_command(label=_("Center"), command=lambda: self.set_align("center")) # text color menu_colors = Menu(self.menu_txt, tearoff=False) colors = list(TEXT_COLORS.keys()) colors.sort() for coul in colors: menu_colors.add_command(label=coul, command=lambda key=coul: self. change_sel_color(TEXT_COLORS[key])) # insert menu_insert = Menu(self.menu_txt, tearoff=False) menu_insert.add_command(label=_("Symbols"), command=self.add_symbols) menu_insert.add_command(label=_("Checkbox"), command=self.add_checkbox) menu_insert.add_command(label=_("Image"), command=self.add_image) menu_insert.add_command(label=_("Date"), command=self.add_date) menu_insert.add_command(label=_("Link"), command=self.add_link) if LATEX: menu_insert.add_command(label="LaTex", command=self.add_latex) self.menu_txt.add_cascade(label=_("Style"), menu=menu_style) self.menu_txt.add_cascade(label=_("Alignment"), menu=menu_align) self.menu_txt.add_cascade(label=_("Color"), menu=menu_colors) self.menu_txt.add_cascade(label=_("Insert"), menu=menu_insert) # --- restore note content/appearence self.color = kwargs.get("color", CONFIG.get("Categories", self.category.get())) self.txt.insert('1.0', kwargs.get("txt", "")) self.txt.edit_reset() # clear undo stack # restore inserted objects (images and checkboxes) # we need to restore objects with increasing index to avoid placment errors indexes = list(kwargs.get("inserted_objects", {}).keys()) indexes.sort(key=sorting) for index in indexes: kind, val = kwargs["inserted_objects"][index] if kind == "checkbox": ch = Checkbutton(self.txt, takefocus=False, style=self.id + ".TCheckbutton") if val: ch.state(("selected", )) self.txt.window_create(index, window=ch) elif kind == "image": if os.path.exists(val): self.images.append(PhotoImage(master=self.txt, file=val)) self.txt.image_create(index, image=self.images[-1], name=val) # restore tags for tag, indices in kwargs.get("tags", {}).items(): if indices: self.txt.tag_add(tag, *indices) for link in kwargs.get("links", {}).values(): self.nb_links += 1 self.links[self.nb_links] = link self.txt.tag_bind("link#%i" % self.nb_links, "<Button-1>", lambda e, l=link: open_url(l)) for img, latex in kwargs.get("latex", {}).items(): self.latex[img] = latex if LATEX: self.txt.tag_bind(img, '<Double-Button-1>', lambda e, im=img: self.add_latex(im)) mode = self.mode.get() if mode != "note": self.txt.tag_add(mode, "1.0", "end") self.txt.focus_set() self.lock() if kwargs.get("rolled", False): self.rollnote() if self.position.get() == "above": self.set_position_above() elif self.position.get() == "below": self.set_position_below() # --- placement # titlebar if CONFIG.get("General", "buttons_position") == "right": # right = lock icon - title - roll - close self.columnconfigure(1, weight=1) self.roll.grid(row=0, column=2, sticky="e") self.close.grid(row=0, column=3, sticky="e", padx=(0, 2)) self.cadenas.grid(row=0, column=0, sticky="w") self.title_label.grid(row=0, column=1, sticky="ew", pady=(1, 0)) else: # left = close - roll - title - lock icon self.columnconfigure(2, weight=1) self.roll.grid(row=0, column=1, sticky="w") self.close.grid(row=0, column=0, sticky="w", padx=(2, 0)) self.cadenas.grid(row=0, column=3, sticky="e") self.title_label.grid(row=0, column=2, sticky="ew", pady=(1, 0)) # body self.txt.grid(row=1, columnspan=4, column=0, sticky="ewsn", pady=(1, 4), padx=4) self.corner.lift(self.txt) self.corner.place(relx=1.0, rely=1.0, anchor="se") # --- bindings self.bind("<FocusOut>", self.save_note) self.bind('<Configure>', self.bouge) self.bind('<Button-1>', self.change_focus, True) self.close.bind("<Button-1>", self.hide) self.close.bind("<Enter>", self.enter_close) self.close.bind("<Leave>", self.leave_close) self.roll.bind("<Button-1>", self.rollnote) self.roll.bind("<Enter>", self.enter_roll) self.roll.bind("<Leave >", self.leave_roll) self.title_label.bind("<Double-Button-1>", self.edit_title) self.title_label.bind("<ButtonPress-1>", self.start_move) self.title_label.bind("<ButtonRelease-1>", self.stop_move) self.title_label.bind("<B1-Motion>", self.move) self.title_label.bind('<Button-3>', self.show_menu) self.title_entry.bind("<Return>", lambda e: self.title_entry.place_forget()) self.title_entry.bind("<FocusOut>", lambda e: self.title_entry.place_forget()) self.title_entry.bind("<Escape>", lambda e: self.title_entry.place_forget()) self.txt.tag_bind("link", "<Enter>", lambda event: self.txt.configure(cursor="hand1")) self.txt.tag_bind("link", "<Leave>", lambda event: self.txt.configure(cursor="")) self.txt.bind("<FocusOut>", self.save_note) self.txt.bind('<Button-3>', self.show_menu_txt) # add binding to the existing class binding so that the selected text # is erased on pasting self.txt.bind("<Control-v>", self.paste) self.corner.bind('<ButtonRelease-1>', self.resize) # --- keyboard shortcuts self.txt.bind('<Control-b>', lambda e: self.toggle_text_style('bold')) self.txt.bind('<Control-i>', lambda e: self.toggle_text_style('italic')) self.txt.bind('<Control-u>', lambda e: self.toggle_underline()) self.txt.bind('<Control-r>', lambda e: self.set_align('right')) self.txt.bind('<Control-l>', lambda e: self.set_align('left')) def __setattr__(self, name, value): object.__setattr__(self, name, value) if name == "color": self.style.configure(self.id + ".TSizegrip", background=self.color) self.style.configure(self.id + ".TLabel", background=self.color) self.style.configure("close" + self.id + ".TLabel", background=self.color) self.style.configure("roll" + self.id + ".TLabel", background=self.color) self.style.map(self.id + ".TLabel", background=[("active", self.color)]) self.style.configure(self.id + ".TCheckbutton", background=self.color) self.style.map(self.id + ".TCheckbutton", background=[("active", self.color), ("disabled", self.color)]) self.style.map("close" + self.id + ".TLabel", background=[("active", self.color)]) self.style.map("roll" + self.id + ".TLabel", background=[("active", self.color)]) self.configure(bg=self.color) self.txt.configure(bg=self.color) def paste(self, event): """ delete selected text before pasting """ if self.txt.tag_ranges("sel"): self.txt.delete("sel.first", "sel.last") def delete(self, confirmation=True): """ Delete this note """ if confirmation: rep = askokcancel(_("Confirmation"), _("Delete the note?")) else: rep = True if rep: del (self.master.note_data[self.id]) del (self.master.notes[self.id]) self.master.save() self.destroy() def lock(self): """ Put note in read-only mode to avoid unwanted text insertion """ if self.is_locked: selectbg = self.style.lookup('TEntry', 'selectbackground', ('focus', )) self.txt.configure(state="normal", selectforeground='white', selectbackground=selectbg, inactiveselectbackground=selectbg) self.style.configure("sel.TCheckbutton", background=selectbg) self.style.map("sel.TCheckbutton", background=[("active", selectbg)]) self.is_locked = False for checkbox in self.txt.window_names(): ch = self.txt.children[checkbox.split(".")[-1]] ch.configure(state="normal") self.cadenas.configure(image="") self.menu.entryconfigure(3, label=_("Lock")) self.title_label.bind("<Double-Button-1>", self.edit_title) self.txt.bind('<Button-3>', self.show_menu_txt) else: self.txt.configure(state="disabled", selectforeground='black', inactiveselectbackground='#c3c3c3', selectbackground='#c3c3c3') self.style.configure("sel.TCheckbutton", background='#c3c3c3') self.style.map("sel.TCheckbutton", background=[("active", '#c3c3c3')]) self.cadenas.configure(image=self.im_lock) for checkbox in self.txt.window_names(): ch = self.txt.children[checkbox.split(".")[-1]] ch.configure(state="disabled") self.is_locked = True self.menu.entryconfigure(3, label=_("Unlock")) self.title_label.unbind("<Double-Button-1>") self.txt.unbind('<Button-3>') self.save_note() def save_info(self): """ Return the dictionnary containing all the note data """ data = {} data["txt"] = self.txt.get("1.0", "end")[:-1] data["tags"] = {} for tag in self.txt.tag_names(): if tag not in ["sel", "todolist", "list", "enum"]: data["tags"][tag] = [ index.string for index in self.txt.tag_ranges(tag) ] data["title"] = self.title_var.get() data["geometry"] = self.save_geometry data["category"] = self.category.get() data["color"] = self.color data["locked"] = self.is_locked data["mode"] = self.mode.get() data["inserted_objects"] = {} data["rolled"] = not self.txt.winfo_ismapped() data["position"] = self.position.get() data["links"] = {} for i, link in self.links.items(): if self.txt.tag_ranges("link#%i" % i): data["links"][i] = link data["latex"] = {} for img, latex in self.latex.items(): if self.txt.tag_ranges(img): data["latex"][img] = latex for image in self.txt.image_names(): data["inserted_objects"][self.txt.index(image)] = ( "image", image.split('#')[0]) for checkbox in self.txt.window_names(): ch = self.txt.children[checkbox.split(".")[-1]] data["inserted_objects"][self.txt.index(checkbox)] = ( "checkbox", "selected" in ch.state()) return data def change_color(self, key): self.color = COLORS[key] self.save_note() def change_category(self, category=None): if category: self.category.set(category) self.color = CONFIG.get("Categories", self.category.get()) self.save_note() def set_position_above(self): e = ewmh.EWMH() for w in e.getClientList(): if w.get_wm_name() == 'mynotes%s' % self.id: e.setWmState(w, 1, '_NET_WM_STATE_ABOVE') e.setWmState(w, 0, '_NET_WM_STATE_BELOW') e.display.flush() self.save_note() def set_position_below(self): e = ewmh.EWMH() for w in e.getClientList(): if w.get_wm_name() == 'mynotes%s' % self.id: e.setWmState(w, 0, '_NET_WM_STATE_ABOVE') e.setWmState(w, 1, '_NET_WM_STATE_BELOW') e.display.flush() self.save_note() def set_position_normal(self): e = ewmh.EWMH() for w in e.getClientList(): if w.get_wm_name() == 'mynotes%s' % self.id: e.setWmState(w, 0, '_NET_WM_STATE_BELOW') e.setWmState(w, 0, '_NET_WM_STATE_ABOVE') e.display.flush() self.save_note() def set_mode_note(self): self.txt.tag_remove("list", "1.0", "end") self.txt.tag_remove("todolist", "1.0", "end") self.txt.tag_remove("enum", "1.0", "end") self.save_note() def set_mode_list(self): end = int(self.txt.index("end").split(".")[0]) lines = self.txt.get("1.0", "end").splitlines() for i, l in zip(range(1, end), lines): # remove checkboxes try: ch = self.txt.window_cget("%i.0" % i, "window") self.txt.children[ch.split('.')[-1]].destroy() self.txt.delete("%i.0" % i) except TclError: # there is no checkbox # remove enumeration res = re.match('^\t[0-9]+\.\t', l) if res: self.txt.delete("%i.0" % i, "%i.%i" % (i, res.end())) if self.txt.get("%i.0" % i, "%i.3" % i) != "\t•\t": self.txt.insert("%i.0" % i, "\t•\t") self.txt.tag_add("list", "1.0", "end") self.txt.tag_remove("todolist", "1.0", "end") self.txt.tag_remove("enum", "1.0", "end") self.save_note() def set_mode_enum(self): self.txt.configure(autoseparators=False) self.txt.edit_separator() end = int(self.txt.index("end").split(".")[0]) lines = self.txt.get("1.0", "end").splitlines() for i, l in zip(range(1, end), lines): # remove checkboxes try: ch = self.txt.window_cget("%i.0" % i, "window") self.txt.children[ch.split('.')[-1]].destroy() self.txt.delete("%i.0" % i) except TclError: # there is no checkbox # remove bullets if self.txt.get("%i.0" % i, "%i.3" % i) == "\t•\t": self.txt.delete("%i.0" % i, "%i.3" % i) if not re.match('^\t[0-9]+\.', l): self.txt.insert("%i.0" % i, "\t0.\t") self.txt.tag_add("enum", "1.0", "end") self.txt.tag_remove("todolist", "1.0", "end") self.txt.tag_remove("list", "1.0", "end") self.update_enum() self.txt.configure(autoseparators=True) self.txt.edit_separator() self.save_note() def set_mode_todolist(self): end = int(self.txt.index("end").split(".")[0]) lines = self.txt.get("1.0", "end").splitlines() for i, l in zip(range(1, end), lines): res = re.match('^\t[0-9]+\.\t', l) if res: self.txt.delete("%i.0" % i, "%i.%i" % (i, res.end())) elif self.txt.get("%i.0" % i, "%i.3" % i) == "\t•\t": self.txt.delete("%i.0" % i, "%i.3" % i) try: ch = self.txt.window_cget("%i.0" % i, "window") except TclError: ch = Checkbutton(self.txt, takefocus=False, style=self.id + ".TCheckbutton") self.txt.window_create("%i.0" % i, window=ch) self.txt.tag_remove("enum", "1.0", "end") self.txt.tag_remove("list", "1.0", "end") self.txt.tag_add("todolist", "1.0", "end") self.save_note() # --- bindings def enter_roll(self, event): """ mouse is over the roll icon """ self.roll.configure(image="img_rollactive") def leave_roll(self, event): """ mouse leaves the roll icon """ self.roll.configure(image="img_roll") def enter_close(self, event): """ mouse is over the close icon """ self.close.configure(image="img_closeactive") def leave_close(self, event): """ mouse leaves the close icon """ self.close.configure(image="img_close") def change_focus(self, event): if not self.is_locked: event.widget.focus_force() def show_menu(self, event): self.menu.tk_popup(event.x_root, event.y_root) def show_menu_txt(self, event): self.menu_txt.tk_popup(event.x_root, event.y_root) def resize(self, event): self.save_geometry = self.geometry() def bouge(self, event): geo = self.geometry().split("+")[1:] self.save_geometry = self.save_geometry.split("+")[0] \ + "+%s+%s" % tuple(geo) def edit_title(self, event): self.title_entry.place(x=self.title_label.winfo_x() + 5, y=self.title_label.winfo_y(), anchor="nw", width=self.title_label.winfo_width() - 10) def start_move(self, event): self.x = event.x self.y = event.y self.configure(cursor='fleur') def stop_move(self, event): self.x = None self.y = None self.configure(cursor='') def move(self, event): if self.x is not None and self.y is not None: deltax = event.x - self.x deltay = event.y - self.y x = self.winfo_x() + deltax y = self.winfo_y() + deltay self.geometry("+%s+%s" % (x, y)) def save_note(self, event=None): data = self.save_info() data["visible"] = True self.master.note_data[self.id] = data self.master.save() def rollnote(self, event=None): if self.txt.winfo_ismapped(): self.txt.grid_forget() self.corner.place_forget() self.geometry("%sx22" % self.winfo_width()) else: self.txt.grid(row=1, columnspan=4, column=0, sticky="ewsn", pady=(1, 4), padx=4) self.corner.place(relx=1.0, rely=1.0, anchor="se") self.geometry(self.save_geometry) self.save_note() def hide(self, event=None): """ Hide note (can be displayed again via app menu) """ cat = self.category.get() self.master.add_note_to_menu(self.id, self.title_var.get().strip(), cat) data = self.save_info() data["visible"] = False self.master.note_data[self.id] = data del (self.master.notes[self.id]) self.master.save() self.destroy() # --- Settings update def update_title_font(self): font = "%s %s" % (CONFIG.get("Font", "title_family").replace( " ", "\ "), CONFIG.get("Font", "title_size")) style = CONFIG.get("Font", "title_style").split(",") if style: font += " " font += " ".join(style) self.title_label.configure(font=font) def update_text_font(self): font = "%s %s" % (CONFIG.get("Font", "text_family").replace( " ", "\ "), CONFIG.get("Font", "text_size")) self.txt.configure(font=font) self.txt.tag_configure("bold", font="%s bold" % font) self.txt.tag_configure("italic", font="%s italic" % font) self.txt.tag_configure("bold-italic", font="%s bold italic" % font) margin = 2 * Font(self, font=font).measure("m") self.txt.tag_configure("enum", lmargin1=0, lmargin2=margin + 5, tabs=(margin, 'right', margin + 5, 'left')) def update_menu_cat(self, categories): """ Update the category submenu """ self.menu_categories.delete(0, "end") for cat in categories: self.menu_categories.add_radiobutton(label=cat.capitalize(), value=cat, variable=self.category, command=self.change_category) def update_titlebar(self): if CONFIG.get("General", "buttons_position") == "right": # right = lock icon - title - roll - close self.columnconfigure(1, weight=1) self.columnconfigure(2, weight=0) self.roll.grid_configure(row=0, column=2, sticky="e") self.close.grid_configure(row=0, column=3, sticky="e", padx=(0, 2)) self.cadenas.grid_configure(row=0, column=0, sticky="w") self.title_label.grid_configure(row=0, column=1, sticky="ew", pady=(1, 0)) else: # left = close - roll - title - lock icon self.columnconfigure(2, weight=1) self.columnconfigure(1, weight=0) self.roll.grid_configure(row=0, column=1, sticky="w") self.close.grid_configure(row=0, column=0, sticky="w", padx=(2, 0)) self.cadenas.grid_configure(row=0, column=3, sticky="e") self.title_label.grid_configure(row=0, column=2, sticky="ew", pady=(1, 0)) # --- Text edition def add_link(self): def ok(eveny=None): lien = link.get() txt = text.get() if lien: if not txt: txt = lien self.nb_links += 1 if self.txt.tag_ranges("sel"): index = self.txt.index("sel.first") self.txt.delete('sel.first', 'sel.last') else: index = "current" tags = self.txt.tag_names(index) + ("link", "link#%i" % self.nb_links) self.txt.insert("current", txt, tags) if not lien[:4] == "http": lien = "http://" + lien self.links[self.nb_links] = lien self.txt.tag_bind("link#%i" % self.nb_links, "<Button-1>", lambda e: open_url(lien)) top.destroy() top = Toplevel(self) top.transient(self) top.update_idletasks() top.geometry("+%i+%i" % top.winfo_pointerxy()) top.grab_set() top.resizable(True, False) top.title(_("Link")) top.columnconfigure(1, weight=1) text = Entry(top) link = Entry(top) if self.txt.tag_ranges('sel'): txt = self.txt.get('sel.first', 'sel.last') else: txt = '' text.insert(0, txt) text.icursor("end") Label(top, text=_("Text")).grid(row=0, column=0, sticky="e", padx=4, pady=4) Label(top, text=_("Link")).grid(row=1, column=0, sticky="e", padx=4, pady=4) text.grid(row=0, column=1, sticky="ew", padx=4, pady=4) link.grid(row=1, column=1, sticky="ew", padx=4, pady=4) Button(top, text="Ok", command=ok).grid(row=2, columnspan=2, padx=4, pady=4) text.focus_set() text.bind("<Return>", ok) link.bind("<Return>", ok) def add_checkbox(self): ch = Checkbutton(self.txt, takefocus=False, style=self.id + ".TCheckbutton") self.txt.window_create("current", window=ch) def add_date(self): self.txt.insert("current", strftime("%x")) def add_latex(self, img_name=None): def ok(event): latex = r'%s' % text.get() if latex: if img_name is None: l = [ int(os.path.splitext(f)[0]) for f in os.listdir(PATH_LATEX) ] l.sort() if l: i = l[-1] + 1 else: i = 0 img = "%i.png" % i self.txt.tag_bind(img, '<Double-Button-1>', lambda e: self.add_latex(img)) self.latex[img] = latex else: img = img_name im = os.path.join(PATH_LATEX, img) try: math_to_image(latex, im, fontsize=CONFIG.getint("Font", "text_size") - 2) self.images.append(PhotoImage(file=im, master=self)) if self.txt.tag_ranges("sel"): index = self.txt.index("sel.first") self.txt.delete('sel.first', 'sel.last') else: index = self.txt.index("current") self.txt.image_create(index, image=self.images[-1], name=im) self.txt.tag_add(img, index) top.destroy() except Exception as e: showerror(_("Error"), str(e)) top = Toplevel(self) top.transient(self) top.update_idletasks() top.geometry("+%i+%i" % top.winfo_pointerxy()) top.grab_set() top.resizable(True, False) top.title("LaTex") text = Entry(top, justify='center') if img_name is not None: text.insert(0, self.latex[img_name]) else: if self.txt.tag_ranges('sel'): text.insert(0, self.txt.get('sel.first', 'sel.last')) else: text.insert(0, '$$') text.icursor(1) text.pack(fill='x', expand=True) text.bind('<Return>', ok) text.focus_set() def add_image(self): fichier = askopenfilename(defaultextension=".png", filetypes=[("PNG", "*.png")], initialdir="", initialfile="", title=_('Select PNG image')) if os.path.exists(fichier): self.images.append(PhotoImage(master=self.txt, file=fichier)) self.txt.image_create("current", image=self.images[-1], name=fichier) elif fichier: showerror("Erreur", "L'image %s n'existe pas" % fichier) def add_symbols(self): symbols = pick_symbol( self, CONFIG.get("Font", "text_family").replace(" ", "\ "), CONFIG.get("General", "symbols")) self.txt.insert("current", symbols) def toggle_text_style(self, style): '''Toggle the style of the selected text''' if self.txt.tag_ranges("sel"): current_tags = self.txt.tag_names("sel.first") if style in current_tags: # first char is in style so 'unstyle' the range self.txt.tag_remove(style, "sel.first", "sel.last") elif style == "bold" and "bold-italic" in current_tags: self.txt.tag_remove("bold-italic", "sel.first", "sel.last") self.txt.tag_add("italic", "sel.first", "sel.last") elif style == "italic" and "bold-italic" in current_tags: self.txt.tag_remove("bold-italic", "sel.first", "sel.last") self.txt.tag_add("bold", "sel.first", "sel.last") elif style == "bold" and "italic" in current_tags: self.txt.tag_remove("italic", "sel.first", "sel.last") self.txt.tag_add("bold-italic", "sel.first", "sel.last") elif style == "italic" and "bold" in current_tags: self.txt.tag_remove("bold", "sel.first", "sel.last") self.txt.tag_add("bold-italic", "sel.first", "sel.last") else: # first char is normal, so apply style to the whole selection self.txt.tag_add(style, "sel.first", "sel.last") def toggle_underline(self): if self.txt.tag_ranges("sel"): current_tags = self.txt.tag_names("sel.first") if "underline" in current_tags: # first char is in style so 'unstyle' the range self.txt.tag_remove("underline", "sel.first", "sel.last") for coul in TEXT_COLORS.values(): self.txt.tag_remove(coul + "-underline", "sel.first", "sel.last") else: self.txt.tag_add("underline", "sel.first", "sel.last") for coul in TEXT_COLORS.values(): r = text_ranges(self.txt, coul, "sel.first", "sel.last") if r: for deb, fin in zip(r[::2], r[1::2]): self.txt.tag_add(coul + "-underline", "sel.first", "sel.last") def toggle_overstrike(self): if self.txt.tag_ranges("sel"): current_tags = self.txt.tag_names("sel.first") if "overstrike" in current_tags: # first char is in style so 'unstyle' the range self.txt.tag_remove("overstrike", "sel.first", "sel.last") for coul in TEXT_COLORS.values(): self.txt.tag_remove(coul + "-overstrike", "sel.first", "sel.last") else: self.txt.tag_add("overstrike", "sel.first", "sel.last") for coul in TEXT_COLORS.values(): r = text_ranges(self.txt, coul, "sel.first", "sel.last") if r: for deb, fin in zip(r[::2], r[1::2]): self.txt.tag_add(coul + "-overstrike", "sel.first", "sel.last") def change_sel_color(self, color): """ change the color of the selection """ if self.txt.tag_ranges("sel"): for coul in TEXT_COLORS.values(): self.txt.tag_remove(coul, "sel.first", "sel.last") self.txt.tag_remove(coul + "-overstrike", "sel.first", "sel.last") self.txt.tag_remove(coul + "-underline", "sel.first", "sel.last") if not color == "black": self.txt.tag_add(color, "sel.first", "sel.last") underline = text_ranges(self.txt, "underline", "sel.first", "sel.last") overstrike = text_ranges(self.txt, "overstrike", "sel.first", "sel.last") for deb, fin in zip(underline[::2], underline[1::2]): self.txt.tag_add(color + "-underline", deb, fin) for deb, fin in zip(overstrike[::2], overstrike[1::2]): self.txt.tag_add(color + "-overstrike", deb, fin) def set_align(self, alignment): """ Align the text according to alignment (left, right, center) """ if self.txt.tag_ranges("sel"): line = self.txt.index("sel.first").split(".")[0] line2 = self.txt.index("sel.last").split(".")[0] deb, fin = line + ".0", line2 + ".end" if not "\t" in self.txt.get(deb, fin): # tabulations don't support right/center alignment # remove old alignment tag self.txt.tag_remove("left", deb, fin) self.txt.tag_remove("right", deb, fin) self.txt.tag_remove("center", deb, fin) # set new alignment tag self.txt.tag_add(alignment, deb, fin) def update_enum(self): """ update enumeration numbers """ lines = self.txt.get("1.0", "end").splitlines() indexes = [] for i, l in enumerate(lines): res = re.match('^\t[0-9]+\.\t', l) res2 = re.match('^\t[0-9]+\.', l) if res: indexes.append((i, res.end())) elif res2: indexes.append((i, res2.end())) for j, (i, end) in enumerate(indexes): self.txt.delete("%i.0" % (i + 1), "%i.%i" % (i + 1, end)) self.txt.insert("%i.0" % (i + 1), "\t%i.\t" % (j + 1)) self.txt.tag_add("enum", "1.0", "end")
class Register(Frame): def __init__(self, master): super().__init__(master=master) self.layout_components() # Setup Callbacks self.show_sign_in: Callable = None self.sign_in: Callable = None self.search_email: Callable = None self.search_username: Callable = None self.search_password: Callable = None self.register: Callable = None self.username_valid: bool = False self.email_valid: bool = False self.password_valid: bool = False self.passcnfm_valid: bool = False # Refocus to Email Entry self.email_Entry.focus() def layout_components(self): self.pack(fill=tk.BOTH, expand=False, padx=PADX, pady=PADY) error_font = font.Font(family="Ariel", size=8) # Variables self.username = tk.StringVar() self.username.set("") self.email = tk.StringVar() self.email.set("") self.password = tk.StringVar() self.password.set("") self.passcnfm = tk.StringVar() self.passcnfm.set("") # Email Row email_Frame = Frame(self) email_Frame.pack(fill=tk.X) email_Label = Label(email_Frame, text="Email:", width=LABEL_WIDTH) email_Label.pack(side=tk.LEFT, padx=PADX, pady=PADY) self.email_Entry = Entry(email_Frame, width=ENTRY_WIDTH, textvariable=self.email) self.email_Entry.pack(fill=tk.X, padx=PADX, pady=PADY, expand=True) self.email_Entry.bind("<FocusOut>", self._validate_email) # Email Error Row email_errFrame = Frame(self) email_errFrame.pack(fill=tk.X) self.email_errLabel = Label(email_errFrame, text="", foreground="red", font=error_font) self.email_errLabel.pack(side=tk.LEFT, anchor="center", expand=True, padx=PADX, pady=PADY) # Username Row user_Frame = Frame(self) user_Frame.pack(fill=tk.X) user_Label = Label(user_Frame, text="Username:"******"<FocusOut>", self._validate_username) # Username Error Row user_errFrame = Frame(self) user_errFrame.pack(fill=tk.X) self.user_errLabel = Label(user_errFrame, text="", foreground="red", font=error_font) self.user_errLabel.pack(side=tk.LEFT, anchor="center", expand=True, padx=PADX, pady=PADY) # Original Password Row pass_Frame = Frame(self) pass_Frame.pack(fill=tk.X) pass_Label = Label(pass_Frame, text="Password:"******"*") self.pass_Entry.pack(fill=tk.X, padx=PADX, pady=PADY, expand=True) self.pass_Entry.bind("<FocusOut>", self._validate_password) # Confirming Password Row pass_cnfmFrame = Frame(self) pass_cnfmFrame.pack(fill=tk.X) pass_cnfmLabel = Label(pass_cnfmFrame, text="Confirm:", width=LABEL_WIDTH) pass_cnfmLabel.pack(side=tk.LEFT, padx=PADX, pady=PADY) self.pass_cnfmEntry = Entry(pass_cnfmFrame, width=ENTRY_WIDTH, textvariable=self.passcnfm, show="*") self.pass_cnfmEntry.pack(fill=tk.X, padx=PADX, pady=PADY, expand=True) self.pass_cnfmEntry.bind("<FocusOut>", self._validate_password) # Password Error Row pass_errFrame = Frame(self) pass_errFrame.pack(fill=tk.X) self.pass_errLabel = Label(pass_errFrame, text="", foreground="red", font=error_font) self.pass_errLabel.pack(side=tk.LEFT, anchor="center", expand=True, padx=PADX, pady=PADY) # Button Row button_Frame = Frame(self) button_Frame.pack(fill=tk.X) # Cancel Button cncl_Button = Button(button_Frame, text="Cancel", command=self.cancel) cncl_Button.pack(side=tk.RIGHT, padx=PADX, pady=PADY, expand=False) # Register Button self.register_Button = Button(button_Frame, text="Register", state="disabled", command=self._register) self.register_Button.pack(side=tk.RIGHT, padx=PADX, pady=PADY, expand=False) # View Password Button self.view_pass_Button = Button(button_Frame, text="View Password", command=self.view_password) self.view_pass_Button.pack(side=tk.LEFT, padx=PADX, pady=PADY) # Go Back Button Row gbck_Frame = Frame(self) gbck_Frame.pack(fill=tk.X) gbck_Label = Label(gbck_Frame, text="Have an Account? Go Ahead and ") gbck_Label.pack(side=tk.LEFT, padx=PADX, pady=PADY, expand=False) gbck_Button = Button(gbck_Frame, text="Sign In", command=self._show_sign_in) gbck_Button.pack(side=tk.RIGHT, padx=PADX, pady=PADY, expand=False) def cancel(self): self.email.set("") self.username.set("") self.password.set("") self.passcnfm.set("") self.email_Entry.focus() self.email_errLabel.configure(text="") self.user_errLabel.configure(text="") self.pass_errLabel.configure(text="") def view_password(self): self.pass_Entry.configure(show="") self.pass_cnfmEntry.configure(show="") self.view_pass_Button.configure(text="Hide Password", command=self.hide_password) def hide_password(self): self.pass_Entry.configure(show="*") self.pass_cnfmEntry.configure(show="*") self.view_pass_Button.configure(text="View Passwrod", command=self.view_password) def _show_sign_in(self): if self.show_sign_in is not None: self.show_sign_in() self.cancel() def _register(self): if self.register is not None: self.register() def _validate_email(self, event): email = self.email.get() if len(email) == 0: self.email_errLabel.configure(text="Email Must not be Empty...") self.email_valid = False elif not validate_email(email): self.email_errLabel.configure(text="Email Format Invalide...") self.email_valid = False elif self.search_email is not None and not self.search_email(email): self.email_errLabel.configure(text="Email Already Registered...") self.email_valid = False else: self.email_errLabel.configure(text="") self.email_valid = True self.enable_register() def _validate_username(self, event): username = self.username.get() if len(username) == 0: self.user_errLabel.configure(text="Username Must not be Empty...") self.username_valid = False elif self.search_username is not None and not self.search_username( username): self.username_valid = False else: self.user_errLabel.configure(text="") self.username_valid = True self.enable_register() def _validate_password(self, event): password = self.password.get() passcnfm = self.passcnfm.get() if len(password) == 0: self.pass_errLabel.configure(text="Password Must Not be Empty...") self.password_valid = False elif len(password) < 8: self.pass_errLabel.configure( text="Password Must be Longer than 8 Characters...") self.password_valid = False elif password != passcnfm: self.pass_errLabel.configure(text="Password Must Match... ") self.passcnfm_valid = False elif self.search_password is not None and not self.search_password( password): self.pass_errLabel.configure(text="") self.password_valid = False else: self.pass_errLabel.configure(text="") self.passcnfm_valid = True self.password_valid = True self.enable_register() def enable_register(self): if (self.email_valid and self.username_valid and self.password_valid and self.passcnfm_valid): self.register_Button.configure(state="normal") def failed_register(self): self.email.set("") self.username.set("") self.pass_errLabel.configure(text="Email or Username Already used") self.email_Entry.focus()
def add_latex(self, img_name=None): def ok(event): latex = r'%s' % text.get() if latex: if img_name is None: l = [ int(os.path.splitext(f)[0]) for f in os.listdir(PATH_LATEX) ] l.sort() if l: i = l[-1] + 1 else: i = 0 img = "%i.png" % i self.txt.tag_bind(img, '<Double-Button-1>', lambda e: self.add_latex(img)) self.latex[img] = latex else: img = img_name im = os.path.join(PATH_LATEX, img) try: math_to_image(latex, im, fontsize=CONFIG.getint("Font", "text_size") - 2) self.images.append(PhotoImage(file=im, master=self)) if self.txt.tag_ranges("sel"): index = self.txt.index("sel.first") self.txt.delete('sel.first', 'sel.last') else: index = self.txt.index("current") self.txt.image_create(index, image=self.images[-1], name=im) self.txt.tag_add(img, index) top.destroy() except Exception as e: showerror(_("Error"), str(e)) top = Toplevel(self) top.transient(self) top.update_idletasks() top.geometry("+%i+%i" % top.winfo_pointerxy()) top.grab_set() top.resizable(True, False) top.title("LaTex") text = Entry(top, justify='center') if img_name is not None: text.insert(0, self.latex[img_name]) else: if self.txt.tag_ranges('sel'): text.insert(0, self.txt.get('sel.first', 'sel.last')) else: text.insert(0, '$$') text.icursor(1) text.pack(fill='x', expand=True) text.bind('<Return>', ok) text.focus_set()
class Notifier(Frame): def __init__(self, parent): Frame.__init__(self, parent) self.parent = parent self.text_clicked = False self.time_clicked = False self.running = False self.afterv = [] self.max_tries = 5 self.initUI() def initUI(self): # Establish frames self.pack(side="top", fill="both", expand=True) self.top_frame = Frame(self) self.bottom_frame = Frame(self) self.top_frame.pack(side="top", fill="both", expand=False) self.bottom_frame.pack(side="bottom", fill="both", expand=True) self.top_top_frame = Frame(self.top_frame) self.top_top_frame.pack(side="top", fill="both", expand=False) self.bottom_top_frame = Frame(self.top_frame) self.bottom_top_frame.pack(side="bottom", fill="both", expand=False) # Entry combo box self.cboxv = StringVar(self.top_top_frame) self.cbox = Combobox(self.top_top_frame, value=self.cboxv, width=40) self.cbox['values'] = ("all", "FreeGamesOnSteam", "funny", "news") self.cbox.current(0) self.cbox.bind("<Button-1>", self.text_callback) self.cbox.bind("<Tab>", self.time_callback) self.cbox.pack(side="left", padx=10, pady=10, expand=True) # Entry time box self.tentry = Entry(self.top_top_frame, width=8, foreground='gray') self.tentry.bind("<Button-1>", self.time_callback) self.tentry.insert(0, "Time(s)") self.tentry.pack(side="left", padx=10, pady=10, expand=True) # Category drop-down menu self.category = StringVar(self.top_top_frame) self.category.set("hot") # default value self.omenu = OptionMenu(self.top_top_frame, self.category, "hot", "new", "top", "controversial", "rising") self.omenu.pack(side="right", padx=10, pady=10, expand=True) # Limit drop-down menu self.limit = IntVar(self.top_top_frame) self.limit.set(5) # default value self.lmenu = OptionMenu(self.top_top_frame, self.limit, *list(range(10))) self.lmenu.pack(side="right", padx=10, pady=10, expand=True) # Scan button self.scanb = Button(self.bottom_top_frame, text="Scan", command=self.scan_subreddit) self.scanb.pack(side="left", padx=10, pady=10, expand=True) self.parent.bind("<Return>", lambda x: self.scan_subreddit()) # Popup check self.checkvar = BooleanVar() self.check = Checkbutton(self.bottom_top_frame, text="Popup", variable=self.checkvar) self.check.pack(side="left", padx=10, pady=10, expand=True) # Continuous check self.contvar = BooleanVar() self.contb = Checkbutton(self.bottom_top_frame, text="Continuous", variable=self.contvar) self.contb.pack(side="left", padx=10, pady=10, expand=True) # Stop button self.stopb = Button(self.bottom_top_frame, text="Stop", command=self.stop_scanning, state="disabled") self.stopb.pack(side="right", padx=10, pady=10, expand=True) self.parent.bind("<Escape>", lambda x: self.stop_scanning()) # Results text box self.text = CustomText(self.bottom_frame, height=10, width=50) self.text.configure(state="disabled") self.text.pack(side="top", padx=10, pady=10, expand=True, fill="both") def text_callback(self, event=None): if not self.text_clicked: self.cbox.delete(0, "end") self.text_clicked = True def time_callback(self, event=None): if not self.time_clicked: self.tentry.delete(0, "end") self.tentry.config(foreground="black") self.time_clicked = True def scan_subreddit(self): self.running = True self.scanb.config(state="disabled") self.stopb.config(state="normal") self.omenu.config(state="disabled") self.lmenu.config(state="disabled") self.cbox.config(state="disabled") self.tentry.config(state="disabled") self.check.config(state="disabled") self.contb.config(state="disabled") self.parent.unbind("<Return>") # Clean text box self.text.config(state="normal") self.text.delete(1.0, 'end') self.text.config(state="disabled") # Get values from boxes sub_name = self.cbox.get() cat = self.category.get() self.slimit = self.limit.get() self.popup = self.checkvar.get() self.cont = self.contvar.get() try: subreddit = reddit.subreddit(sub_name) except Exception: self.text.tinsert("Error: insert a subreddit" + '\n') self.stop_scanning() return try: self.stime = max(0, int(self.tentry.get())) except Exception: self.text.tinsert("Error: time must be a number" + '\n') self.stop_scanning() return self.text.tinsert("Info: getting " + cat + " posts from /r/" + sub_name + '\n') self.subcat = get_subreddit_cat(subreddit, cat) self.tries = 0 self.done_trying = False self.started_managing = False self.done_managing = False self.submissions = None self.get_results() def stop_scanning(self): self.running = False self.scanb.config(state="normal") self.stopb.config(state="disabled") self.omenu.config(state="normal") self.lmenu.config(state="normal") self.cbox.config(state="normal") self.tentry.config(state="normal") self.check.config(state="normal") self.contb.config(state="normal") self.parent.bind("<Return>", lambda x: self.scan_subreddit()) for a in self.afterv: self.parent.after_cancel(a) del self.afterv[:] def get_results(self): if self.running: now = time.time() if not self.done_trying: if self.tries < self.max_tries: try: self.submissions = [ x for x in self.subcat(limit=self.slimit) if (now - x.created_utc) < self.stime ] self.done_trying = True except Exception: self.text.tinsert("Error: [" + nows() + "] try n. " + str(self.tries + 1) + ", cannot access subreddit" + '\n') self.tries += 1 self.afterv.append( self.parent.after(5000, self.get_results)) else: self.text.tinsert( "Error: [" + nows() + "] couldn't access subreddit. Stopping scan." + '\n') self.stop_scanning() self.done_trying = True self.tries = 0 if self.done_trying: if not self.submissions: if not self.started_managing: self.text.tinsert("Info: [" + nows() + "] no results found" '\n') self.done_managing = True else: if not self.started_managing: self.text.tinsert("Info: [" + nows() + "] " + str(len(self.submissions)) + " results found" '\n') self.started_managing = True s = self.submissions[0] self.text.tinsert("Title: " + convert65536(s.title) + '\n') self.text.tinsert("Url: " + s.url + '\n') self.text.tinsert("Created: " + pretty_date(s) + '\n\n') self.parent.update_idletasks() if self.popup: if sys.platform.startswith('win'): import winsound winsound.PlaySound("media/jamaica.wav", winsound.SND_FILENAME) Dialog(self.parent, s.url, s.title) self.submissions = self.submissions[1:] self.afterv.append( self.parent.after(1000, self.get_results)) if self.done_managing: if self.cont: self.text.tinsert( "Info: [" + nows() + "] continuous mode, will check again in " + str(self.stime) + " seconds\n\n") self.afterv.append( self.parent.after(self.stime * 1000, self.get_results)) self.done_trying = False self.started_managing = False self.done_managing = False else: self.text.tinsert("Info: [" + nows() + "] scanning finished" '\n') self.stop_scanning()