def __init__(self, w: PlaylistControl, *args, **kwargs): self.EMPTY_MENUBTN = _("Select Playlist") #After defined _ by gettext self.playlist = w.playlist self.playlist_control = w super().__init__(w, *args, **kwargs) #___ self.menubtn = Menubutton(self, direction="above", width=13, text=config.general["playlist"]) self.menubtn.pack() self.menu = Menu(self.menubtn, bg=config.colors["BG"], activebackground=config.colors["TV_BG_HOVER"], activeforeground=config.colors["FG"], tearoff=False) self.menu.add_command(label=_("Import Playlist"), command=self._newPlaylist) self.menu.add_separator() for playlist in config.user_config["Playlists"]: #https://stackoverflow.com/questions/11723217/python-lambda-doesnt-remember-argument-in-for-loop func_get_set_playlist = lambda playlist=playlist: self.setPlaylist( playlist) self.menu.add_command(label=playlist, command=func_get_set_playlist) self.menubtn.configure(menu=self.menu)
def mainButtons(self): row = 0 col = 0 self.buttons = [] mb = Menubutton(self.root, text="Select Application") mb.menu = Menu(mb, tearoff=0) mb["menu"] = mb.menu for app in APPLICATIONS: mb.menu.add_radiobutton(label=app, variable=self.appVar, command=self.onSelectApp) mb.grid(row=row, column=col, sticky="NEW") col += 1 self.buttons.append(mb) otherButtons = ( ("Run %12s" % self.appVar.get(), self.runApp), ("load Config", self.loadCfg), ("Save Config", self.saveCfg), ("Save Config as", self.saveCfgAs), ("Quit", self.root.quit), ) for text, command in otherButtons: self.buttons.append(Button(self.root, text=text, command=command)) self.buttons[-1].grid(row=row, column=col, sticky="NEW") col += 1 return len(self.buttons)
def init_gui(self): """ Initializes all widgets for the main screen and calls grid_widgets() to place them """ self.title("exp_check") self.config(bg='black') style = Style() style.configure("TMenubutton", foreground="white", background="black") # setup widgets self.add_button = Button(self, text="Add Food", **widget_options, command=self.add_food) self.delete_button = Button(self, text="Delete Food", **widget_options, command=self.delete_food) self.search_box = Entry(self, **widget_options, insertbackground='white') self.search_box.bind("<Key>", self.search) self.data_display = DataDisplay(widget_options) vals = self.data_manager.get_keylist() vals.insert(0, 'name') menu1 = Menu(tearoff=0) menu1.add('radiobutton', label=vals[0], command=lambda: self.update_data_display(sort_key=vals[0])) menu1.add('radiobutton', label=vals[1], command=lambda: self.update_data_display(sort_key=vals[1])) menu1.add('radiobutton', label=vals[2], command=lambda: self.update_data_display(sort_key=vals[2])) self.sort_menu = Menubutton(self, text='sort by', menu=menu1, style="TMenubutton") search_icon = self.generate_icon_object("./data/search_icon.png", (20, 20)) self.search_label = Label(image=search_icon, **widget_options) self.search_label.image = search_icon # setup message box dialog self.message = Label(self, text='', **widget_options) self.okay_button = Button( self, text=" OK ", **widget_options, command=lambda: self.okay_button_press(self.cur_instance)) self.grid_widgets()
def toc_menu(self, text): "Create table of contents as drop-down menu." toc = Menubutton(self, text='TOC') drop = Menu(toc, tearoff=False) for lbl, dex in text.parser.toc: drop.add_command(label=lbl, command=lambda dex=dex:text.yview(dex)) toc['menu'] = drop return toc
def __init__(self, master, type, aqua=False, label="", **options): self.backend = "tkinter" self.type = type self.master = master self.aqua = aqua if type == "bar": self.children = {} self.menu = _Menu(master=master, tearoff=False, **options) self.master.config(menu=self.menu) elif type == "bar_child": self.menu = _Menu(master=master, tearoff=False, **options) self.master.add_cascade(menu=self.menu, label=label) elif type == "cascade": self.menu = _Menu(master=master, tearoff=False, **options) self.master.add_cascade(menu=self.menu, label=label) elif type == "popup": pass elif type == "menubutton": from tkinter.ttk import Menubutton self.widget = Menubutton(master=master, **options)
def __init__(self, parent, **options): """ créer le Toplevel permettant de modifier les paramètres """ Toplevel.__init__(self, parent, **options) self.grab_set() self.transient(parent) self.title(_("Settings")) self.resizable(0, 0) self.onglets = Notebook(self) self.onglets.grid(row=0,column=0,columnspan=2) self.im_color = PhotoImage(master=self, file=COLOR) self.style = Style(self) self.style.theme_use(STYLE) self.style.configure('title.TLabel', font='CMU\ Sans\ Serif\ Demi\ Condensed 12') self.okfct = self.register(valide_entree_nb) self.nb_task = len(CONFIG.options("Tasks")) # Général (temps, police et langue) self.general = Frame(self.onglets, padding=10) self.general.pack(fill="both", expand=True, padx=10, pady=10) self.onglets.add(self.general, text=_("General")) # Temps Label(self.general, text=_("Times:"), style='title.TLabel').grid(row=0, pady=4, sticky="w") self.time_frame = Frame(self.general) self.time_frame.grid(row=1, sticky="ew") Label(self.time_frame, text=_("Work: ")).grid(row=0, column=0) self.travail = Entry(self.time_frame, width=4, justify='center', validatecommand=(self.okfct, '%d', '%S'), validate='key') self.travail.insert(0, CONFIG.get("Work", "time")) self.travail.grid(row=0, column=1, padx=(0,10)) Label(self.time_frame, text=_("Break: ")).grid(row=0, column=2) self.pause = Entry(self.time_frame, width=4, justify='center', validatecommand=(self.okfct, '%d', '%S'), validate='key') self.pause.insert(0, CONFIG.get("Break", "time")) self.pause.grid(row=0, column=3, padx=(0,10)) Label(self.time_frame, text=_("Rest: ")).grid(row=0, column=4) self.rest = Entry(self.time_frame, width=4, justify='center', validatecommand=(self.okfct, '%d', '%S'), validate='key') self.rest.insert(0, CONFIG.get("Rest", "time")) self.rest.grid(row=0, column=5) Separator(self.general, orient='horizontal').grid(row=2, sticky="ew", pady=10) # Police self.font_frame = Frame(self.general) self.font_frame.grid(row=3, pady=4, sticky="ew") Label(self.font_frame, text=_("Font:"), style='title.TLabel').pack(anchor="n", side="left") self.exemple = Label(self.font_frame, text="02:17", anchor="center", font="%s %i" % (CONFIG.get("General", "font"), CONFIG.getint("General", "fontsize")), relief="groove") self.exemple.pack(side="right") self.font_frame2 = Frame(self.general) self.font_frame2.grid(row=4) Label(self.font_frame2, text=_("Family: ")).grid(row=0, column=0, sticky="e") self.font = Entry(self.font_frame2, justify='center') self.font.insert(0, CONFIG.get("General", "font")) self.font.grid(row=0, column=1, padx=(0,10), sticky="ew") self.font.bind('<FocusOut>', self.actualise_police) self.font.bind('<Key-Return>', self.actualise_police, True) Label(self.font_frame2, text=_("Size: ")).grid(row=0, column=2, sticky="e") self.size = Entry(self.font_frame2, width=4, justify='center', validatecommand=(self.okfct, '%d', '%S'), validate='key') self.size.insert(0, CONFIG.getint("General", "fontsize")) self.size.grid(row=0, column=3, pady=2, sticky="w") self.size.bind('<FocusOut>', self.actualise_police) self.size.bind('<Key-Return>', self.actualise_police, True) Separator(self.general, orient='horizontal').grid(row=5, sticky="ew", pady=10) # Langues self.lang_frame = Frame(self.general) self.lang_frame.grid(row=6, pady=4, sticky="ew") Label(self.lang_frame, text=_("Language:"), style='title.TLabel').pack(side="left") self.lang = StringVar(self.lang_frame, LANGUES[CONFIG.get("General", "language")]) b_lang = Menubutton(self.lang_frame, textvariable=self.lang) menu = Menu(b_lang, tearoff=False) menu.add_radiobutton(label="English", variable=self.lang, value="English", command=self.change_langue) menu.add_radiobutton(label="Français", variable=self.lang, value="Français", command=self.change_langue) b_lang.configure(menu=menu) b_lang.pack(side="right") # Son self.im_son = PhotoImage(master=self, file=SON) self.im_mute = PhotoImage(master=self, file=MUTE) self.son = Frame(self.onglets, padding=10) self.son.pack(fill="both", expand=True, padx=10, pady=10) self.son.columnconfigure(1, weight=1) self.onglets.add(self.son, text=_("Sound")) Label(self.son, text=_("Sound:"), style='title.TLabel').grid(row=0, pady=4, sticky="w") self.mute = BooleanVar(self) self.mute.set(not CONFIG.get("Sound", "mute")) def mute_unmute(): if self.mute.get(): self.mute.set(False) b_son.configure(image=self.im_son) else: self.mute.set(True) b_son.configure(image=self.im_mute) b_son = Button(self.son, command=mute_unmute) mute_unmute() b_son.grid(row=0, column=1, sticky="e", pady=4) self.son_frame = Frame(self.son) self.son_frame.grid(row=1, sticky="ew", columnspan=2) self.bip = Entry(self.son_frame, justify='center') self.bip.insert(0, CONFIG.get("Sound", "beep")) self.bip.pack(side="left", fill="both", expand=True) Button(self.son_frame, text="...", width=2, command=self.choix_son).pack(side="right", padx=(2,0)) if PL[0] != "w": Separator(self.son, orient='horizontal').grid(row=2, columnspan=2, sticky="ew", pady=10) son_frame2 = Frame(self.son) son_frame2.grid(row=3, sticky="ew", columnspan=2) Label(son_frame2, text=_("Audio player: "), style='title.TLabel').pack(side="left") self.player = Entry(son_frame2, justify='center') self.player.insert(0, CONFIG.get("Sound", "player")) self.player.pack(side="right", fill="both", expand=True) # Couleurs self.couleurs = Frame(self.onglets, padding=10) self.couleurs.pack(fill="both", expand=True, padx=10, pady=10) self.onglets.add(self.couleurs, text=_("Colors")) # style des boutons de choix des couleurs self.style.configure("fond_w.TButton", background=CONFIG.get("Work", "bg")) self.style.configure("fond_p.TButton", background=CONFIG.get("Break", "bg")) self.style.configure("fond_r.TButton", background=CONFIG.get("Rest", "bg")) self.style.configure("texte_w.TButton", background=CONFIG.get("Work", "fg")) self.style.configure("texte_p.TButton", background=CONFIG.get("Break", "fg")) self.style.configure("texte_r.TButton", background=CONFIG.get("Rest", "fg")) self.couleurs.grid_columnconfigure(3, weight=3) self.couleurs.grid_rowconfigure(0, weight=1) Label(self.couleurs, text=_("Work: "), style='title.TLabel').grid(row=0, column=0, pady=4, padx=(2,10), sticky="w") Label(self.couleurs, text=_("Background: ")).grid(row=0, column=1, sticky="e", pady=(6,4)) Button(self.couleurs, width=2, command=lambda: self.choix_couleur("fond_w"), style='fond_w.TButton').grid(row=0, column=2, pady=4) Label(self.couleurs, text=_("Text: ")).grid(row=1, column=1, sticky="e") Button(self.couleurs, width=2, command=lambda: self.choix_couleur("texte_w"), style='texte_w.TButton').grid(row=1, column=2, pady=4) Separator(self.couleurs, orient='horizontal').grid(row=2, sticky="ew", pady=10, columnspan=4) Label(self.couleurs, text=_("Break: "), style='title.TLabel').grid(row=3, column=0, pady=4, padx=(2,10), sticky="w") Label(self.couleurs, text=_("Background: ")).grid(row=3, column=1, sticky="e", pady=(6,4)) Button(self.couleurs, width=2, command=lambda: self.choix_couleur("fond_p"), style='fond_p.TButton').grid(row=3, column=2, pady=4) Label(self.couleurs, text=_("Text: ")).grid(row=4, column=1, sticky="e") Button(self.couleurs, width=2, command=lambda: self.choix_couleur("texte_p"), style='texte_p.TButton').grid(row=4, column=2, pady=4) Separator(self.couleurs, orient='horizontal').grid(row=5, sticky="ew", pady=10, columnspan=4) Label(self.couleurs, text=_("Rest: "), style='title.TLabel').grid(row=6, column=0, pady=4, sticky="w", padx=(2,10)) Label(self.couleurs, text=_("Background: ")).grid(row=6, column=1, sticky="e", pady=(6,4)) Button(self.couleurs, width=2, command=lambda: self.choix_couleur("fond_r"), style='fond_r.TButton').grid(row=6, column=2, pady=4) Label(self.couleurs, text=_("Text: ")).grid(row=7, column=1, sticky="e") Button(self.couleurs, width=2, command=lambda: self.choix_couleur("texte_r"), style='texte_r.TButton').grid(row=7, column=2, pady=4) # Stats self.stats = Frame(self.onglets, padding=10) self.stats.pack(fill="both", expand=True, padx=10, pady=10) self.stats.grid_columnconfigure(2, weight=1) self.onglets.add(self.stats, text=_("Statistics")) Label(self.stats, text=_("Statistics:"), style='title.TLabel').grid(row=0, column=0, pady=4, sticky="w") tasks = [t.capitalize() for t in CONFIG.options("Tasks")] cmap = [CONFIG.get("Tasks", task) for task in tasks] for i, coul, task in zip(range(self.nb_task), cmap , tasks): Label(self.stats, text=task).grid(row=i + 1, column=0, sticky="e", padx=4, pady=4) self.style.configure("t%i.TButton" % i, background=coul) Button(self.stats, style="t%i.TButton" % i, width=2, command=lambda j=i: self.coul_stat(j)).grid(row=i + 1, column=1, pady=4) # Validation Button(self, text="Ok", command=self.valide).grid(row=1,column=1, sticky="we") Button(self, text=_("Cancel"), command=self.destroy).grid(row=1,column=0, sticky="we")
class MainWindow(Frame): def __init__(self, master=None): Frame.__init__(self, master) self.grid() self.master.title("Simple Data Modeling") self.createWidgets() self.model_loaded = False self.header_bool = IntVar() # define model types (classification/regression) self.clas_models = { 'Decision Tree Classifier': sklearn.tree.DecisionTreeClassifier, 'Random Forest Classifier': ensemble.RandomForestClassifier, 'Gradient Boosting Classifier': sklearn.ensemble.GradientBoostingClassifier } self.reg_models = { 'Linear Model': sklearn.linear_model.LinearRegression, 'k-Nearest Neighbors Regression': sklearn.neighbors.KNeighborsRegressor, 'Decision Tree Regression': sklearn.tree.DecisionTreeRegressor, 'Gaussian Process Regression': gaussian_process.GaussianProcessRegressor, 'Neural Network': neural_network.MLPRegressor, 'Support Vector Regression': sklearn.svm.SVR, 'XGB Regressor': xgb.XGBRegressor, } # define metric types for evaluation (classification/regression) self.clas_metrics = { "Accuracy Classification Score": metrics.accuracy_score, "Balanced Accuracy": metrics.balanced_accuracy_score, "F1 Score": metrics.f1_score, "Precision": metrics.precision_score, "Recall": metrics.recall_score } self.reg_metrics = { "Mean Absolute Error": metrics.mean_absolute_error, "Mean Squared Error": metrics.mean_squared_error, "R\u00B2 (Coefficient of Determination)": metrics.r2_score } def createWidgets(self): top = self.winfo_toplevel() self.menuBar = Menu(top) top["menu"] = self.menuBar self.subMenu = Menu(self.menuBar, tearoff=0) self.menuBar.add_cascade(label="File", menu=self.subMenu) self.subMenu.add_command(label="New", command=self.readData_createWindow) self.subMenu.add_command(label="Load Model", command=self.laod_model) self.subMenu.add_separator() self.subMenu.add_command(label="Help", command=self.help) self.subMenu.add_command(label="About", command=self.about) self.menuBar.add_command(label="Quit", command=self.master.destroy) def readData_createWindow(self): try: filename = filedialog.askopenfilename() f = open(filename, "rb") self.set_header(self.header_bool) # f = 'http://archive.ics.uci.edu/ml/machine-learning-databases/iris/iris.data' header = self.header_bool.get() == 1 self.data = pd.read_csv(f, header=0 if header else None, sep=',') if not header: self.data.columns = [ 'var' + str(i) for i in range(len(self.data.columns)) ] except AttributeError: pass except Exception as e: return showerror("Error", "Data could not be loaded! Make sure the data is " \ + "formated in a similar way as the sample data: {}.".format(e)) self.cols = self.data.columns self.setUpData() self.bools = [ ] # variables for columns: first axis: which col; second axis: what type height = min(5, self.data.shape[0]) width = len(self.cols) # data frame data_frame = LabelFrame(self.master, text="Data Summary", relief=RIDGE) data_frame.grid(row=0, column=0, columnspan=5, sticky="EWNS", padx=15, pady=7.5) data_size = "Data size is {} kilobytes. " \ .format(np.round(self.data.memory_usage(deep=False).sum() / 1000, 2)) cols_rows = "The number of columns is {} and the number of rows is {}. " \ .format(self.data.shape[1], self.data.shape[0]) miss_data = "The data does have missing values." if self.data.isnull().values.any() \ else "The data does not have missing values." Message(data_frame, text=data_size + cols_rows + miss_data, width=335) \ .grid(row=0, column=0, columnspan=width-1, rowspan=3, sticky='NW') Button(data_frame, text="Data", width=13, command=self.show_data) \ .grid(row=0, column=4, columnspan=1, padx=4, pady=4) Button(data_frame, text="Description", width=13, command=self.show_description) \ .grid(row=1, column=4, columnspan=1, padx=4, pady=0) Button(data_frame, text="Pair Plot", width=13, command=self.pair_plot) \ .grid(row=2, column=4, columnspan=1, padx=4, pady=4) # head frame head_frame = LabelFrame(self.master, text="Head of data", relief=RIDGE) head_frame.grid(row=5, column=0, columnspan=5, sticky="EWNS", padx=15, pady=7.5) for i in range(len(self.cols)): self.bools.append( self.initBools(5, trues=[0, 3] if i < width - 1 else [1, 3])) table = CustomTable(main_window=self, parent=head_frame, dataframe=self.data.head(), editable=False, width=1, height=120) config.apply_options({'fontsize': 10}, table) table.show() # modeling frame model_frame = LabelFrame(self.master, text="Modeling", relief=RIDGE) model_frame.grid(row=height + 11, column=0, columnspan=5, sticky="EWNS", padx=15, pady=7.5) # train / test ratio self.train_test_ratio = 1 / 3 self.train_test_ratio_str = StringVar( self.master, value=str(np.round(self.train_test_ratio, 2))) Button(model_frame, text="Shuffle Data", width=13, command=self.shuffle_data) \ .grid(row=0, column=0, columnspan=1) Button(model_frame, text="TrainTest Ratio", width=13, command=self.set_traintest) \ .grid(row=0, column=2, columnspan=1) Label(model_frame, textvariable=self.train_test_ratio_str) \ .grid(row=0, column=3, columnspan=1, sticky="E") # model selection ttk.Style().configure("TMenubutton", background="#E1E1E1") self.model_btn = Menubutton(model_frame, text="Model", width=9) self.set_model(self.model_btn) self.model_btn.grid(row=1, column=0, columnspan=1, padx=0, pady=4) Button(model_frame, text="Parameters", width=13, command=self.set_model_parameters) \ .grid(row=1, column=1, columnspan=1, padx=0, pady=4) self.metric_btn = Menubutton(model_frame, text="Metric", width=9) self.set_metric(self.metric_btn) self.metric_btn.grid(row=1, column=2, columnspan=1, padx=0, pady=4) # model training self.score = -1 self.score_str = StringVar(self.master, value="") Button(model_frame, text="Train Model", width=13, command=self.startModel) \ .grid(row=1, column=3, columnspan=width-1) Label(model_frame, textvariable=self.score_str) \ .grid(row=3, columnspan=width, sticky='W') # Export Frame export_frame = LabelFrame(self.master, text="Save", relief=RIDGE) export_frame.grid(row=height + 15, column=0, columnspan=5, sticky="EWNS", padx=15, pady=7.5) Button(export_frame, text="Export Data", width=13, command=self.export_data) \ .grid(row=0, column=0, columnspan=1, padx=4, pady=4) Button(export_frame, text="Export Model", width=13, command=self.export_model) \ .grid(row=0, column=1, columnspan=1, padx=0, pady=4) def set_header(self, header_var): """ User selection if data has a header as first row. """ class popupWindow(object): def __init__(self, master): top = self.top = Toplevel(master) top.title('Header') top.attributes("-topmost", True) top.geometry("300x65") top.grid() top.resizable(0, 0) self.e = Checkbutton(top, text="Data contains header", variable=header_var, onvalue=1, offvalue=0) self.e.grid(row=0, column=1, columnspan=1) Button(top, text=' Ok ', command=self.cleanup) \ .grid(row=0, column=2, columnspan=1) top.bind('<Return>', self.cleanup) def cleanup(self, event=None): self.top.destroy() popup = popupWindow(self.master) self.master.wait_window(popup.top) def setUpData(self): self.input_cols = list(np.arange(len(self.cols) - 1)) self.output_cols = [len(self.cols) - 1] self.ignore_cols = [] self.numeric_cols = list(np.arange(len(self.cols))) self.categorical_cols = [] def setColSelection(self, new_btn, col): new_menu = Menu(new_btn, tearoff=0) new_btn["menu"] = new_menu new_menu.add_checkbutton(label="Input", command=self.setIn(col), variable=self.bools[col][0], onvalue=1, offvalue=0) #, #state='disabled' if col < len(self.cols)-1 else 'active') new_menu.add_checkbutton(label="Output", command=self.setOut(col), variable=self.bools[col][1]) new_menu.add_checkbutton(label="Ignore", command=self.setIgnore(col), variable=self.bools[col][2]) new_menu.add_separator() new_menu.add_checkbutton( label="Numeric", command=self.setNum(col), variable=self.bools[col][3]) #, state='disabled') new_menu.add_checkbutton(label="Categorical", command=self.setCat(col), variable=self.bools[col][4]) return new_menu def initBools(self, n, trues=[0, 3]): return [ BooleanVar(self.master, value=True if i in trues else False) for i in range(n) ] ### functions for feature settings ### def setIn(self, col): def _setIn(): if col in self.input_cols: pass else: self.input_cols.append(col) self.input_cols = sorted(self.input_cols) try: del self.output_cols[self.output_cols.index(col)] except: pass try: del self.ignore_cols[self.ignore_cols.index(col)] except: pass self.bools[col][0].set(value=True) self.bools[col][1].set(value=False) self.bools[col][2].set(value=False) return _setIn def setOut(self, col): def _setOut(): if col in self.output_cols: pass else: try: del self.input_cols[self.input_cols.index(col)] except: pass try: del self.ignore_cols[self.ignore_cols.index(col)] except: pass if len(self.output_cols) == 1: self.input_cols.append(self.output_cols[0]) self.bools[self.output_cols[0]][0].set(value=True) self.bools[self.output_cols[0]][1].set(value=False) self.output_cols = [col] self.bools[col][0].set(value=False) self.bools[col][1].set(value=True) self.bools[col][2].set(value=False) return _setOut def setIgnore(self, col): def _setOut(): if col in self.ignore_cols: pass else: self.ignore_cols.append(col) self.ignore_cols = sorted(self.ignore_cols) try: del self.input_cols[self.input_cols.index(col)] except: pass try: del self.output_cols[self.output_cols.index(col)] except: pass self.bools[col][0].set(value=False) self.bools[col][1].set(value=False) self.bools[col][2].set(value=True) return _setOut def setNum(self, col): def _setNum(): if col in self.numeric_cols: pass else: self.numeric_cols.append(col) self.numeric_cols = sorted(self.numeric_cols) try: del self.categorical_cols[self.categorical_cols.index(col)] except: pass self.bools[col][3].set(value=True) self.bools[col][4].set(value=False) return _setNum def setCat(self, col): def _setCat(): # showinfo("Information", "Categorical variables not supported yet!") if col in self.categorical_cols: pass else: self.categorical_cols.append(col) self.categorical_cols = sorted(self.categorical_cols) try: del self.numeric_cols[self.numeric_cols.index(col)] except: pass self.bools[col][3].set(value=False) self.bools[col][4].set(value=True) return _setCat ### ------------------------------ ### def properties(self): pass def help(self): instructions = "Instructions\n" \ + "1) Load your data which is formated as csv file.\n" \ + "2) Make sure loading worked by checking the displayed ´Head of Data´\n" \ + " or pressing the ´Data´ button to see the whole dataset.\n" \ + "3) In the ´Head of Data´ press the column names to change their type" \ + " and to select the output feature.\n" \ + "4) Select your appropriate model and change its parameters if needed.\n" \ + "5) Save your predictions and model.\n" showinfo("Information", instructions) def about(self): showinfo("About", "This Application is for small data modeling tasks.\n\n" \ + "Author\t{}\nVersion\t{}".format(__author__, __version__)) def set_traintest(self): train_test_ratio = self.train_test_ratio_str.get() class popupWindow(object): def __init__(self, master): top = self.top = Toplevel(master) top.title('Train-Test Ratio') top.attributes("-topmost", True) top.geometry("350x80") top.grid() top.resizable(0, 0) Label(top, text="Enter the ratio of training set " \ + "size to test set size:").grid(row=0, columnspan=6, sticky='nesw', padx=15, pady=7.5) self.e = Entry(top) self.e.insert(END, str(train_test_ratio)) self.e.grid(row=1, column=0, columnspan=5, sticky='w', padx=15) Button(top, text=' Ok ', command=self.cleanup) \ .grid(row=1, column=5, columnspan=1, sticky='e', padx=15) top.bind('<Return>', self.cleanup) def cleanup(self, event=None): self.value = self.e.get() self.top.destroy() popup = popupWindow(self.master) self.master.wait_window(popup.top) try: train_test_ratio = float(popup.value) if train_test_ratio > 1 or train_test_ratio <= 0: showerror("Error", "Train-Test ratio must be in (0,1]!") else: self.train_test_ratio = train_test_ratio self.train_test_ratio_str.set( str(np.round(self.train_test_ratio, 2))) except AttributeError: pass except: showerror("Error", "Train-Test ratio must be a value in (0,1]!") def set_model(self, btn): new_menu = Menu(btn, tearoff=0) btn["menu"] = new_menu self.model_selection_bool = self.initBools(len(self.reg_models) + len(self.clas_models), trues=[]) for i, model in enumerate(self.reg_models.keys()): new_menu.add_checkbutton(label=model, command=self.setModelType(i), variable=self.model_selection_bool[i]) new_menu.add_separator() for i, model in enumerate(self.clas_models.keys()): j = len(self.reg_models) + i new_menu.add_checkbutton(label=model, command=self.setModelType(j), variable=self.model_selection_bool[j]) return new_menu def set_metric(self, btn): new_menu = Menu(btn, tearoff=0) btn["menu"] = new_menu self.metric_selection_bool = self.initBools(len(self.reg_metrics) + len(self.clas_metrics), trues=[]) for i, metric in enumerate(self.reg_metrics.keys()): new_menu.add_checkbutton(label=metric, command=self.setMetricType(i), variable=self.metric_selection_bool[i]) new_menu.add_separator() for i, metric in enumerate(self.clas_metrics.keys()): new_menu.add_checkbutton( label=metric, command=self.setMetricType(len(self.reg_metrics) + i), variable=self.metric_selection_bool[len(self.reg_metrics) + i]) return new_menu def setModelType(self, model_index, default_params=True): def _setModelType(): if len(self.output_cols) == 0: showerror("Error", "No output variable selected!") if self.output_cols[0] in self.numeric_cols: if model_index >= len(self.reg_models): # regression for j in range(len(self.model_selection_bool)): self.model_selection_bool[j].set(value=False) return showerror("Error", "This model is for classification!") elif self.output_cols[0] in self.categorical_cols: if model_index < len(self.reg_models): for j in range(len(self.model_selection_bool)): self.model_selection_bool[j].set(value=False) return showerror("Error", "This model is for regression!") for j in range(len(self.model_selection_bool)): self.model_selection_bool[j].set(value=False) self.model_selection_bool[model_index].set(value=True) # get selected model type for i, b in enumerate(self.model_selection_bool): if b.get(): self.model_int = i try: if self.output_cols[0] in self.numeric_cols: # regression model = self.reg_models[list( self.reg_models.keys())[self.model_int]] model_name = list(self.reg_models.keys())[self.model_int] elif self.output_cols[ 0] in self.categorical_cols: # classification model_int = self.model_int - len(self.reg_models) model = self.clas_models[list( self.clas_models.keys())[model_int]] model_name = list(self.clas_models.keys())[model_int] except Exception as e: return showerror( "Error", "An appropriate model has to be selected: {}".format(e)) self.model_name = model_name self.model = model # get and set default model parameters if default_params: signature = inspect.signature(model) self.model_dict = { k: v.default for k, v in signature.parameters.items() if v.default is not inspect.Parameter.empty } # transformation for regression tasks if self.output_cols[0] in self.numeric_cols: def transformedTargetRegressor(**kwargs): return TransformedTargetRegressor( regressor=model(**kwargs), transformer=MinMaxScaler()) model = transformedTargetRegressor return _setModelType def set_model_parameters(self): """ """ try: model_name, model, model_dict = self.model_name, self.model, self.model_dict except Exception as e: return showerror("Error", "An model has to be selected first: {}".format(e)) class popupWindow(object): def __init__(self, master): top = self.top = Toplevel(master) top.title("Parameters") top.attributes("-topmost", True) width = str(26 * (len(model_dict) + 4)) top.geometry("310x" + width) top.grid() top.resizable(0, 0) frame = LabelFrame(top, text=model_name, relief=RIDGE, width=260) frame.grid(row=0, column=0, columnspan=2, sticky="EWNS", padx=15, pady=15) self.values = list() line = 1 for k, v in model_dict.items(): Label(frame, text=k, width=20) \ .grid(row=line, column=0, columnspan=1, sticky='W', padx=4, pady=1) e = Entry(frame, width=10) e.insert(END, str(v)) e.grid(row=line, column=1, columnspan=1, sticky='E', padx=6, pady=1) self.values.append(e) line += 1 Button(frame, text=' Help ', command=self.help) \ .grid(row=line+2, column=0, columnspan=1, sticky='W', padx=4, pady=4) Button(frame, text=' Ok ', command=self.cleanup) \ .grid(row=line+2, column=1, columnspan=1, sticky='E', padx=4, pady=4) top.bind('<Return>', self.cleanup) def cleanup(self, event=None): for i, k in enumerate(model_dict.keys()): param_type = type(model_dict[k]) try: value = self.values[i].get() if param_type in (type(tuple()), type(list())): model_dict[k] = eval(value) elif param_type is not type(None): model_dict[k] = param_type(value) elif value == 'True' or value == 'False': model_dict[k] = bool(value) else: # default might be NoneType which we don't want try: model_dict[k] = float(value) except: try: model_dict[k] = int(value) except: model_dict[k] = None self.model_dict = model_dict except Exception as e: showerror("Error", "The parameter type of {} is wrong: {}." \ .format(k, type(e))) self.top.destroy() def help(self, event=None): model_class = str(model) start = model_class.find('\'') + 1 end = model_class.rfind('\'') keyword = model_class[start:end] keyword = keyword.replace('.', ' ').replace('_', ' ').replace(' ', ' ') webbrowser.open('https://google.com/search?q=' + keyword) popup = popupWindow(self.master) self.master.wait_window(popup.top) try: self.model_dict = popup.model_dict except AttributeError: pass def setMetricType(self, metric_index): def _setMetricType(): if len(self.output_cols) == 0: showerror("Error", "No output variable selected!") if self.output_cols[0] in self.numeric_cols: if metric_index >= len(self.reg_metrics): # regression for j in range(len(self.metric_selection_bool)): self.metric_selection_bool[j].set(value=False) return showerror("Error", "This metric is for classification!") elif self.output_cols[0] in self.categorical_cols: if metric_index < len(self.reg_metrics): for j in range(len(self.metric_selection_bool)): self.metric_selection_bool[j].set(value=False) return showerror("Error", "This metric is for regression!") for j in range(len(self.metric_selection_bool)): self.metric_selection_bool[j].set(value=False) self.metric_selection_bool[metric_index].set(value=True) # get selected metric type for i, b in enumerate(self.metric_selection_bool): if b.get(): self.metric_int = i # set name and metric itself if self.output_cols[0] in self.numeric_cols: self.metric_name = list( self.reg_metrics.keys())[self.metric_int] self.metric = self.reg_metrics[self.metric_name] elif self.output_cols[0] in self.categorical_cols: metric_int = self.metric_int - len(self.reg_metrics) self.metric_name = list(self.clas_metrics.keys())[metric_int] self.metric = self.clas_metrics[self.metric_name] return _setMetricType def show_data(self): """ Opens a new window showing the data. """ data = self.data class DataFrame(Frame): def __init__(self, master=None): top = self.top = Toplevel(master) top.attributes("-topmost", True) top.geometry('600x720') top.title('Data') self.table = pt = Table(top, dataframe=data, editable=False, enable_menus=False) pt.show() return popup = DataFrame(self.master) self.master.wait_window(popup.top) def show_description(self): """ Opens a new window showing the a description of the data. """ data = self.data.describe() data.reset_index(level=0, inplace=True) data.rename(columns={"index": ""}, inplace=True) class DataFrame(Frame): def __init__(self, master=None): top = self.top = Toplevel(master) top.attributes("-topmost", True) top.geometry('550x220') top.title('Data Description') self.table = pt = Table(top, dataframe=data, editable=False, enable_menus=False) pt.show() return popup = DataFrame(self.master) self.master.wait_window(popup.top) def pair_plot(self, limit: int = 50): """ Draws a seaborn pairplot of the current data selection. Arguments --------- limit: int, maximum number of data points to plot. Returns ------- - """ if len(self.input_cols) + len(self.output_cols) <= 1: return showerror("Error", "No features selected to plot.") if len(self.output_cols) == 1: hue = self.cols[self.output_cols[0]] if \ self.bools[self.output_cols[0]][4].get() else None else: hue = None if limit < self.data.shape[0]: showinfo("Info", "Showing only the first {} entries.".format(limit)) sns.pairplot(self.data[self.cols[self.input_cols + self.output_cols]][:limit], hue=hue, height=1.5, aspect=1.) plt.gcf().canvas.set_window_title('Pair Plot of Data') plt.get_current_fig_manager().window.setWindowIcon( QtGui.QIcon(os.path.join(os.path.dirname(__file__), 'icon.ico'))) plt.show() def shuffle_data(self): """ Shuffle the rows of the data. """ self.data = self.data.sample(frac=1) class Notification(Frame): def __init__(self, master=None): top = self.top = Toplevel(master) top.attributes("-topmost", True) window_height = 75 window_width = 225 screen_width = top.winfo_screenwidth() screen_height = top.winfo_screenheight() x_cordinate = int((screen_width / 2) - (window_width / 2)) y_cordinate = int((screen_height / 2) - (window_height / 2)) top.geometry("{}x{}+{}+{}".format(window_width, window_height, x_cordinate, y_cordinate)) top.title('') Label(top, text="\nShuffeld\n", anchor=CENTER).pack() return popup = Notification(self.master) self.after(500, lambda: popup.top.destroy()) def startModel(self): """ Main action for trainig the selected model on the data. """ error_msg = "" if len(self.output_cols) != 1: error_msg += " * There must be exactly one dependent variable.\n" if len(self.input_cols) < 1: error_msg += " * There must be at least one independent variable.\n" if not hasattr(self, 'model'): error_msg += " * A model has to be selected.\n" if not hasattr(self, 'metric_int'): error_msg += " * A metric has to be selected.\n" if len(error_msg) > 0: return showerror("Error", 'Model training failed!\n' + error_msg) # split data X_train, X_test, y_train, y_test = train_test_split( self.data[self.cols[self.input_cols]], self.data[self.cols[self.output_cols]], test_size=self.train_test_ratio) numeric_transformer = Pipeline( steps=[('imputer', SimpleImputer( strategy='median')), ('scaler', StandardScaler())]) categorical_transformer = Pipeline( steps=[('imputer', SimpleImputer(strategy='constant', fill_value='missing') ), ('onehot', OneHotEncoder(handle_unknown='ignore'))]) preprocessor = ColumnTransformer( transformers=[('num', numeric_transformer, self.cols[list( set(self.numeric_cols) - set(self.ignore_cols + self.output_cols))]), ('cat', categorical_transformer, self.cols[list( set(self.categorical_cols) - set(self.ignore_cols + self.output_cols))])]) model = Pipeline(steps=[('preprocessor', preprocessor), ('model', Model(self.master, self.model, self.model_name, self.model_dict))]) try: model.fit(X_train, y_train) except ValueError as e: return showerror( "Error", "Could not train the model (ValueError): {}".format(e)) except Exception as e: return showerror("Error", "Could not train the model: {}.".format(e)) # make prediction try: y_pred = model.predict(X_test) self.data["predictions"] = model.predict( self.data[self.cols[self.input_cols]]) except Exception as e: return showerror("Error", "Failed to calculate predictions: {}".format(e)) # evaluate model try: self.score = np.round(self.metric(y_test, y_pred), 4) showinfo("Result", "The model {} scored a {} of {} on the test data." \ .format(self.model_name, self.metric_name, self.score)) self.score_str.set( "The current model scores {} on the test data.".format( str(np.round(self.score, 4))) if self.score != -1 else "") except Exception as e: return showerror("Error", "Failed to evaluate the predictions with " \ + "the specified metric: {}.".format(e)) def export_data(self): """ Save preprocessed data and predictions (if made). """ try: export_file_path = filedialog.asksaveasfilename( filetypes=[("default", "*.csv")], defaultextension='.csv') self.data.to_csv(export_file_path, index=False, header=True) except FileNotFoundError: pass except Exception as e: showerror("Error", "Data could not be saved: {}.".format(e)) def export_model(self): """ Save the model on disk. """ try: export_file_path = filedialog.asksaveasfilename( filetypes=[("default", "*.pkl")], defaultextension='.pkl') saving = (self.model_name, self.model_dict, self.model, self.model_int, self.metric_int) pickle.dump(saving, open(export_file_path, "wb")) except (AttributeError, FileNotFoundError): pass except Exception as e: showerror("Error", "Failed to save model: {}.".format(e)) def laod_model(self): try: filename = filedialog.askopenfilename(filetypes=[("default", "*.pkl")], defaultextension='.pkl') self.model_name, self.model_dict, self.model, self.model_int, \ self.metric_int = pickle.load(open(filename, 'rb')) self.model_loaded = True self.setModelType(self.model_int, default_params=False)() self.setMetricType(self.metric_int)() except FileNotFoundError: pass except Exception as e: showerror("Error", "Data could not be saved: {}.".format(e))
def readData_createWindow(self): try: filename = filedialog.askopenfilename() f = open(filename, "rb") self.set_header(self.header_bool) # f = 'http://archive.ics.uci.edu/ml/machine-learning-databases/iris/iris.data' header = self.header_bool.get() == 1 self.data = pd.read_csv(f, header=0 if header else None, sep=',') if not header: self.data.columns = [ 'var' + str(i) for i in range(len(self.data.columns)) ] except AttributeError: pass except Exception as e: return showerror("Error", "Data could not be loaded! Make sure the data is " \ + "formated in a similar way as the sample data: {}.".format(e)) self.cols = self.data.columns self.setUpData() self.bools = [ ] # variables for columns: first axis: which col; second axis: what type height = min(5, self.data.shape[0]) width = len(self.cols) # data frame data_frame = LabelFrame(self.master, text="Data Summary", relief=RIDGE) data_frame.grid(row=0, column=0, columnspan=5, sticky="EWNS", padx=15, pady=7.5) data_size = "Data size is {} kilobytes. " \ .format(np.round(self.data.memory_usage(deep=False).sum() / 1000, 2)) cols_rows = "The number of columns is {} and the number of rows is {}. " \ .format(self.data.shape[1], self.data.shape[0]) miss_data = "The data does have missing values." if self.data.isnull().values.any() \ else "The data does not have missing values." Message(data_frame, text=data_size + cols_rows + miss_data, width=335) \ .grid(row=0, column=0, columnspan=width-1, rowspan=3, sticky='NW') Button(data_frame, text="Data", width=13, command=self.show_data) \ .grid(row=0, column=4, columnspan=1, padx=4, pady=4) Button(data_frame, text="Description", width=13, command=self.show_description) \ .grid(row=1, column=4, columnspan=1, padx=4, pady=0) Button(data_frame, text="Pair Plot", width=13, command=self.pair_plot) \ .grid(row=2, column=4, columnspan=1, padx=4, pady=4) # head frame head_frame = LabelFrame(self.master, text="Head of data", relief=RIDGE) head_frame.grid(row=5, column=0, columnspan=5, sticky="EWNS", padx=15, pady=7.5) for i in range(len(self.cols)): self.bools.append( self.initBools(5, trues=[0, 3] if i < width - 1 else [1, 3])) table = CustomTable(main_window=self, parent=head_frame, dataframe=self.data.head(), editable=False, width=1, height=120) config.apply_options({'fontsize': 10}, table) table.show() # modeling frame model_frame = LabelFrame(self.master, text="Modeling", relief=RIDGE) model_frame.grid(row=height + 11, column=0, columnspan=5, sticky="EWNS", padx=15, pady=7.5) # train / test ratio self.train_test_ratio = 1 / 3 self.train_test_ratio_str = StringVar( self.master, value=str(np.round(self.train_test_ratio, 2))) Button(model_frame, text="Shuffle Data", width=13, command=self.shuffle_data) \ .grid(row=0, column=0, columnspan=1) Button(model_frame, text="TrainTest Ratio", width=13, command=self.set_traintest) \ .grid(row=0, column=2, columnspan=1) Label(model_frame, textvariable=self.train_test_ratio_str) \ .grid(row=0, column=3, columnspan=1, sticky="E") # model selection ttk.Style().configure("TMenubutton", background="#E1E1E1") self.model_btn = Menubutton(model_frame, text="Model", width=9) self.set_model(self.model_btn) self.model_btn.grid(row=1, column=0, columnspan=1, padx=0, pady=4) Button(model_frame, text="Parameters", width=13, command=self.set_model_parameters) \ .grid(row=1, column=1, columnspan=1, padx=0, pady=4) self.metric_btn = Menubutton(model_frame, text="Metric", width=9) self.set_metric(self.metric_btn) self.metric_btn.grid(row=1, column=2, columnspan=1, padx=0, pady=4) # model training self.score = -1 self.score_str = StringVar(self.master, value="") Button(model_frame, text="Train Model", width=13, command=self.startModel) \ .grid(row=1, column=3, columnspan=width-1) Label(model_frame, textvariable=self.score_str) \ .grid(row=3, columnspan=width, sticky='W') # Export Frame export_frame = LabelFrame(self.master, text="Save", relief=RIDGE) export_frame.grid(row=height + 15, column=0, columnspan=5, sticky="EWNS", padx=15, pady=7.5) Button(export_frame, text="Export Data", width=13, command=self.export_data) \ .grid(row=0, column=0, columnspan=1, padx=4, pady=4) Button(export_frame, text="Export Model", width=13, command=self.export_model) \ .grid(row=0, column=1, columnspan=1, padx=0, pady=4)
def __init__(self): Tk.__init__(self, className="WorkHourGlass") self.on = False # is the timer on? if not CONFIG.options("Tasks"): CONFIG.set("Tasks", _("Work"), CMAP[0]) # colors self.background = { _("Work"): CONFIG.get("Work", "bg"), _("Break"): CONFIG.get("Break", "bg"), _("Rest"): CONFIG.get("Rest", "bg") } self.foreground = { _("Work"): CONFIG.get("Work", "fg"), _("Break"): CONFIG.get("Break", "fg"), _("Rest"): CONFIG.get("Rest", "fg") } # window configuration if PL[0] == "w": self.iconbitmap(ICON_WIN, default=ICON_WIN) else: self.icon = PhotoImage(master=self, file=ICON) self.iconphoto(True, self.icon) self.title("WorkHourGlass") self.protocol("WM_DELETE_WINDOW", self.exit) self.rowconfigure(1, weight=1) self.columnconfigure(0, weight=1) self.columnconfigure(1, weight=1) self.minsize(181, 190) self.geometry("200x190+%i+%i" % ((self.winfo_screenwidth() - 200) // 2, (self.winfo_screenheight() - 190) // 2)) self.configure(background=self.background[_("Work")]) # style self.style = Style(self) self.style.theme_use(STYLE) self.style.configure('fen.TLabel', foreground=self.foreground[_("Work")], background=self.background[_("Work")]) # nombre de séquence de travail effectuées d'affilée (pour # faire des pauses plus longues tous les 4 cycles) self.nb_cycles = 0 self.pomodori = IntVar(self, 0) # images self.im_go = PhotoImage(master=self, file=GO) self.im_stop = PhotoImage(master=self, file=STOP) self.im_plus = PhotoImage(master=self, file=PLUS) self.im_moins = PhotoImage(master=self, file=MOINS) self.im_params = PhotoImage(master=self, file=PARAMS) self.im_tomate = PhotoImage(master=self, file=TOMATE) self.im_graph = PhotoImage(master=self, file=GRAPH) # tasks list tasks_frame = Frame(self) tasks_frame.grid(row=3, column=0, columnspan=3, sticky="wnse") tasks = [t.capitalize() for t in CONFIG.options("Tasks")] self.task = StringVar(self, tasks[0]) self.menu_tasks = Menu(tasks_frame, tearoff=False) for task in tasks: self.menu_tasks.add_radiobutton(label=task, value=task, variable=self.task) self.menu_tasks.add_command(label=_("New task"), image=self.im_plus, compound="left", command=self.add_task) self.menu_tasks.add_command(label=_("Remove task"), image=self.im_moins, compound="left", command=self.del_task) self.menu_tasks.add_command(label=_("Statistics"), image=self.im_graph, compound="left", command=self.display_stats) self.choose_task = Menubutton(tasks_frame, textvariable=self.task, menu=self.menu_tasks) Label(tasks_frame, text=_("Task: "), font="CMU\ Sans\ Serif\ Demi\ Condensed 12", width=6, anchor="e").pack(side="left") self.choose_task.pack(side="right", fill="x") # display self.tps = [CONFIG.getint("Work", "time"), 0] # time: min, sec self.activite = StringVar(self, _("Work")) self.titre = Label(self, textvariable=self.activite, font='CMU\ Sans\ Serif\ Demi\ Condensed 14', style='fen.TLabel', anchor="center") self.titre.grid(row=0, column=0, columnspan=2, sticky="we") self.temps = Label( self, text="{0:02}:{1:02}".format(self.tps[0], self.tps[1]), font="%s %i" % (CONFIG.get( "General", "font"), CONFIG.getint("General", "fontsize")), style='fen.TLabel', anchor="center") self.temps.grid(row=1, column=0, columnspan=2, sticky="nswe", pady=(0, 10)) self.aff_pomodori = Label(self, textvariable=self.pomodori, image=self.im_tomate, compound="left", style='fen.TLabel', font='CMU\ Sans\ Serif\ Demi\ Condensed 14') self.aff_pomodori.grid(row=2, columnspan=2, sticky="e", padx=20) # buttons self.b_go = Button(self, image=self.im_go, command=self.go) self.b_go.grid(row=4, column=0, sticky="ew") self.b_params = Button(self, image=self.im_params, command=self.params) self.b_params.grid(row=4, column=1, sticky="ew") # --- make window sticky self.update_idletasks() e = EWMH() try: for w in e.getClientList(): if w.get_wm_name() == self.title(): e.setWmState(w, 1, '_NET_WM_STATE_STICKY') e.display.flush() except ewmh.display.error.BadWindow: pass
class Timer(Tk): """ Chronométre de temps de travail pour plus d'efficacité """ def __init__(self): Tk.__init__(self, className="WorkHourGlass") self.on = False # is the timer on? if not CONFIG.options("Tasks"): CONFIG.set("Tasks", _("Work"), CMAP[0]) # colors self.background = { _("Work"): CONFIG.get("Work", "bg"), _("Break"): CONFIG.get("Break", "bg"), _("Rest"): CONFIG.get("Rest", "bg") } self.foreground = { _("Work"): CONFIG.get("Work", "fg"), _("Break"): CONFIG.get("Break", "fg"), _("Rest"): CONFIG.get("Rest", "fg") } # window configuration if PL[0] == "w": self.iconbitmap(ICON_WIN, default=ICON_WIN) else: self.icon = PhotoImage(master=self, file=ICON) self.iconphoto(True, self.icon) self.title("WorkHourGlass") self.protocol("WM_DELETE_WINDOW", self.exit) self.rowconfigure(1, weight=1) self.columnconfigure(0, weight=1) self.columnconfigure(1, weight=1) self.minsize(181, 190) self.geometry("200x190+%i+%i" % ((self.winfo_screenwidth() - 200) // 2, (self.winfo_screenheight() - 190) // 2)) self.configure(background=self.background[_("Work")]) # style self.style = Style(self) self.style.theme_use(STYLE) self.style.configure('fen.TLabel', foreground=self.foreground[_("Work")], background=self.background[_("Work")]) # nombre de séquence de travail effectuées d'affilée (pour # faire des pauses plus longues tous les 4 cycles) self.nb_cycles = 0 self.pomodori = IntVar(self, 0) # images self.im_go = PhotoImage(master=self, file=GO) self.im_stop = PhotoImage(master=self, file=STOP) self.im_plus = PhotoImage(master=self, file=PLUS) self.im_moins = PhotoImage(master=self, file=MOINS) self.im_params = PhotoImage(master=self, file=PARAMS) self.im_tomate = PhotoImage(master=self, file=TOMATE) self.im_graph = PhotoImage(master=self, file=GRAPH) # tasks list tasks_frame = Frame(self) tasks_frame.grid(row=3, column=0, columnspan=3, sticky="wnse") tasks = [t.capitalize() for t in CONFIG.options("Tasks")] self.task = StringVar(self, tasks[0]) self.menu_tasks = Menu(tasks_frame, tearoff=False) for task in tasks: self.menu_tasks.add_radiobutton(label=task, value=task, variable=self.task) self.menu_tasks.add_command(label=_("New task"), image=self.im_plus, compound="left", command=self.add_task) self.menu_tasks.add_command(label=_("Remove task"), image=self.im_moins, compound="left", command=self.del_task) self.menu_tasks.add_command(label=_("Statistics"), image=self.im_graph, compound="left", command=self.display_stats) self.choose_task = Menubutton(tasks_frame, textvariable=self.task, menu=self.menu_tasks) Label(tasks_frame, text=_("Task: "), font="CMU\ Sans\ Serif\ Demi\ Condensed 12", width=6, anchor="e").pack(side="left") self.choose_task.pack(side="right", fill="x") # display self.tps = [CONFIG.getint("Work", "time"), 0] # time: min, sec self.activite = StringVar(self, _("Work")) self.titre = Label(self, textvariable=self.activite, font='CMU\ Sans\ Serif\ Demi\ Condensed 14', style='fen.TLabel', anchor="center") self.titre.grid(row=0, column=0, columnspan=2, sticky="we") self.temps = Label( self, text="{0:02}:{1:02}".format(self.tps[0], self.tps[1]), font="%s %i" % (CONFIG.get( "General", "font"), CONFIG.getint("General", "fontsize")), style='fen.TLabel', anchor="center") self.temps.grid(row=1, column=0, columnspan=2, sticky="nswe", pady=(0, 10)) self.aff_pomodori = Label(self, textvariable=self.pomodori, image=self.im_tomate, compound="left", style='fen.TLabel', font='CMU\ Sans\ Serif\ Demi\ Condensed 14') self.aff_pomodori.grid(row=2, columnspan=2, sticky="e", padx=20) # buttons self.b_go = Button(self, image=self.im_go, command=self.go) self.b_go.grid(row=4, column=0, sticky="ew") self.b_params = Button(self, image=self.im_params, command=self.params) self.b_params.grid(row=4, column=1, sticky="ew") # --- make window sticky self.update_idletasks() e = EWMH() try: for w in e.getClientList(): if w.get_wm_name() == self.title(): e.setWmState(w, 1, '_NET_WM_STATE_STICKY') e.display.flush() except ewmh.display.error.BadWindow: pass def set_config(self): self.background = { _("Work"): CONFIG.get("Work", "bg"), _("Break"): CONFIG.get("Break", "bg"), _("Rest"): CONFIG.get("Rest", "bg") } self.foreground = { _("Work"): CONFIG.get("Work", "fg"), _("Break"): CONFIG.get("Break", "fg"), _("Rest"): CONFIG.get("Rest", "fg") } act = self.activite.get() self.configure(background=self.background[act]) self.style.configure('fen.TLabel', foreground=self.foreground[act], background=self.background[act]) self.temps.configure(font="%s %i" % (CONFIG.get("General", "font"), CONFIG.getint("General", "fontsize"))) 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 del_task(self): """ Suppression de tâches """ def supprime(): rep = askyesno(_("Confirmation"), _("Are you sure you want to delete these tasks?")) if rep: for i in range(len(boutons) - 1, -1, -1): # l'ordre de parcours permet de supprimer les derniers # éléments en premier afin de ne pas modifier les index des # autres éléments lors des suppressions task = tasks[i] if "selected" in boutons[i].state(): # suppression de la tâche de la liste des tâches CONFIG.remove_option("Tasks", task) tasks.remove(task) # suppression de l'entrée correspondante dans le menu self.menu_tasks.delete(i) if not tasks: CONFIG.set("Tasks", _("Work"), CMAP[0]) tasks.append(_("Work")) self.menu_tasks.insert_radiobutton( 0, label=_("Work"), value=_("Work"), variable=self.task) if self.task.get() == task: self.task.set(tasks[0]) # suppression des stats associées chemin = PATH_STATS + "_" + "_".join(task.split(" ")) if os.path.exists(chemin): os.remove(chemin) top.destroy() with open(PATH_CONFIG, "w") as file: CONFIG.write(file) else: top.destroy() tasks = [t.capitalize() for t in CONFIG.options("Tasks")] top = Toplevel(self) top.title(_("Remove task")) top.transient(self) top.grab_set() style = Style(top) style.theme_use(STYLE) boutons = [] for i, task in enumerate(tasks): boutons.append(Checkbutton(top, text=task)) boutons[-1].grid(row=i, columnspan=2, sticky="w") Button(top, text=_("Cancel"), command=top.destroy).grid(row=i + 1, column=0) Button(top, text=_("Delete"), command=supprime).grid(row=i + 1, column=1) def stats(self): """ Enregistre la durée de travail (en min) effectuée ce jour pour la tâche qui vient d'être interrompue. Seul les pomodori complets sont pris en compte. """ # TODO: translate, correct date/time format pom = self.pomodori.get() if pom: # la tâche en cours a été travaillée, il faut enregistrer les stats date = dt.date.today() task = self.task.get() chemin = PATH_STATS + "_" + "_".join(task.split(" ")) if not os.path.exists(chemin): with open(chemin, 'w') as fich: fich.write( "# tâche : %s\n# jour\tmois\tannée\ttemps de travail (min)\n" % task) with open(chemin, 'r') as fich: stats = fich.readlines() if len(stats) > 2: last = stats[-1][:10], stats[-1][:-1].split("\t")[-1] else: last = "", 0 if last[0] != date.strftime("%d\t%m\t%Y"): with open(chemin, 'a') as fich: fich.write("%s\t%i\n" % (date.strftime("%d\t%m\t%Y"), pom * CONFIG.getint("Work", "time"))) else: # un nombre a déjà été enregistré plus tôt dans la journée # il faut les additioner with open(chemin, 'w') as fich: fich.writelines(stats[:-1]) fich.write( "%s\t%i\n" % (date.strftime("%d\t%m\t%Y"), pom * CONFIG.getint("Work", "time") + int(last[1]))) def display_stats(self): """ affiche les statistiques """ plt.figure("Statistiques") tasks = [t.capitalize() for t in CONFIG.options("Tasks")] coul = [CONFIG.get("Tasks", task) for task in tasks] stats_x = [] stats_y = [] demain = dt.date.today().toordinal() + 1 min_x = demain # récupération des données no_data = True for i, task in enumerate(tasks): chemin = PATH_STATS + "_" + "_".join(task.split(" ")) if os.path.exists(chemin): no_data = False stat = loadtxt(chemin, dtype=int) if len(stat.shape) == 1: stat = stat.reshape(1, 4) x = [ dt.date(an, mois, jour).toordinal() for jour, mois, an in stat[:, :3] ] y = stat[:, -1] / 60 # temps de travail min_x = min(x[0], min_x) stats_x.append(x) stats_y.append(y) else: # la taĉhe n'a jamais été travaillée stats_x.append([demain - 1]) stats_y.append(array([0])) # plots xx = arange(min_x, demain, dtype=float) yy0 = zeros_like(xx) # pour empiler les stats if not no_data: for (i, task), x, y in zip(enumerate(tasks), stats_x, stats_y): ax0 = plt.subplot(111) plt.ylabel(_("time (h)")) plt.xlabel(_("date")) yy = array([], dtype=int) # comble les trous par des 0 # ainsi, les jours où une tâche n'a pas été travaillée correspondent # à des 0 sur le graph xxx = arange(min_x, x[0]) yy = concatenate((yy, zeros_like(xxx, dtype=int))) for j in range(len(x) - 1): xxx = arange(x[j], x[j + 1]) yy = concatenate((yy, [y[j]], zeros(len(xxx) - 1, dtype=int))) xxx = arange(x[-1], demain) yy = concatenate((yy, [y[-1]], zeros(len(xxx) - 1, dtype=int))) plt.bar(xx - 0.4, yy, bottom=yy0, width=0.8, label=task, color=coul[i]) yy0 += yy axx = array( [int(xt) for xt in ax0.get_xticks() if xt.is_integer()]) ax0.set_xticks(axx) ax0.set_xticklabels( [dt.date.fromordinal(i).strftime("%x") for i in axx]) plt.gcf().autofmt_xdate() ax0.set_xlim(min_x - 0.5, demain - 0.5) lgd = plt.legend(fontsize=10) lgd.draggable() plt.subplots_adjust(top=0.95) max_y = yy0.max() ax0.set_ylim(0, max_y + 0.1 * max_y) plt.show() def go(self): if self.on: self.on = False if self.activite.get() == _("Work"): # rep = askyesno(title=_("Confirmation"), # message=_("You should not interrupt your work if you want to be efficient. Do you still want to suspend the timer?"), # icon="warning") # else: # rep = True self.stop() # if rep: # self.b_go.configure(image=self.im_go) # else: # self.on = True # self.affiche() else: self.on = True self.choose_task.config(state="disabled") self.b_go.configure(image=self.im_stop) self.after(1000, self.affiche) def stop(self, confirmation=True): """ Arrête le décompte du temps et le réinitialise, demande une confirmation avant de le faire si confirmation=True """ self.on = False if confirmation: rep = askyesno( title=_("Confirmation"), message=_( "Are you sure you want to give up the current session?")) else: rep = True if rep: self.stats() self.pomodori.set(0) self.nb_cycles = 0 self.b_go.configure(image=self.im_go) self.tps = [CONFIG.getint("Work", "time"), 0] self.temps.configure( text="{0:02}:{1:02}".format(self.tps[0], self.tps[1])) act = _("Work") self.activite.set(act) self.style.configure('fen.TLabel', background=self.background[act], foreground=self.foreground[act]) self.configure(background=self.background[act]) self.choose_task.config(state="normal") else: self.on = True self.affiche() def ting(self): """ joue le son marquant le changement de période """ if not CONFIG.getboolean("Sound", "mute", fallback=False): if PL[0] == "w": Popen([ "powershell", "-c", '(New-Object Media.SoundPlayer "%s").PlaySync();' % (CONFIG.get("Sound", "beep")) ]) else: Popen([ CONFIG.get("Sound", "player"), CONFIG.get("Sound", "beep") ]) def affiche(self): if self.on: self.tps[1] -= 1 if self.tps[1] == 0: if self.tps[0] == 0: self.ting() if self.activite.get() == _("Work"): self.pomodori.set(self.pomodori.get() + 1) self.nb_cycles += 1 if self.nb_cycles % 4 == 0: # pause longue self.activite.set(_("Rest")) self.tps = [CONFIG.getint("Rest", "time"), 0] else: # pause courte self.activite.set(_("Break")) self.tps = [CONFIG.getint("Break", "time"), 0] else: self.activite.set(_("Work")) self.tps = [CONFIG.getint("Work", "time"), 0] act = self.activite.get() self.style.configure('fen.TLabel', background=self.background[act], foreground=self.foreground[act]) self.configure(background=self.background[act]) elif self.tps[1] == -1: self.tps[0] -= 1 self.tps[1] = 59 self.temps.configure( text="{0:02}:{1:02}".format(self.tps[0], self.tps[1])) self.after(1000, self.affiche) def params(self): on = self.on self.on = False self.b_go.configure(image=self.im_go) p = Params(self) self.wait_window(p) if on: self.on = True self.choose_task.config(state="disabled") self.b_go.configure(image=self.im_stop) self.after(1000, self.affiche) def exit(self): self.stats() plt.close() self.destroy()
def __init__(self, master): Toplevel.__init__(self, master, class_="CheckMails") self.title(_("Preferences")) style = Style(self) style.map("TCombobox", fieldbackground=[('readonly', 'white')], selectbackground=[('readonly', 'white')], selectforeground=[('readonly', 'black')], foreground=[('readonly', 'black')]) # validation of the entries : only numbers are allowed self._validate_entry_nb = self.register(self.validate_entry_nb) # --- Times Label(self, text=_("Time between two checks")).grid(row=0, column=0, padx=(10, 4), pady=(10, 4), sticky="e") Label(self, justify="right", text=_("Maximum time allowed for login or check\n\ (then the connection is reset)")).grid(row=1, column=0, padx=(10, 4), pady=4, sticky="e") self.time_entry = Entry(self, width=5, justify="center", validate="key", validatecommand=(self._validate_entry_nb, "%P")) self.time_entry.grid(row=0, column=1, padx=(4, 0), pady=(10, 4)) self.time_entry.insert(0, "%g" % (CONFIG.getint("General", "time") / 60000)) self.timeout_entry = Entry(self, width=5, justify="center", validate="key", validatecommand=(self._validate_entry_nb, "%P")) self.timeout_entry.grid(row=1, column=1, padx=(4, 0), pady=4) self.timeout_entry.insert(0, "%g" % (CONFIG.getint("General", "timeout") / 60000)) Label(self, text="min").grid(row=0, column=2, padx=(0, 10), pady=(10, 4)) Label(self, text="min").grid(row=1, column=2, padx=(0, 10), pady=4) frame = Frame(self) frame.grid(row=2, columnspan=3, padx=6, pady=(0, 6)) # --- Language Label(frame, text=_("Language")).grid(row=0, column=0, padx=8, pady=4, sticky="e") lang = {"fr": "Français", "en": "English"} self.lang = StringVar(self, lang[CONFIG.get("General", "language")]) menu_lang = Menu(frame, tearoff=False) Menubutton(frame, menu=menu_lang, width=9, textvariable=self.lang).grid(row=0, column=1, padx=8, pady=4, sticky="w") menu_lang.add_radiobutton(label="English", value="English", variable=self.lang, command=self.translate) menu_lang.add_radiobutton(label="Français", value="Français", variable=self.lang, command=self.translate) # --- gui toolkit Label(frame, text=_("GUI Toolkit for the system tray icon")).grid(row=1, column=0, padx=8, pady=4, sticky="e") self.gui = StringVar(self, CONFIG.get("General", "trayicon").capitalize()) menu_gui = Menu(frame, tearoff=False) Menubutton(frame, menu=menu_gui, width=9, textvariable=self.gui).grid(row=1, column=1, padx=8, pady=4, sticky="w") for toolkit, b in TOOLKITS.items(): if b: menu_gui.add_radiobutton(label=toolkit.capitalize(), value=toolkit.capitalize(), variable=self.gui, command=self.change_gui) # --- Font self.preview_path = tempfile.mktemp(".png", "checkmails_preview") w = max([len(f) for f in TTF_FONTS]) self.fonts = sorted(TTF_FONTS) self.font = Combobox(frame, values=self.fonts, width=(w * 2) // 3, exportselection=False, state="readonly") current_font = CONFIG.get("General", "font") if current_font in self.fonts: i = self.fonts.index(current_font) else: i = 0 self.font.current(i) self.img_prev = PhotoImage(master=self, file=IMAGE) Label(frame, text=_("Font")).grid(row=2, column=0, padx=8, pady=4, sticky="e") self.font.grid(row=2, column=1, padx=8, pady=4, sticky="w") self.prev = Label(frame, image=self.img_prev) self.prev.grid(row=2, column=2, padx=8, pady=4) self.update_preview() self.font.bind('<<ComboboxSelected>>', self.update_preview) self.font.bind_class("ComboboxListbox", '<KeyPress>', self.key_nav) # --- Ok/Cancel frame_button = Frame(self) frame_button.grid(row=3, columnspan=3, padx=6, pady=(0, 6)) Button(frame_button, text="Ok", command=self.ok).grid(row=2, column=0, padx=8, pady=4) Button(frame_button, text=_("Cancel"), command=self.destroy).grid(row=2, column=1, padx=4, pady=4)
def __init__(self, master): Toplevel.__init__(self, master) self.title(_("Preferences")) self.grab_set() self.resizable(False, False) self.protocol("WM_DELETE_WINDOW", self.quit) self.changes = {}, {} # --- style style = Style(self) style.theme_use("clam") style.configure("TScale", sliderlength=20) style.map("TCombobox", fieldbackground=[('readonly', 'white')], selectbackground=[('readonly', 'white')], selectforeground=[('readonly', 'black')]) style.configure("prev.TLabel", background="white") style.map("prev.TLabel", background=[("active", "white")]) color = CONFIG.get("Categories", CONFIG.get("General", "default_category")) style.configure("titlebar.TFrame", background=color) style.configure("titlebar.TLabel", background=color) style.configure("text.TFrame", background="white") # --- body self.notebook = Notebook(self) okcancel_frame = Frame(self) okcancel_frame.columnconfigure(0, weight=1) okcancel_frame.columnconfigure(1, weight=1) self.notebook.pack(expand=True, fill="both") okcancel_frame.pack(fill="x", expand=True) # --- * General settings general_settings = Frame(self.notebook) general_settings.columnconfigure(0, weight=1) self.notebook.add(general_settings, text=_("General"), sticky="ewsn", padding=4) # --- *-- language lang = {"fr": "Français", "en": "English"} self.lang = StringVar(self, lang[CONFIG.get("General", "language")]) lang_frame = Frame(general_settings) Label(lang_frame, text=_("Language")).grid(row=0, sticky="w", padx=4, pady=4) menu_lang = Menu(lang_frame, tearoff=False) Menubutton(lang_frame, menu=menu_lang, width=9, textvariable=self.lang).grid(row=0, column=1, padx=8, pady=4) menu_lang.add_radiobutton(label="English", value="English", variable=self.lang, command=self.translate) menu_lang.add_radiobutton(label="Français", value="Français", variable=self.lang, command=self.translate) # --- *-- opacity self.opacity_scale = Scale(general_settings, orient="horizontal", length=200, from_=0, to=100, value=CONFIG.get("General", "opacity"), command=self.display_label) self.opacity_label = Label( general_settings, text="{val}%".format(val=self.opacity_scale.get())) # --- *-- position frame_position = Frame(general_settings) self.position = StringVar(self, CONFIG.get("General", "position")) Label(frame_position, text=_("Default position of the notes")).grid(row=0, columnspan=3, sticky="w", padx=4, pady=4) Radiobutton(frame_position, text=_("Always above"), value="above", variable=self.position).grid(row=1, column=0) Radiobutton(frame_position, text=_("Always below"), value="below", variable=self.position).grid(row=1, column=1) Radiobutton(frame_position, text=_("Normal"), value="normal", variable=self.position).grid(row=1, column=2) # --- *-- titlebar self.titlebar_disposition = StringVar( self, CONFIG.get("General", "buttons_position")) 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) frame_titlebar = Frame(general_settings) frame_titlebar.columnconfigure(1, weight=1) frame_titlebar.columnconfigure(3, weight=1) Label(frame_titlebar, text=_("Title bar disposition")).grid(row=0, columnspan=4, sticky="w", padx=4, pady=4) Radiobutton(frame_titlebar, value="right", variable=self.titlebar_disposition).grid(row=1, column=0) right = Frame(frame_titlebar, style="titlebar.TFrame") right.grid(row=1, column=1, sticky="ew") def select_right(event): self.titlebar_disposition.set("right") Label(right, text=_("Title"), style="titlebar.TLabel", anchor="center", font=font_title).pack(side="left", fill="x", expand=True) Label(right, image="img_close", style="titlebar.TLabel").pack(side="right") Label(right, image="img_roll", style="titlebar.TLabel").pack(side="right") for ch in right.children.values(): ch.bind("<Button-1>", select_right) Radiobutton(frame_titlebar, value="left", variable=self.titlebar_disposition).grid(row=1, column=2) left = Frame(frame_titlebar, style="titlebar.TFrame") left.grid(row=1, column=3, sticky="ew") def select_left(event): self.titlebar_disposition.set("left") Label(left, image="img_close", style="titlebar.TLabel").pack(side="left") Label(left, image="img_roll", style="titlebar.TLabel").pack(side="left") Label(left, text=_("Title"), style="titlebar.TLabel", anchor="center", font=font_title).pack(side="right", fill="x", expand=True) for ch in left.children.values(): ch.bind("<Button-1>", select_left) # --- *-- placement lang_frame.grid(sticky="w") Separator(general_settings, orient="horizontal").grid(sticky="ew", pady=10) Label(general_settings, text=_("Opacity")).grid(sticky="w", padx=4, pady=4) self.opacity_scale.grid(padx=4, pady=(4, 10)) self.opacity_label.place(in_=self.opacity_scale, relx=1, rely=0.5, anchor="w", bordermode="outside") Separator(general_settings, orient="horizontal").grid(sticky="ew", pady=10) frame_position.grid(sticky="ew") Separator(general_settings, orient="horizontal").grid(sticky="ew", pady=10) frame_titlebar.grid(sticky="ew", pady=4) if LATEX: Separator(general_settings, orient="horizontal").grid(sticky="ew", pady=10) Button(general_settings, text=_('Delete unused LaTex data'), command=self.cleanup).grid(padx=4, pady=4, sticky='w') # --- * Font settings font_settings = Frame(self.notebook) font_settings.columnconfigure(0, weight=1) self.notebook.add(font_settings, text=_("Font"), sticky="ewsn", padding=4) # --- *-- title fonttitle_frame = Frame(font_settings) title_size = CONFIG.get("Font", "title_size") title_family = CONFIG.get("Font", "title_family") self.sampletitle = Label(fonttitle_frame, text=_("Sample text"), anchor="center", style="prev.TLabel", relief="groove") self.sampletitle.grid(row=2, columnspan=2, padx=4, pady=6, ipadx=4, ipady=4, sticky="eswn") self.fonts = list(set(font.families())) self.fonts.append("TkDefaultFont") self.fonts.sort() w = max([len(f) for f in self.fonts]) self.sizes = [ "%i" % i for i in (list(range(6, 17)) + list(range(18, 32, 2))) ] self.fonttitle_family = Combobox(fonttitle_frame, values=self.fonts, width=(w * 2) // 3, exportselection=False, validate="key") self._validate_title_size = self.register( lambda *args: self.validate_font_size(self.fonttitle_size, *args)) self._validate_title_family = self.register( lambda *args: self.validate_font_family(self.fonttitle_family, * args)) self.fonttitle_family.configure( validatecommand=(self._validate_title_family, "%d", "%S", "%i", "%s", "%V")) self.fonttitle_family.current(self.fonts.index(title_family)) self.fonttitle_family.grid(row=0, column=0, padx=4, pady=4) self.fonttitle_size = Combobox( fonttitle_frame, values=self.sizes, width=5, exportselection=False, validate="key", validatecommand=(self._validate_title_size, "%d", "%P", "%V")) self.fonttitle_size.current(self.sizes.index(title_size)) self.fonttitle_size.grid(row=0, column=1, padx=4, pady=4) frame_title_style = Frame(fonttitle_frame) frame_title_style.grid(row=1, columnspan=2, padx=4, pady=6) self.is_bold = Checkbutton(frame_title_style, text=_("Bold"), command=self.update_preview_title) self.is_italic = Checkbutton(frame_title_style, text=_("Italic"), command=self.update_preview_title) self.is_underlined = Checkbutton(frame_title_style, text=_("Underline"), command=self.update_preview_title) style = CONFIG.get("Font", "title_style") if "bold" in style: self.is_bold.state(("selected", )) if "italic" in style: self.is_italic.state(("selected", )) if "underline" in style: self.is_underlined.state(("selected", )) self.is_bold.pack(side="left") self.is_italic.pack(side="left") self.is_underlined.pack(side="left") self.update_preview_title() # --- *-- text size = CONFIG.get("Font", "text_size") family = CONFIG.get("Font", "text_family") font_frame = Frame(font_settings) self.sample = Label(font_frame, text=_("Sample text"), anchor="center", style="prev.TLabel", relief="groove") self.sample.grid(row=1, columnspan=2, padx=4, pady=6, ipadx=4, ipady=4, sticky="eswn") self.font_family = Combobox(font_frame, values=self.fonts, width=(w * 2) // 3, exportselection=False, validate="key") self._validate_family = self.register( lambda *args: self.validate_font_family(self.font_family, *args)) self._validate_size = self.register( lambda *args: self.validate_font_size(self.font_size, *args)) self.font_family.configure(validatecommand=(self._validate_family, "%d", "%S", "%i", "%s", "%V")) self.font_family.current(self.fonts.index(family)) self.font_family.grid(row=0, column=0, padx=4, pady=4) self.font_size = Combobox(font_frame, values=self.sizes, width=5, exportselection=False, validate="key", validatecommand=(self._validate_size, "%d", "%P", "%V")) self.font_size.current(self.sizes.index(size)) self.font_size.grid(row=0, column=1, padx=4, pady=4) self.update_preview() # --- *-- placement Label(font_settings, text=_("Title")).grid(row=0, padx=4, pady=4, sticky="w") fonttitle_frame.grid(row=1) Separator(font_settings, orient="horizontal").grid(row=2, sticky="ew", pady=10) Label(font_settings, text=_("Text")).grid(row=3, padx=4, pady=4, sticky="w") font_frame.grid(row=4) # --- * Categories self.category_settings = CategoryManager(self.notebook, master) self.notebook.add(self.category_settings, text=_("Categories"), sticky="ewsn", padding=4) # --- * Symbols symbols_settings = Frame(self.notebook) self.notebook.add(symbols_settings, text=_("Symbols"), sticky="ewsn", padding=4) txt_frame = Frame(symbols_settings, relief="sunken", borderwidth=1, style="text.TFrame") self.symbols = Text(txt_frame, width=1, height=1, highlightthickness=0, spacing2=5, spacing1=5, relief="flat", padx=4, pady=4, font="%s %s" % (family.replace(" ", "\ "), size)) self.symbols.insert("1.0", CONFIG.get("General", "symbols")) Label(symbols_settings, text=_("Available symbols")).pack(padx=4, pady=4) txt_frame.pack(fill="both", expand=True, padx=4, pady=4) self.symbols.pack(fill="both", expand=True) Button(symbols_settings, text=_('Reset'), command=self.reset_symbols).pack(padx=4, pady=4) # --- Ok/Cancel buttons Button(okcancel_frame, text="Ok", command=self.ok).grid(row=1, column=0, padx=4, pady=10, sticky="e") Button(okcancel_frame, text=_("Cancel"), command=self.destroy).grid(row=1, column=1, padx=4, pady=10, sticky="w") # --- bindings self.font_family.bind('<<ComboboxSelected>>', self.update_preview) self.font_family.bind('<Return>', self.update_preview) self.font_size.bind('<<ComboboxSelected>>', self.update_preview, add=True) self.font_size.bind('<Return>', self.update_preview, add=True) self.fonttitle_family.bind('<<ComboboxSelected>>', self.update_preview_title) self.fonttitle_size.bind('<<ComboboxSelected>>', self.update_preview_title, add=True) self.fonttitle_family.bind('<Return>', self.update_preview_title) self.fonttitle_size.bind('<Return>', self.update_preview_title, add=True)
def initialize(self): self.master.title("NENR DZ5 - Miljenko Šuflaj") self.pack(fill="both", expand=True) notebook = Notebook(self) notebook.pack() record_gestures_frame = Frame(self) classify_gestures_frame = Frame(self) notebook.add(record_gestures_frame, text="Zabilježi geste") notebook.add(classify_gestures_frame, text="Klasificiraj geste") notebook.enable_traversal() notebook.select(record_gestures_frame) gesture_classification_frame = Frame(classify_gestures_frame) gesture_record_frame_2 = Frame(classify_gestures_frame) gesture_classification_frame.pack(side="top", fill="x", expand=True) gesture_record_frame_2.pack(fill="both") # region Record gesture tab gesture_info_frame = Frame(record_gestures_frame) gesture_record_frame = Frame(record_gestures_frame) gesture_end_frame = Frame(record_gestures_frame) gesture_info_frame.pack(side="top", fill="x") gesture_record_frame.pack(fill="both") gesture_end_frame.pack(side="bottom", fill="x") gesture_name_menu = Menubutton(gesture_info_frame, text="Odaberi gestu za bilježenje...") gesture_name_menu.menu = Menu(gesture_name_menu, tearoff=0) gesture_name_menu["menu"] = gesture_name_menu.menu for i, label in enumerate(GestureWindow.labels): gesture_name_menu.menu.add_command(label=label, command=self.switch_record(i)) self.__recorded_gesture_label = Label(gesture_info_frame) gesture_record_canvas = Canvas(gesture_record_frame, width=700, height=475, bg="white") gesture_record_canvas.current_coords = None gesture_record_canvas.records = list() gesture_record_save_button = Button(gesture_end_frame, text="Pohrani u .tsv", command=self.save_data) gesture_record_delete_button = Button(gesture_end_frame, text="Zaboravi učitane podatke", command=self.delete_internal) gesture_name_menu.pack(side="left", fill="x", padx=5, pady=5, expand=True) self.__recorded_gesture_label.pack(side="left", fill="x", padx=5, pady=5) gesture_record_canvas.pack(fill="both", padx=5, pady=5, expand=True) gesture_record_delete_button.pack(side="left", fill="x", padx=5, pady=5) gesture_record_save_button.pack(side="right", fill="x", padx=5, pady=5) self.switch_record(self.__recorded_gesture_index)() # endregion # region Classify gesture tab gesture_classification_frame = Frame(classify_gestures_frame) gesture_record_frame_2 = Frame(classify_gestures_frame) gesture_classification_frame.pack(side="top", fill="x", expand=True) gesture_record_frame_2.pack(fill="both") classification_labels = list() self.__classification_outputs = list() for category in GestureWindow.labels: classification_labels.append( Label(gesture_classification_frame, text=category)) self.__classification_outputs.append( Label(gesture_classification_frame, text=f"{0.:.01f}%", font=("helvetica", 8))) classification_blank = Label(gesture_classification_frame) classification_labels[-1].pack(side="left", fill="x", padx=5, pady=5) self.__classification_outputs[-1].pack(side="left", fill="x", padx=5, pady=5) classification_blank.pack(side="left", fill="x", padx=50, pady=5) gesture_record_canvas_2 = Canvas(gesture_record_frame_2, width=700, height=525, bg="white") gesture_record_canvas_2.current_coords = None gesture_record_canvas_2.records = list() gesture_record_canvas_2.pack(side="left", fill="both", padx=5, pady=5, expand=True) # endregion # region Functionality for record_canvas in [gesture_record_canvas, gesture_record_canvas_2]: draw_function = self.get_draw_on_canvas_function(record_canvas) record_canvas.bind("<B1-Motion>", draw_function) record_canvas.bind("<ButtonRelease-1>", draw_function) self.__root_window.bind( "<BackSpace>", self.get_delete_currently_drawn(gesture_record_canvas)) self.__root_window.bind( "<Return>", self.get_record_gesture_function(gesture_record_canvas)) gesture_record_canvas_2.bind( "<Leave>", self.get_evaluate_gesture_function(gesture_record_canvas_2)) self.__root_window.bind( "<Delete>", self.get_delete_currently_drawn(gesture_record_canvas_2))
class ExpCheckGUI(Tk): def __init__(self, data_manager): super().__init__() self.data_manager = data_manager self.searching = False self.good_chars = printable[:-5] + '\x08' self.add_gui = AddFoodGUI(self) self.init_gui() def init_gui(self): """ Initializes all widgets for the main screen and calls grid_widgets() to place them """ self.title("exp_check") self.config(bg='black') style = Style() style.configure("TMenubutton", foreground="white", background="black") # setup widgets self.add_button = Button(self, text="Add Food", **widget_options, command=self.add_food) self.delete_button = Button(self, text="Delete Food", **widget_options, command=self.delete_food) self.search_box = Entry(self, **widget_options, insertbackground='white') self.search_box.bind("<Key>", self.search) self.data_display = DataDisplay(widget_options) vals = self.data_manager.get_keylist() vals.insert(0, 'name') menu1 = Menu(tearoff=0) menu1.add('radiobutton', label=vals[0], command=lambda: self.update_data_display(sort_key=vals[0])) menu1.add('radiobutton', label=vals[1], command=lambda: self.update_data_display(sort_key=vals[1])) menu1.add('radiobutton', label=vals[2], command=lambda: self.update_data_display(sort_key=vals[2])) self.sort_menu = Menubutton(self, text='sort by', menu=menu1, style="TMenubutton") search_icon = self.generate_icon_object("./data/search_icon.png", (20, 20)) self.search_label = Label(image=search_icon, **widget_options) self.search_label.image = search_icon # setup message box dialog self.message = Label(self, text='', **widget_options) self.okay_button = Button( self, text=" OK ", **widget_options, command=lambda: self.okay_button_press(self.cur_instance)) self.grid_widgets() def grid_widgets(self): """ Places initialized widgets on screen """ self.title("exp_check") self.cur_instance = self self.columnconfigure(0, weight=1) self.columnconfigure(1, weight=1) self.rowconfigure(2, weight=1) grid_options = {"padx": 3, "pady": 3} self.add_button.grid(row=0, column=0, **grid_options) self.delete_button.grid(row=0, column=1, **grid_options) self.data_display.grid(row=2, column=0, **grid_options, columnspan=6, sticky=N + S + E + W) self.search_label.grid(row=0, column=3) self.search_box.grid(row=0, column=4, **grid_options) self.sort_menu.grid(row=0, column=5, **grid_options) self.update_data_display() def generate_icon_object(self, path, size): """ Initializes the an icon with @param path so it is ready to be placed inside a label widget to be placed on screen """ image = Image.open(path) image.convert("RGBA") image.thumbnail(size, Image.ANTIALIAS) return ImageTk.PhotoImage(image) def update_data_display(self, event=None, sort_key='name', key_list=None, search_string=None): """ Synchronizes the data display with the database from the data manager """ if key_list is None: key_list = self.data_manager.get_keylist() self.data_display.delete(0, END) for item in self.data_manager.get_database(key_list=key_list, sort_key=sort_key): item_str = "{} {} {}".format(*item) if search_string is None or\ search_string in item_str.lower(): item[1] = format_string.format(item[1]) item[2] = format_string.format(item[2]) self.data_display.insert(END, item) def search(self, event=None): """ Updates the data display with whatever is in the search box. Will run any time a key is pressed while focused on the search box. """ search_string = self.search_box.get() if event is None or event.char not in self.good_chars: newchar = "" elif event.char == '\x08': search_string = search_string[:-1] newchar = "" else: newchar = event.char search_string += newchar search_string = search_string.lower() self.update_data_display(search_string=search_string) def un_grid_widgets(self, event=None): """ Removes all the current widgets """ self.add_button.grid_forget() self.delete_button.grid_forget() self.data_display.grid_forget() self.search_label.grid_forget() self.search_box.grid_forget() self.sort_menu.grid_forget() def add_food(self, event=None): """ Removes all the current widgets and draws draws the add_food_gui widgets on the window. """ self.un_grid_widgets() self.add_gui.grid_widgets() def delete_food(self, event=None): """ Selects and deletes a food from the database by calling the data manager """ selection = self.data_display.get(ACTIVE).split() if not selection: return name = ' '.join( selection[0:-2]) if len(selection) > 3 else selection[0] msg = self.data_manager.delete_entry(name) if msg is not None: self.msg_box_init(self, msg) return self.update_data_display() def msg_box_init(self, instance, msg='a message'): """ Creates a message box after deleting all removing all widgets from the screen """ instance.un_grid_widgets() self.message['text'] = msg self.message.grid(row=0, column=0) self.okay_button.grid(row=1, column=0) def okay_button_press(self, instance, event=None): """ On pressing the okay button, replaces all changed widgets """ self.message.grid_forget() self.okay_button.grid_forget() instance.grid_widgets()
def __init__(self, master, note_data): """Create export dialog.""" Toplevel.__init__(self, master, class_='MyNotes') self.title(_("Export")) self.minsize(350, 250) self.grab_set() self.columnconfigure(0, weight=1) self.rowconfigure(3, weight=1) self.note_data = note_data self.categories = CONFIG.options("Categories") self.categories.sort() self.notes_to_export = [] self.export_type = None self.export_data = False # export type self.type = StringVar(self, _("Notes (.notes)")) type_frame = Frame(self) menu_type = Menu(self, tearoff=False) for etype in EXT_DICT: menu_type.add_radiobutton(label=etype, value=etype, variable=self.type) mb = Menubutton(type_frame, menu=menu_type, textvariable=self.type, width=max([int(len(key) * 0.8) for key in EXT_DICT])) Label(type_frame, text=_('Export to')).pack(side='left', padx=4) mb.pack(side='left', padx=4) type_frame.grid(row=0, columnspan=2, sticky='w', pady=4) Separator(self).grid(columnspan=2, sticky="ew", padx=4, pady=4) # export only visible notes checkbutton self.ch_only_visible = Checkbutton(self, text=_("Only visible notes"), command=self.select_only_visible) self.ch_only_visible.grid(columnspan=2, sticky="w", padx=4, pady=4) # note selection self.tree = CheckboxTreeview(self, show='tree') self.tree.grid(row=3, sticky="nsew", padx=4, pady=4) scroll = Scrollbar(self, orient='vertical', command=self.tree.yview) self.tree.configure(yscrollcommand=scroll.set) scroll.grid(row=3, column=1, sticky='ns') self.tree.insert('', 'end', 'root', text=_('Categories')) for cat in self.categories: self.tree.insert('root', 'end', cat, text=cat.capitalize()) for key, data in self.note_data.items(): self.tree.insert(data['category'], 'end', key, text='{} - {}'.format(data['title'], data.get('date', '??')), tags=['visible'] if data['visible'] else []) for cat in self.categories: if not self.tree.get_children(cat): self.tree.detach(cat) self.tree.bind('<<Checked>>', self.toggle_select_visible) self.tree.bind('<<Unchecked>>', self.toggle_select_visible) Separator(self).grid(sticky="ew", columnspan=2, padx=4, pady=4) self.ch_export_data = Checkbutton(self, text=_('Export data (pictures and linked files)')) self.ch_export_data.grid(sticky="w", columnspan=2, padx=4, pady=4) frame = Frame(self) frame.grid(columnspan=2) Button(frame, text="Ok", command=self.ok).grid(row=0, column=0, sticky="w", padx=4, pady=4) Button(frame, text=_("Cancel"), command=self.destroy).grid(row=0, column=1, sticky="e", padx=4, pady=4) self.tree.check_item('root') self.tree.expand_all() self.toggle_select_visible()
def create_content(self, **kw): self.minsize(190, 190) self.on = False # is the timer on? if not CONFIG.options("Tasks"): CONFIG.set("Tasks", _("Work"), CMAP[0]) self._stats = None # --- colors self.background = { _("Work"): CONFIG.get("Pomodoro", "work_bg"), _("Break"): CONFIG.get("Pomodoro", "break_bg"), _("Rest"): CONFIG.get("Pomodoro", "rest_bg") } self.foreground = { _("Work"): CONFIG.get("Pomodoro", "work_fg"), _("Break"): CONFIG.get("Pomodoro", "break_fg"), _("Rest"): CONFIG.get("Pomodoro", "rest_fg") } self.rowconfigure(1, weight=1) self.columnconfigure(0, weight=1) self.columnconfigure(1, weight=1) # nombre de séquence de travail effectuées d'affilée (pour # faire des pauses plus longues tous les 4 cycles) self.nb_cycles = 0 self.pomodori = IntVar(self, 0) # --- images self.im_go = PhotoImage(master=self, file=IM_START) self.im_stop = PhotoImage(master=self, file=IM_STOP) self.im_tomate = PhotoImage(master=self, file=IM_POMODORO) self.im_graph = PhotoImage(master=self, file=IM_GRAPH) # --- tasks list tasks_frame = Frame(self, style='pomodoro.TFrame') tasks_frame.grid(row=3, column=0, columnspan=3, sticky="wnse") tasks = [t.capitalize() for t in CONFIG.options("PomodoroTasks")] tasks.sort() self.task = StringVar(self, tasks[0]) self.menu_tasks = Menu(tasks_frame, relief='sunken', activeborderwidth=0) self.choose_task = Menubutton(tasks_frame, textvariable=self.task, menu=self.menu_tasks, style='pomodoro.TMenubutton') Label(tasks_frame, text=_("Task: "), style='pomodoro.TLabel', font="TkDefaultFont 12", width=6, anchor="e").pack(side="left", padx=4) self.choose_task.pack(side="right", fill="x", pady=4) # --- display self.tps = [CONFIG.getint("Pomodoro", "work_time"), 0] # time: min, sec self.activite = StringVar(self, _("Work")) self.titre = Label(self, textvariable=self.activite, font='TkDefaultFont 14', style='timer.pomodoro.TLabel', anchor="center") self.titre.grid(row=0, column=0, columnspan=2, sticky="we", pady=(4, 0), padx=4) self.temps = Label(self, text="{0:02}:{1:02}".format(self.tps[0], self.tps[1]), style='timer.pomodoro.TLabel', anchor="center") self.temps.grid(row=1, column=0, columnspan=2, sticky="nswe", padx=4) self.aff_pomodori = Label(self, textvariable=self.pomodori, anchor='e', padding=(20, 4, 20, 4), image=self.im_tomate, compound="left", style='timer.pomodoro.TLabel', font='TkDefaultFont 14') self.aff_pomodori.grid(row=2, columnspan=2, sticky="ew", padx=4) # --- buttons self.b_go = Button(self, image=self.im_go, command=self.go, style='pomodoro.TButton') self.b_go.grid(row=4, column=0, sticky="ew") self.b_stats = Button(self, image=self.im_graph, command=self.display_stats, style='pomodoro.TButton') self.b_stats.grid(row=4, column=1, sticky="ew") self._corner = Sizegrip(self, style="pomodoro.TSizegrip") self._corner.place(relx=1, rely=1, anchor='se') # --- bindings self.bind('<3>', lambda e: self.menu.tk_popup(e.x_root, e.y_root)) tasks_frame.bind('<ButtonPress-1>', self._start_move) tasks_frame.bind('<ButtonRelease-1>', self._stop_move) tasks_frame.bind('<B1-Motion>', self._move) self.titre.bind('<ButtonPress-1>', self._start_move) self.titre.bind('<ButtonRelease-1>', self._stop_move) self.titre.bind('<B1-Motion>', self._move) self.temps.bind('<ButtonPress-1>', self._start_move) self.temps.bind('<ButtonRelease-1>', self._stop_move) self.temps.bind('<B1-Motion>', self._move) self.b_stats.bind('<Enter>', self._on_enter) self.b_stats.bind('<Leave>', self._on_leave)
class Pomodoro(BaseWidget): """ Chronometre de temps de travail pour plus d'efficacité """ def __init__(self, master): BaseWidget.__init__(self, 'Pomodoro', master) def create_content(self, **kw): self.minsize(190, 190) self.on = False # is the timer on? if not CONFIG.options("Tasks"): CONFIG.set("Tasks", _("Work"), CMAP[0]) self._stats = None # --- colors self.background = { _("Work"): CONFIG.get("Pomodoro", "work_bg"), _("Break"): CONFIG.get("Pomodoro", "break_bg"), _("Rest"): CONFIG.get("Pomodoro", "rest_bg") } self.foreground = { _("Work"): CONFIG.get("Pomodoro", "work_fg"), _("Break"): CONFIG.get("Pomodoro", "break_fg"), _("Rest"): CONFIG.get("Pomodoro", "rest_fg") } self.rowconfigure(1, weight=1) self.columnconfigure(0, weight=1) self.columnconfigure(1, weight=1) # nombre de séquence de travail effectuées d'affilée (pour # faire des pauses plus longues tous les 4 cycles) self.nb_cycles = 0 self.pomodori = IntVar(self, 0) # --- images self.im_go = PhotoImage(master=self, file=IM_START) self.im_stop = PhotoImage(master=self, file=IM_STOP) self.im_tomate = PhotoImage(master=self, file=IM_POMODORO) self.im_graph = PhotoImage(master=self, file=IM_GRAPH) # --- tasks list tasks_frame = Frame(self, style='pomodoro.TFrame') tasks_frame.grid(row=3, column=0, columnspan=3, sticky="wnse") tasks = [t.capitalize() for t in CONFIG.options("PomodoroTasks")] tasks.sort() self.task = StringVar(self, tasks[0]) self.menu_tasks = Menu(tasks_frame, relief='sunken', activeborderwidth=0) self.choose_task = Menubutton(tasks_frame, textvariable=self.task, menu=self.menu_tasks, style='pomodoro.TMenubutton') Label(tasks_frame, text=_("Task: "), style='pomodoro.TLabel', font="TkDefaultFont 12", width=6, anchor="e").pack(side="left", padx=4) self.choose_task.pack(side="right", fill="x", pady=4) # --- display self.tps = [CONFIG.getint("Pomodoro", "work_time"), 0] # time: min, sec self.activite = StringVar(self, _("Work")) self.titre = Label(self, textvariable=self.activite, font='TkDefaultFont 14', style='timer.pomodoro.TLabel', anchor="center") self.titre.grid(row=0, column=0, columnspan=2, sticky="we", pady=(4, 0), padx=4) self.temps = Label(self, text="{0:02}:{1:02}".format(self.tps[0], self.tps[1]), style='timer.pomodoro.TLabel', anchor="center") self.temps.grid(row=1, column=0, columnspan=2, sticky="nswe", padx=4) self.aff_pomodori = Label(self, textvariable=self.pomodori, anchor='e', padding=(20, 4, 20, 4), image=self.im_tomate, compound="left", style='timer.pomodoro.TLabel', font='TkDefaultFont 14') self.aff_pomodori.grid(row=2, columnspan=2, sticky="ew", padx=4) # --- buttons self.b_go = Button(self, image=self.im_go, command=self.go, style='pomodoro.TButton') self.b_go.grid(row=4, column=0, sticky="ew") self.b_stats = Button(self, image=self.im_graph, command=self.display_stats, style='pomodoro.TButton') self.b_stats.grid(row=4, column=1, sticky="ew") self._corner = Sizegrip(self, style="pomodoro.TSizegrip") self._corner.place(relx=1, rely=1, anchor='se') # --- bindings self.bind('<3>', lambda e: self.menu.tk_popup(e.x_root, e.y_root)) tasks_frame.bind('<ButtonPress-1>', self._start_move) tasks_frame.bind('<ButtonRelease-1>', self._stop_move) tasks_frame.bind('<B1-Motion>', self._move) self.titre.bind('<ButtonPress-1>', self._start_move) self.titre.bind('<ButtonRelease-1>', self._stop_move) self.titre.bind('<B1-Motion>', self._move) self.temps.bind('<ButtonPress-1>', self._start_move) self.temps.bind('<ButtonRelease-1>', self._stop_move) self.temps.bind('<B1-Motion>', self._move) self.b_stats.bind('<Enter>', self._on_enter) self.b_stats.bind('<Leave>', self._on_leave) def update_style(self): self.menu_tasks.delete(0, 'end') tasks = [t.capitalize() for t in CONFIG.options('PomodoroTasks')] tasks.sort() for task in tasks: self.menu_tasks.add_radiobutton(label=task, value=task, variable=self.task) if self.task.get() not in tasks: self.stop(False) self.task.set(tasks[0]) self.attributes('-alpha', CONFIG.get(self.name, 'alpha', fallback=0.85)) bg = CONFIG.get('Pomodoro', 'background') fg = CONFIG.get('Pomodoro', 'foreground') active_bg = active_color(*self.winfo_rgb(bg)) self.style.configure('pomodoro.TMenubutton', background=bg, relief='flat', foreground=fg, borderwidth=0, arrowcolor=fg) self.style.configure('pomodoro.TButton', background=bg, relief='flat', foreground=fg, borderwidth=0) self.style.configure('pomodoro.TLabel', background=bg, foreground=fg) self.style.configure('pomodoro.TFrame', background=bg) self.style.configure('pomodoro.TSizegrip', background=bg) self.style.map('pomodoro.TSizegrip', background=[('active', active_bg)]) self.style.map('pomodoro.TButton', background=[('disabled', bg), ('!disabled', 'active', active_bg)]) self.style.map('pomodoro.TMenubutton', background=[('disabled', bg), ('!disabled', 'active', active_bg)]) self.configure(bg=bg) self.menu.configure(bg=bg, fg=fg, selectcolor=fg, activeforeground=fg, activebackground=active_bg) self.menu_pos.configure(bg=bg, fg=fg, selectcolor=fg, activeforeground=fg, activebackground=active_bg) self.menu_tasks.configure(bg=bg, activebackground=active_bg, fg=fg, selectcolor=fg, activeforeground=fg) self.background = { _("Work"): CONFIG.get("Pomodoro", "work_bg"), _("Break"): CONFIG.get("Pomodoro", "break_bg"), _("Rest"): CONFIG.get("Pomodoro", "rest_bg") } self.foreground = { _("Work"): CONFIG.get("Pomodoro", "work_fg"), _("Break"): CONFIG.get("Pomodoro", "break_fg"), _("Rest"): CONFIG.get("Pomodoro", "rest_fg") } act = self.activite.get() self.style.configure('timer.pomodoro.TLabel', font=CONFIG.get("Pomodoro", "font"), foreground=self.foreground[act], background=self.background[act]) def _on_enter(self, event=None): self._corner.state(('active', )) def _on_leave(self, event=None): self._corner.state(('!active', )) def _start_move(self, event): self.x = event.x self.y = event.y def _stop_move(self, event): self.x = None self.y = None self.configure(cursor='arrow') def _move(self, event): if self.x is not None and self.y is not None: self.configure(cursor='fleur') 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 hide(self): if self._stats is not None: self._stats.destroy() BaseWidget.hide(self) def stats(self, time=None): """Save stats.""" if time is None: time = CONFIG.getint("Pomodoro", "work_time") today = dt.date.today().toordinal() task = self.task.get().lower().replace(' ', '_') db = sqlite3.connect(PATH_STATS) cursor = db.cursor() try: cursor.execute('SELECT * FROM {} ORDER BY id DESC LIMIT 1'.format( scrub(task))) key, date, work = cursor.fetchone() except sqlite3.OperationalError: cursor.execute('''CREATE TABLE {} (id INTEGER PRIMARY KEY, date INTEGER, work INTEGER)'''.format( scrub(task))) cursor.execute( 'INSERT INTO {}(date, work) VALUES (?, ?)'.format(scrub(task)), (today, time)) else: if today != date: cursor.execute( 'INSERT INTO {}(date, work) VALUES (?, ?)'.format( scrub(task)), (today, time)) else: # update day's value cursor.execute( 'UPDATE {} SET work=? WHERE id=?'.format(scrub(task)), (work + time, key)) finally: db.commit() db.close() def display_stats(self): """ affiche les statistiques """ if self._stats is None: self._stats = Stats(self) self._stats.bind('<Destroy>', self._on_close_stats) else: self._stats.lift() def _on_close_stats(self, event): self._stats = None def go(self): if self.on: self.stop() else: self.on = True self.choose_task.state(["disabled"]) self.b_go.configure(image=self.im_stop) self.after(1000, self.affiche) logging.info('Start work cycle for task ' + self.task.get()) def stop(self, confirmation=True): """ Arrête le décompte du temps et le réinitialise, demande une confirmation avant de le faire si confirmation=True """ tps = int( CONFIG.getint("Pomodoro", "work_time") - self.tps[0] - self.tps[1] / 60) self.on = False rep = True if confirmation: rep = askyesno( title=_("Confirmation"), message=_( "Are you sure you want to give up the current session?")) if rep: self.choose_task.state(["!disabled"]) self.b_go.configure(image=self.im_go) if self.activite.get() == _("Work"): self.stats(tps) self.pomodori.set(0) self.nb_cycles = 0 self.tps = [CONFIG.getint("Pomodoro", "work_time"), 0] self.temps.configure( text="{0:02}:{1:02}".format(self.tps[0], self.tps[1])) act = _("Work") self.activite.set(act) self.style.configure('timer.pomodoro.TLabel', background=self.background[act], foreground=self.foreground[act]) logging.info('Pomodoro session interrupted.') else: self.on = True self.affiche() return rep @staticmethod def ting(): """ joue le son marquant le changement de période """ if not CONFIG.getboolean("Pomodoro", "mute", fallback=False): Popen([ CONFIG.get("General", "soundplayer"), CONFIG.get("Pomodoro", "beep") ]) def affiche(self): if self.on: self.tps[1] -= 1 if self.tps[1] == 0: if self.tps[0] == 0: self.ting() if self.activite.get() == _("Work"): self.pomodori.set(self.pomodori.get() + 1) self.nb_cycles += 1 self.choose_task.state(["!disabled"]) logging.info( 'Pomodoro: completed work session for task ' + self.task.get()) if self.nb_cycles % 4 == 0: # pause longue self.stats() self.activite.set(_("Rest")) self.tps = [ CONFIG.getint("Pomodoro", "rest_time"), 0 ] else: # pause courte self.stats() self.activite.set(_("Break")) self.tps = [ CONFIG.getint("Pomodoro", "break_time"), 0 ] else: self.choose_task.state(["disabled"]) self.activite.set(_("Work")) self.tps = [CONFIG.getint("Pomodoro", "work_time"), 0] act = self.activite.get() self.style.configure('timer.pomodoro.TLabel', background=self.background[act], foreground=self.foreground[act]) elif self.tps[1] == -1: self.tps[0] -= 1 self.tps[1] = 59 self.temps.configure(text="{0:02}:{1:02}".format(*self.tps)) self.after(1000, self.affiche)
def _init_general(self): frame_general = Frame(self) self.notebook.add(frame_general, text=_("General")) # --- Language Label(frame_general, text=_("Language")).grid(row=0, column=0, padx=8, pady=4, sticky="e") menu_lang = Menu(frame_general, tearoff=False, background=self._bg) mb = Menubutton(frame_general, menu=menu_lang, textvariable=self.lang) mb.grid(row=0, column=1, padx=8, pady=4, sticky="w") for lang in LANGUAGES: language = LANGUAGES[lang] menu_lang.add_radiobutton(label=language, value=language, variable=self.lang, command=self.translate) # --- gui toolkit Label(frame_general, text=_("GUI Toolkit for the system tray icon")).grid(row=2, column=0, padx=8, pady=4, sticky="e") menu_gui = Menu(frame_general, tearoff=False, background=self._bg) Menubutton(frame_general, menu=menu_gui, width=9, textvariable=self.gui).grid(row=2, column=1, padx=8, pady=4, sticky="w") for toolkit, b in TOOLKITS.items(): if b: menu_gui.add_radiobutton(label=toolkit.capitalize(), value=toolkit.capitalize(), variable=self.gui, command=self.change_gui) # --- Update delay Label(frame_general, text=_("Feed update delay (min)")).grid(row=4, column=0, padx=8, pady=4, sticky="e") self.entry_delay = Entry(frame_general, width=10, justify='center', validate='key', validatecommand=(self._validate, '%P')) self.entry_delay.grid(row=4, column=1, padx=8, pady=4, sticky='w') self.entry_delay.insert( 0, CONFIG.getint('General', 'update_delay') // 60000) # --- image loading timeout Label(frame_general, text=_("Image loading timeout (s)")).grid(row=5, column=0, padx=8, pady=4, sticky="e") self.entry_timeout = Entry(frame_general, width=10, justify='center', validate='key', validatecommand=(self._validate, '%P')) self.entry_timeout.grid(row=5, column=1, padx=8, pady=4, sticky='w') self.entry_timeout.insert( 0, CONFIG.getint('General', 'img_timeout', fallback=10)) # --- Notifications self.notifications = Checkbutton(frame_general, text=_("Activate notifications")) self.notifications.grid(row=6, column=0, padx=8, pady=4, columnspan=2, sticky='w') if CONFIG.getboolean('General', 'notifications', fallback=True): self.notifications.state(('selected', '!alternate')) else: self.notifications.state(('!selected', '!alternate')) # --- Confirm remove feed self.confirm_feed_rem = Checkbutton( frame_general, text=_("Show confirmation dialog before removing feed")) self.confirm_feed_rem.grid(row=7, column=0, padx=8, pady=4, columnspan=2, sticky='w') if CONFIG.getboolean('General', 'confirm_feed_remove', fallback=True): self.confirm_feed_rem.state(('selected', '!alternate')) else: self.confirm_feed_rem.state(('!selected', '!alternate')) # --- Confirm remove cat self.confirm_cat_rem = Checkbutton( frame_general, text=_("Show confirmation dialog before removing category")) self.confirm_cat_rem.grid(row=8, column=0, padx=8, pady=4, columnspan=2, sticky='w') if CONFIG.getboolean('General', 'confirm_cat_remove', fallback=True): self.confirm_cat_rem.state(('selected', '!alternate')) else: self.confirm_cat_rem.state(('!selected', '!alternate')) # --- Confirm update self.confirm_update = Checkbutton( frame_general, text=_("Check for updates on start-up")) self.confirm_update.grid(row=9, column=0, padx=8, pady=4, columnspan=2, sticky='w') if CONFIG.getboolean('General', 'check_update', fallback=True): self.confirm_update.state(('selected', '!alternate')) else: self.confirm_update.state(('!selected', '!alternate')) # --- Splash supported self.splash_support = Checkbutton( frame_general, text=_("Check this box if the widgets disappear when you click")) self.splash_support.grid(row=10, column=0, padx=8, pady=4, columnspan=2, sticky='w') if not CONFIG.getboolean('General', 'splash_supported', fallback=True): self.splash_support.state(('selected', '!alternate')) else: self.splash_support.state(('!selected', '!alternate'))
def _init_general(self): general_settings = Frame(self.notebook, padding=4) general_settings.columnconfigure(0, weight=1) self.notebook.add(general_settings, text=_("General"), sticky="ewsn", padding=4) # ---- language self.lang = StringVar(self, LANGUAGES[CONFIG.get("General", "language")]) lang_frame = Frame(general_settings) Label(lang_frame, text=_("Language")).grid(row=0, sticky="w", padx=4, pady=4) menu_lang = Menu(lang_frame, tearoff=False) Menubutton(lang_frame, menu=menu_lang, width=9, textvariable=self.lang).grid(row=0, column=1, padx=8, pady=4) for lang in LANGUAGES.values(): menu_lang.add_radiobutton(variable=self.lang, label=lang, value=lang, command=self.translate) # ---- gui toolkit self.gui = StringVar(self, CONFIG.get("General", "trayicon").capitalize()) gui_frame = Frame(general_settings) Label(gui_frame, text=_("GUI Toolkit for the system tray icon")).grid(row=0, column=0, padx=4, pady=4, sticky="w") menu_gui = Menu(gui_frame, tearoff=False) Menubutton(gui_frame, menu=menu_gui, width=9, textvariable=self.gui).grid(row=0, column=1, padx=4, pady=4, sticky="w") for toolkit, b in TOOLKITS.items(): if b: menu_gui.add_radiobutton(label=toolkit.capitalize(), value=toolkit.capitalize(), variable=self.gui, command=self.change_gui) # ---- opacity self.opacity = OpacityFrame(general_settings, CONFIG.getint("General", "opacity")) # ---- position frame_position = Frame(general_settings) self.position = StringVar(self, CONFIG.get("General", "position")) Label(frame_position, text=_("Default position of the notes")).grid(row=0, columnspan=3, sticky="w", padx=4, pady=4) Radiobutton(frame_position, text=_("Always above"), value="above", variable=self.position).grid(row=1, column=0, padx=4) Radiobutton(frame_position, text=_("Always below"), value="below", variable=self.position).grid(row=1, column=1, padx=4) Radiobutton(frame_position, text=_("Normal"), value="normal", variable=self.position).grid(row=1, column=2, padx=4) # ---- titlebar self.titlebar_disposition = StringVar( self, CONFIG.get("General", "buttons_position")) self.title_var = StringVar( self) # to add date if date_in_title is true 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) frame_titlebar = Frame(general_settings) frame_titlebar.columnconfigure(1, weight=1) frame_titlebar.columnconfigure(3, weight=1) Label(frame_titlebar, text=_("Title bar disposition")).grid(row=0, columnspan=4, sticky="w", padx=4, pady=4) Radiobutton(frame_titlebar, value="right", variable=self.titlebar_disposition).grid(row=1, column=0, padx=4) right = Frame(frame_titlebar, style="titlebar.TFrame") right.grid(row=1, column=1, sticky="ew", padx=4) def select_right(event): self.titlebar_disposition.set("right") Label(right, textvariable=self.title_var, style="titlebar.TLabel", anchor="center", font=font_title).pack(side="left", fill="x", expand=True) Label(right, image="img_close", style="titlebar.TLabel").pack(side="right") Label(right, image="img_roll", style="titlebar.TLabel").pack(side="right") for ch in right.children.values(): ch.bind("<Button-1>", select_right) Radiobutton(frame_titlebar, value="left", variable=self.titlebar_disposition).grid(row=1, column=2) left = Frame(frame_titlebar, style="titlebar.TFrame") left.grid(row=1, column=3, sticky="ew") def select_left(event): self.titlebar_disposition.set("left") Label(left, image="img_close", style="titlebar.TLabel").pack(side="left") Label(left, image="img_roll", style="titlebar.TLabel").pack(side="left") Label(left, textvariable=self.title_var, style="titlebar.TLabel", anchor="center", font=font_title).pack(side="right", fill="x", expand=True) for ch in left.children.values(): ch.bind("<Button-1>", select_left) self.date_in_title = BooleanVar( self, CONFIG.getboolean('General', 'date_in_title', fallback=True)) date_in_title = Checkbutton(frame_titlebar, variable=self.date_in_title, text=_('Display creation date in title'), command=self.toggle_date) date_in_title.grid(row=2, columnspan=4, sticky='w', pady=4, padx=4) self.toggle_date() # ---- placement lang_frame.grid(sticky="w") Separator(general_settings, orient="horizontal").grid(sticky="ew", pady=10) gui_frame.grid(sticky="w") Separator(general_settings, orient="horizontal").grid(sticky="ew", pady=10) # opacity_frame.grid(sticky='w') self.opacity.grid(sticky='w', padx=4) Separator(general_settings, orient="horizontal").grid(sticky="ew", pady=10) frame_position.grid(sticky="ew") Separator(general_settings, orient="horizontal").grid(sticky="ew", pady=10) frame_titlebar.grid(sticky="ew", pady=4) # ---- clean local data Separator(general_settings, orient="horizontal").grid(sticky="ew", pady=10) Button(general_settings, text=_('Delete unused local data'), command=self.cleanup).grid(padx=4, pady=4, sticky='w') # ---- splash supported Separator(general_settings, orient="horizontal").grid(sticky="ew", pady=10) self.splash_support = Checkbutton( general_settings, text=_("Check this box if the notes disappear when you click")) self.splash_support.grid(padx=4, pady=4, sticky='w') if not CONFIG.getboolean('General', 'splash_supported', fallback=True): self.splash_support.state(('selected', '!alternate')) else: self.splash_support.state(('!selected', '!alternate'))
def __init__(self, master): """Create note manager to easily delete multiple notes.""" Toplevel.__init__(self, master, class_='MyNotes') self.title(_("Note Manager")) self.minsize(width=546, height=200) self.grab_set() categories = CONFIG.options("Categories") categories.sort() self.im_del = PhotoImage(file=IM_DELETE, master=self) self.im_change = PhotoImage(file=IM_CHANGE, master=self) self.im_visible = PhotoImage(file=IM_VISIBLE_24, master=self) self.im_hidden = PhotoImage(file=IM_HIDDEN_24, master=self) tooltipwrapper = TooltipWrapper(self) self.notebook = Notebook(self) self.notebook.pack(fill='both', expand=True) self.texts = {} self.frames = {} self.notes = {} # to change notes category menu_cat = Menu(self, tearoff=False) self.category = StringVar(self) # create one tab per category for cat in categories: menu_cat.add_radiobutton(label=cat.capitalize(), value=cat, variable=self.category, command=self.change_cat_selection) self.notes[cat] = {} frame = Frame(self.notebook, padding=2) self.texts[cat] = Text(frame, width=1, height=1, bg=self.cget('bg'), relief='flat', highlightthickness=0, padx=0, pady=0, cursor='arrow') frame.columnconfigure(0, weight=1) frame.rowconfigure(1, weight=1) self.texts[cat].grid(row=1, column=0, sticky='ewsn') scrolly = Scrollbar(frame, orient='vertical', command=self.texts[cat].yview) scrolly.grid(row=1, column=1, sticky='ns', pady=(2, 0)) scrollx = Scrollbar(frame, orient='horizontal', command=self.texts[cat].xview) scrollx.grid(row=2, column=0, sticky='ew') self.texts[cat].configure(xscrollcommand=scrollx.set, yscrollcommand=scrolly.set) self.frames[cat] = Frame(self.texts[cat], style='bg.TFrame', padding=1, height=29, width=523) self.frames[cat].columnconfigure(0, weight=1, minsize=170) headings = Frame(frame, padding=(1, 0, 1, 0)) headings.columnconfigure(0, weight=0, minsize=20) headings.columnconfigure(1, weight=1, minsize=198) headings.columnconfigure(2, weight=1, minsize=198) headings.columnconfigure(3, weight=0, minsize=84) headings.columnconfigure(4, weight=0, minsize=22) Heading(headings, cat, 'title', command=self.sort_column, text=_('Title')).grid(row=0, column=1, sticky='ew') Heading(headings, cat, 'text', command=self.sort_column, text=_('Text')).grid(row=0, column=2, sticky='ew') Heading(headings, cat, 'date', command=self.sort_column, text=_('Date')).grid(row=0, column=3, sticky='ew') Heading(headings, cat, 'select_all', style='select.heading.TLabel', padding=0, command=self.toggle_selectall).place(x=0, y=0, anchor='nw', relheight=1, width=20) Heading(headings, cat, 'visibility', command=self.sort_column).place(relx=1, y=0, anchor='ne', bordermode='outside', width=23, relheight=1) headings.place(x=0, y=2, anchor='nw') self.update_idletasks() frame.rowconfigure(0, minsize=headings.winfo_reqheight()) self.texts[cat].window_create('1.0', window=self.frames[cat]) b_frame = Frame(frame) b_frame.grid(row=3, columnspan=2) m = Menubutton(b_frame, image=self.im_change, text=_('Change category'), compound='right', menu=menu_cat, padding=1) m.pack(side='left', padx=4, pady=4, fill='y') tooltipwrapper.add_tooltip(m, _('Change category of selected notes')) b_show = Button(b_frame, image=self.im_visible, padding=1, command=self.show_selection) b_show.pack(side='left', padx=4, pady=4) tooltipwrapper.add_tooltip(b_show, _('Show selected notes')) b_hide = Button(b_frame, image=self.im_hidden, padding=1, command=self.hide_selection) b_hide.pack(side='left', padx=4, pady=4) tooltipwrapper.add_tooltip(b_hide, _('Hide selected notes')) b_del = Button(b_frame, image=self.im_del, command=self.del_selection, padding=1) b_del.pack(side='left', padx=4, pady=4, fill='y') tooltipwrapper.add_tooltip(b_del, _('Delete selected notes')) self.notebook.add(frame, text=cat.capitalize(), sticky="ewsn", padding=0) # display notes by category for key, note_data in self.master.note_data.items(): self.display_note(key, note_data) for txt in self.texts.values(): txt.configure(state='disabled') self.geometry('410x450') self.bind("<Button-4>", lambda e: self.scroll(-1)) self.bind("<Button-5>", lambda e: self.scroll(1)) self.notebook.bind('<<NotebookTabChanged>>', self.on_change_tab)
class PlaylistHandlerSet(Frame): def __init__(self, w: PlaylistControl, *args, **kwargs): self.EMPTY_MENUBTN = _("Select Playlist") #After defined _ by gettext self.playlist = w.playlist self.playlist_control = w super().__init__(w, *args, **kwargs) #___ self.menubtn = Menubutton(self, direction="above", width=13, text=config.general["playlist"]) self.menubtn.pack() self.menu = Menu(self.menubtn, bg=config.colors["BG"], activebackground=config.colors["TV_BG_HOVER"], activeforeground=config.colors["FG"], tearoff=False) self.menu.add_command(label=_("Import Playlist"), command=self._newPlaylist) self.menu.add_separator() for playlist in config.user_config["Playlists"]: #https://stackoverflow.com/questions/11723217/python-lambda-doesnt-remember-argument-in-for-loop func_get_set_playlist = lambda playlist=playlist: self.setPlaylist( playlist) self.menu.add_command(label=playlist, command=func_get_set_playlist) self.menubtn.configure(menu=self.menu) #__________________________________________________ def _newPlaylist(self): folder: str = filedialog.askdirectory( title=_("Select folder for new playlist")) if folder == "": return playlist = os.path.basename(folder) if playlist not in config.user_config["Playlists"]: config.user_config["Playlists"][playlist] = { "path": os.path.normcase(folder), "orderby": ["title", 1], "filter": "" } self.menu.add_command(label=playlist, command=lambda: self.setPlaylist(playlist)) self.setPlaylist(playlist) def setPlaylist(self, playlist: str): ''' There will be no playlist when starting the application if the playlist had been destroyed with "self.delPlaylist()" and closed without selecting one playlist ''' if playlist == "": self.menubtn["text"] = self.EMPTY_MENUBTN return playlist_path = config.user_config["Playlists"][playlist]["path"] if not os.path.exists(playlist_path): messagebox.showerror(_("Load failed"), _("The folder does not to exist")) self.delPlaylist(playlist) return config.general["playlist"] = playlist config.playlist = config.user_config["Playlists"][playlist] self.menubtn["text"] = playlist self.playlist.setPlaylist(playlist_path) self.playlist_control.sortPlaylistForced(config.playlist["orderby"][0], config.playlist["orderby"][1]) self.playlist_control.setSearch(config.playlist["filter"]) def delPlaylist(self, playlist: str, in_tv: bool = True): config.user_config["Playlists"].pop(playlist) self.menu.delete(playlist) if in_tv: config.general["playlist"] = "" self.menubtn["text"] = self.EMPTY_MENUBTN self.playlist.delPlaylist() def renamePlaylist(self, playlist_new: str, playlist_new_path: str): playlist_old = config.general["playlist"] config.general["playlist"] = playlist_new config.user_config["Playlists"][playlist_new] = config.user_config[ "Playlists"].pop(playlist_old) config.playlist = config.user_config["Playlists"][playlist_new] config.playlist["path"] = playlist_new_path self.menu.entryconfig(self.menu.index(playlist_old), label=playlist_new, command=lambda: self.setPlaylist(playlist_new)) self.menubtn["text"] = playlist_new #Change the path of each song in the playlist for song in self.playlist.getAllSongs(): song.path = os.path.join(playlist_new_path, song.name) + song.extension