class Config(Toplevel): def __init__(self, master): Toplevel.__init__(self, master, class_=APP_NAME) self.title(_("Settings")) self.grab_set() self.columnconfigure(0, weight=1) self.columnconfigure(1, weight=1) self.rowconfigure(0, weight=1) self.resizable(True, True) self.minsize(470, 574) style = Style(self) self._bg = style.lookup('TFrame', 'background') self.notebook = Notebook(self) self._validate = self.register(self._validate_entry_nb) self.img_color = PhotoImage(master=self, file=IM_COLOR) self.lang = StringVar(self, LANGUAGES[CONFIG.get("General", "language")]) self.gui = StringVar(self, CONFIG.get("General", "trayicon").capitalize()) self._init_general() self._init_widget() self.notebook.grid(sticky='ewsn', row=0, column=0, columnspan=2) Button(self, text=_('Ok'), command=self.ok).grid(row=1, column=0, sticky='e', padx=4, pady=10) Button(self, text=_('Cancel'), command=self.destroy).grid(row=1, column=1, sticky='w', padx=4, pady=10) 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_widget(self): frame_widget = Frame(self) self.notebook.add(frame_widget, text=_('Widget')) # --- font frame_font = Frame(frame_widget) self.title_font = FontFrame(frame_font, CONFIG.get("Widget", "font_title"), True) self.text_font = FontFrame(frame_font, CONFIG.get("Widget", "font")) frame_font.columnconfigure(1, weight=1) Label(frame_font, text=_('Title')).grid(row=0, column=0, sticky='nw', padx=4, pady=4) self.title_font.grid(row=0, column=1) Separator(frame_font, orient='horizontal').grid(row=1, columnspan=2, sticky='ew', padx=4, pady=4) Label(frame_font, text=_('Text')).grid(row=2, column=0, sticky='nw', padx=4, pady=4) self.text_font.grid(row=2, column=1) # --- opacity self.opacity_frame = OpacityFrame(frame_widget, CONFIG.get("Widget", "alpha")) # --- colors frame_color = Frame(frame_widget) frame_color.columnconfigure(1, weight=1) frame_color.columnconfigure(3, weight=1) self.color_bg = ColorFrame(frame_color, CONFIG.get("Widget", "background"), _('Background color')) self.color_fg = ColorFrame(frame_color, CONFIG.get("Widget", "foreground"), _('Foreground color')) self.color_feed_bg = ColorFrame( frame_color, CONFIG.get("Widget", "feed_background"), _('Background color')) self.color_feed_fg = ColorFrame( frame_color, CONFIG.get("Widget", "feed_foreground"), _('Foreground color')) self.color_link = ColorFrame(frame_color, CONFIG.get("Widget", "link_color"), _('Link color')) Label(frame_color, text=_('General')).grid(row=0, column=0, sticky='w', padx=4, pady=2) self.color_bg.grid(row=0, column=1, sticky='e', padx=4, pady=2) self.color_fg.grid(row=1, column=1, sticky='e', padx=4, pady=2) Separator(frame_color, orient='horizontal').grid(row=2, columnspan=4, sticky='ew', padx=4, pady=4) Label(frame_color, text=_('Feed entry')).grid(row=3, column=0, sticky='w', padx=4, pady=2) self.color_feed_bg.grid(row=3, column=1, sticky='e', padx=4, pady=2) self.color_feed_fg.grid(row=4, column=1, sticky='e', padx=4, pady=2) self.color_link.grid(row=5, column=1, sticky='e', padx=4, pady=2) # --- pack Label(frame_widget, text=_('Font'), font='TkDefaultFont 9 bold', anchor='w').pack(padx=4, fill='x') frame_font.pack(fill='x', padx=14) Separator(frame_widget, orient='horizontal').pack(fill='x', pady=6) self.opacity_frame.pack(padx=(4, 10), fill='x') Separator(frame_widget, orient='horizontal').pack(fill='x', pady=6) Label(frame_widget, text=_('Colors'), font='TkDefaultFont 9 bold', anchor='w').pack(padx=4, fill='x') frame_color.pack(fill='x', padx=14) def display_label(self, value): self.opacity_label.configure(text=" {val} %".format( val=int(float(value)))) def translate(self): showinfo( "Information", _("The language setting will take effect after restarting the application" ), parent=self) @staticmethod def _config_size(variable, font): size = variable.get() if size: font.configure(size=size) @staticmethod def _validate_entry_nb(P): """ Allow only to enter numbers""" parts = P.split(".") b = len(parts) < 3 and P != "." for p in parts: b = b and (p == "" or p.isdigit()) return b def change_gui(self): showinfo( "Information", _("The GUI Toolkit setting will take effect after restarting the application" ), parent=self) def ok(self): # --- general CONFIG.set("General", "language", REV_LANGUAGES[self.lang.get()]) CONFIG.set("General", "trayicon", self.gui.get().lower()) CONFIG.set("General", "update_delay", "%i" % (int(self.entry_delay.get()) * 60000)) CONFIG.set("General", "img_timeout", "%i" % (int(self.entry_timeout.get()))) CONFIG.set('General', 'confirm_feed_remove', str(self.confirm_feed_rem.instate(('selected', )))) CONFIG.set('General', 'confirm_cat_remove', str(self.confirm_cat_rem.instate(('selected', )))) CONFIG.set('General', 'check_update', str(self.confirm_update.instate(('selected', )))) CONFIG.set('General', 'splash_supported', str(not self.splash_support.instate(('selected', )))) CONFIG.set('General', 'notifications', str(self.notifications.instate(('selected', )))) # --- widget CONFIG.set("Widget", "alpha", "%i" % self.opacity_frame.get_opacity()) font_title_dic = self.title_font.get_font() font_title_dic[ 'underline'] = 'underline' if font_title_dic['underline'] else '' font_title_dic['family'] = font_title_dic['family'].replace(' ', '\ ') CONFIG.set( "Widget", "font_title", "{family} {size} {weight} {slant} {underline}".format( **font_title_dic)) font_text_dic = self.text_font.get_font() font_text_dic['family'] = font_text_dic['family'].replace(' ', '\ ') CONFIG.set("Widget", "font", "{family} {size}".format(**font_text_dic)) CONFIG.set("Widget", "foreground", self.color_fg.get_color()) CONFIG.set("Widget", "background", self.color_bg.get_color()) CONFIG.set("Widget", "feed_foreground", self.color_feed_fg.get_color()) CONFIG.set("Widget", "feed_background", self.color_feed_bg.get_color()) CONFIG.set("Widget", "link_color", self.color_link.get_color()) self.destroy()
class StringEntry(LabelFrame): # changed """String class for entry rationalised with integer and float classes super Parameters ---------- parent : str parent handle lf_text : str text on LabelFrame def_inp : str default text colour : str frame colour mod : boolean enable or disable state switch Returns ------- string """ def __init__(self, parent, lf_text, def_inp="", colour='brown', mod=False): self.lf_text = lf_text super().__init__(parent, text=lf_text) # added self.mod = mod self.ent0 = None # for entry self.cb_opt = None # for check option self.out_var = StringVar() self.out_var.set(def_inp) self.construct(colour) def construct(self, colour): """construct of colour style Parameters ---------- colour : str frame colour Returns ------- None """ self.farbe = farbe = { 'blue': 'light blue', 'brown': 'brown1', 'green': 'light green', 'pink': '#EAAFBF' } colour = colour if colour in farbe else 'brown' self.colour = colour st1 = Style() st1.theme_use('default') st1.configure(colour + '.TLabelframe', background='#C9B99B') st1.configure(colour + '.TLabelframe.Label', background=farbe[colour]) st1.configure(colour + '.TCheckbutton', background=farbe[colour]) st1.configure('brown.TLabel', background='#EDEF77') st1.configure('lowr.TLabel', background='lightblue') st1.configure('upr.TLabel', background='red') # self.lf1 = Labelframe(self.fr, text=self.lf_text, # style=self.colour+'.TLabelframe') # self.lf1.grid(column=0,row=0,padx=10, pady=10) self['style'] = self.colour + '.TLabelframe' self.messlbl = Label(self, style='brown.TLabel') # self.lf1 self.messlbl.grid(row=2, column=0, pady=10, padx=10) self.make_entry() def make_entry(self): """construct of Entry Parameters ---------- None Returns ------- None """ vcmd = self.register(self.is_okay) self.ent0 = ent0 = Entry( self, validate='key', validatecommand=(vcmd, '%P', '%S', '%i'), # self.lf1 textvariable=self.out_var) ent0.bind("<Return>", self.end_input) ent0.grid(row=1, column=0, padx=10) ent0.focus() if self.mod in (True, False): self.modify() def modify(self): """construct of state switch Parameters ---------- None Returns ------- None """ # entry disabled until checkbox is ticked self.cb_opt = Checkbutton( self, command=self.toggle_opt, # self.lf1 style=self.colour + '.TCheckbutton') self['labelwidget'] = self.cb_opt # self.lf1[ if self.mod: self.ent0.state(['!disabled']) self.cb_opt.state(['!selected']) self.cb_opt['text'] = self.lf_text self.ent0.focus() else: self.ent0.state(['disabled']) self.cb_opt.state(['selected']) self.cb_opt['text'] = self.lf_text def toggle_opt(self): """state switch logic Parameters ---------- None Returns ------- None """ # state of entry controlled # by the state of the check button in Option frame label widget if self.cb_opt.instate(['selected']): self.ent0.state(['disabled']) self.cb_opt['text'] = self.lf_text else: self.ent0.state(['!disabled']) self.cb_opt['text'] = self.lf_text self.ent0.focus() def end_input(self, _evt): """limit on string Parameters ---------- evt : str bind handle Returns ------- None """ if len(self.out_var.get()) > 5: self.messlbl['text'] = "That's OK" else: self.messlbl['text'] = "Need at least 6 characters" def is_okay(self, text, inp, ind): """ validation function Parameters ---------- text : str text if allowed inp : str current input Returns ------- boolean """ ind = int(ind) if (inp.isalnum() or inp in (",", ".", "'", " ")) and ind > 0: return True else: return bool((text.isupper() or text == "") and ind == 0)
class StringEntry: """String class for entry added colour, change state Parameters ---------- parent : str parent handle lf_text : str text on LabelFrame mess_text : str message def_text : str default text colour : str frame colour mod : str enable or disable state switch Returns ------- string """ def __init__(self, parent, lf_text, mess_text, def_text="", colour='brown', mod=False): self.parent = parent self.lf_text = lf_text self.mess_text = mess_text self.mod = mod self.out_var = StringVar() self.out_var.set(def_text) self.farbe = farbe = { 'blue': 'light blue', 'brown': '#EDEF77', 'green': 'light green', 'pink': '#EAAFBF' } colour = colour if colour in farbe else 'brown' self.colour = colour st1 = Style() st1.theme_use('default') st1.configure(colour + '.TLabelframe', background='#C9B99B') st1.configure(colour + '.TLabelframe.Label', background=farbe[colour]) st1.configure(colour + '.TCheckbutton', background=farbe[colour]) st1.configure('brown.TLabel', background='#EDEF77') self.construct() def construct(self): """construct of LabelFrame and message Parameters ---------- None Returns ------- None """ self.lf1 = Labelframe(self.parent, text=self.lf_text, style=self.colour + '.TLabelframe') self.lf1.grid(column=0, row=0, padx=10, pady=10) self.messlbl = Label(self.lf1, text=self.mess_text, style='brown.TLabel') self.messlbl.grid(row=2, column=0, pady=10, padx=10) self.make_entry() def make_entry(self): """construct of Entry Parameters ---------- None Returns ------- None """ vcmd = self.lf1.register(self.is_okay) self.ent1 = ent1 = Entry(self.lf1, validate='key', validatecommand=(vcmd, '%P', '%S', '%i'), textvariable=self.out_var) ent1.bind("<Return>", self.end_input) ent1.grid(row=1, column=0, padx=10) ent1.focus() if self.mod in (True, False): self.modify() def modify(self): """construct of state switch Parameters ---------- None Returns ------- None """ lf_text = self.lf_text # entry disabled until checkbox is ticked self.cb_opt = Checkbutton(self.lf1, command=self.toggle_opt, style=self.colour + '.TCheckbutton') self.lf1['labelwidget'] = self.cb_opt if self.mod: self.ent1.state(['!disabled']) self.cb_opt.state(['!selected']) self.cb_opt['text'] = lf_text + ' Check to prevent editing ' self.ent1.focus() else: self.ent1.state(['disabled']) self.cb_opt.state(['selected']) self.cb_opt['text'] = lf_text + ' Check to modify ' def toggle_opt(self): """state switch logic Parameters ---------- None Returns ------- None """ lf_text = self.lf_text # state of entry controlled # by the state of the check button in Option frame label widget if self.cb_opt.instate(['selected']): print('selected state') self.ent1.state(['disabled']) self.cb_opt['text'] = lf_text + ' Check to modify ' else: print('unselected state') self.ent1.state(['!disabled']) # enable option self.cb_opt['text'] = lf_text + ' Check to prevent editing ' self.ent1.focus() def end_input(self, _evt): """limit on string Parameters ---------- evt : str bind handle Returns ------- None """ if len(self.out_var.get()) > 5: self.messlbl['text'] = "That's OK" else: self.messlbl['text'] = "Should be at least 6 characters long" def is_okay(self, text, inp, ind): """ validation function Parameters ---------- text : str text if allowed inp : str current input Returns ------- boolean """ ind = int(ind) print(ind) if (inp.isalnum() or inp in (",", ".", "'", " ")) and ind > 0: return True else: return bool((text.isupper() or text == "") and ind == 0)
class NotebookDemo: def __init__(self, fr): self.fr = fr self.style = Style() # ts.ThemedStyle() # Style() self._create_demo_panel() # run this before allBtns self.allBtns = self.ttkbut + self.cbs[1:] + self.rb try: piratz_theme.install('piratz') except Exception: import warnings warnings.warn("piratz theme being used without images") def _create_demo_panel(self): demoPanel = Frame(self.fr, name="demo") demoPanel.pack(side='top', fill='both', expand='y') # create the notebook self.nb = nb = Notebook(demoPanel, name="nb") nb.bind("<<NotebookTabChanged>>", self._on_tab_changed) # extend bindings to top level window allowing # CTRL+TAB - cycles thru tabs # SHIFT+CTRL+TAB - previous tab # ALT+K - select tab using mnemonic (K = underlined letter) nb.enable_traversal() nb.pack(fill='both', expand='y', padx=2, pady=3) self._create_descrip_tab(nb) self._create_treeview_tab(nb) self._create_text_tab(nb) def _create_descrip_tab(self, nb): # frame to hold contents frame = Frame(nb, name='descrip') # widgets to be displayed on 'Description' tab # position and set resize behaviour frame.rowconfigure(1, weight=1) frame.columnconfigure((0, 1), weight=1, uniform=1) lf = LabelFrame(frame, text='Animals') lf.pack(pady=5, padx=5, side='left', fill='y') themes = ['horse', 'elephant', 'crocodile', 'bat', 'grouse'] self.ttkbut = [] for t in themes: b = Button(lf, text=t) b.pack(pady=2) self.ttkbut.append(b) lF2 = LabelFrame(frame, text="Theme Combobox") lF2.pack(pady=5, padx=5) themes = list(sorted( self.style.theme_names())) # get_themes # used in ttkthemes themes.insert(0, "Pick a theme") self.cb = cb = Combobox(lF2, values=themes, state="readonly", height=10) cb.set(themes[0]) #cb.bind('<<ComboboxSelected>>', self.change_style) cb.grid(row=0, column=0, sticky='nw', pady=5) lf1 = LabelFrame(frame, text='Checkbuttons') lf1.pack(pady=5, padx=5, side='left', fill='y') # control variables self.enabled = IntVar() self.cheese = IntVar() self.tomato = IntVar() self.basil = IntVar() self.oregano = IntVar() # checkbuttons self.cbOpt = Checkbutton(lf1, text='Enabled', variable=self.enabled, command=self._toggle_opt) cbCheese = Checkbutton(text='Cheese', variable=self.cheese, command=self._show_vars) cbTomato = Checkbutton(text='Tomato', variable=self.tomato, command=self._show_vars) sep1 = Separator(orient='h') cbBasil = Checkbutton(text='Basil', variable=self.basil, command=self._show_vars) cbOregano = Checkbutton(text='Oregano', variable=self.oregano, command=self._show_vars) sep2 = Separator(orient='h') self.cbs = [ self.cbOpt, sep1, cbCheese, cbTomato, sep2, cbBasil, cbOregano ] for opt in self.cbs: if opt.winfo_class() == 'TCheckbutton': opt.configure(onvalue=1, offvalue=0) opt.setvar(opt.cget('variable'), 0) opt.pack(in_=lf1, side='top', fill='x', pady=2, padx=5, anchor='nw') lf2 = LabelFrame(frame, text='Radiobuttons', labelanchor='n') lf2.pack(pady=5, padx=5, side='left', fill='y') self.rb = [] self.happiness = StringVar() for s in ['Great', 'Good', 'OK', 'Poor', 'Awful']: b = Radiobutton(lf2, text=s, value=s, variable=self.happiness, command=lambda s=s: self._show_vars()) b.pack(anchor='nw', side='top', fill='x', pady=5, padx=5) self.rb.append(b) right = LabelFrame(frame, text='Control Variables') right.pack(pady=5, padx=5, side='left', fill='y') self.vb0 = Label(right, font=('Courier', 10)) self.vb1 = Label(right, font=('Courier', 10)) self.vb2 = Label(right, font=('Courier', 10)) self.vb3 = Label(right, font=('Courier', 10)) self.vb4 = Label(right, font=('Courier', 10)) self.vb5 = Label(right, font=('Courier', 10)) self.vb0.pack(anchor='nw', pady=5, padx=5) self.vb1.pack(anchor='nw', pady=5, padx=5) self.vb2.pack(anchor='nw', pady=5, padx=5) self.vb3.pack(anchor='nw', pady=5, padx=5) self.vb4.pack(anchor='nw', pady=5, padx=5) self.vb5.pack(anchor='nw', pady=5, padx=5) self._show_vars() # add to notebook (underline = index for short-cut character) nb.add(frame, text='Description', underline=0, padding=2) # ============================================================================= def _create_treeview_tab(self, nb): # Populate the second pane. Note that the content doesn't really matter tree = None self.backg = ["white", '#f0f0ff'] tree_columns = ("country", "capital", "currency") tree_data = [("Argentina", "Buenos Aires", "ARS"), ("Australia", "Canberra", "AUD"), ("Brazil", "Brazilia", "BRL"), ("Canada", "Ottawa", "CAD"), ("China", "Beijing", "CNY"), ("France", "Paris", "EUR"), ("Germany", "Berlin", "EUR"), ("India", "New Delhi", "INR"), ("Italy", "Rome", "EUR"), ("Japan", "Tokyo", "JPY"), ("Mexico", "Mexico City", "MXN"), ("Russia", "Moscow", "RUB"), ("South Africa", "Pretoria", "ZAR"), ("United Kingdom", "London", "GBP"), ("United States", "Washington, D.C.", "USD")] container = Frame(nb) container.pack(fill='both', expand=False) self.tree = Treeview(container, columns=tree_columns, show="headings") vsb = Scrollbar(container, orient="vertical", command=self.tree.yview) hsb = Scrollbar(container, orient="horizontal", command=self.tree.xview) self.tree.configure(yscrollcommand=vsb.set, xscrollcommand=hsb.set) self.tree.grid(column=0, row=0, sticky='ns', in_=container) vsb.grid(column=1, row=0, sticky='ns', in_=container) hsb.grid(column=0, row=1, sticky='ew', in_=container) container.grid_columnconfigure(0, weight=1) container.grid_rowconfigure(0, weight=1) for col in tree_columns: self.tree.heading( col, text=col.title(), command=lambda c=col: self.sortby(self.tree, c, 0)) # XXX tkFont.Font().measure expected args are incorrect according # to the Tk docs self.tree.column(col, width=Font().measure(col.title()), stretch=False) for ix, item in enumerate(tree_data): itemID = self.tree.insert('', 'end', values=item) self.tree.item(itemID, tags=itemID) self.tree.tag_configure(itemID, background=self.backg[ix % 2]) # adjust columns lengths if necessary for indx, val in enumerate(item): ilen = Font().measure(val) if self.tree.column(tree_columns[indx], width=None) < ilen: self.tree.column(tree_columns[indx], width=ilen) sg = Sizegrip(container) sg.grid(sticky='e') nb.add(container, text='Treeview', underline=0, padding=2) # ============================================================================= def _create_text_tab(self, nb): self.dir0 = 1 self.dir1 = 1 # populate the third frame with other widgets fr = Frame(nb, name='fr') lF = LabelFrame(fr, text="Slider") fr1 = Frame(lF) fr1.grid(row=0, column=0, sticky='nsew') from_ = 100 to = 0 value = 0 step = 10 fontSize = 9 self.scvar = IntVar() scRange = self.any_number_range(from_, to, step) scLen = len(scRange[1]) * (fontSize + 10) self.sc = Scale(fr1, from_=from_, to=to, variable=self.scvar, orient='vertical', length=scLen, command=self.v_scale) self.sc.set(value) l1 = Label(fr1, textvariable=self.scvar, width=5) l1.grid(row=0, column=0, padx=5, pady=5) self.sc.grid(row=0, column=1, padx=5, pady=5) fr4 = Frame(fr1) fr4.grid(row=0, column=2) sc_split = '\n'.join(scRange[0].split()) lb = Label(fr1, text=sc_split, font=('Courier New', str(fontSize))) lb.grid(row=0, column=2, padx=5, pady=5) fr2 = Frame(lF, name='fr2') fr2.grid(row=0, column=1, sticky='nsew') self.schvar = IntVar() a = 0 b = 100 schRange = self.any_number_range(a, b, s=10) schLen = Font().measure(schRange[0]) self.sch = Scale(fr2, from_=a, to=b, length=schLen, variable=self.schvar, orient='horizontal', command=self.h_scale) self.sch.set(0) l2 = Label(fr2, textvariable=self.schvar) l2.grid(row=1, column=1, pady=2) self.sch.grid(row=2, column=1, padx=5, pady=5, sticky='nsew') l3 = Label(fr2, text=schRange[0], font=('Courier New', str(fontSize))) l3.grid(row=3, column=1, padx=5, pady=5) lF.grid(row=0, column=0, sticky='nesw', pady=5, padx=5) lF1 = LabelFrame(fr, text="Progress", name='lf') pb1var = IntVar() pb2var = IntVar() self.pbar = Progressbar(lF1, variable=pb1var, length=150, mode="indeterminate", name='pb1', orient='horizontal') self.pb2 = Progressbar(lF1, variable=pb2var, length=150, mode='indeterminate', name='pb2', orient='vertical') self.pbar["value"] = 25 self.h_progress() self.v_progress() self.pbar.grid(row=1, column=0, padx=5, pady=5, sticky='nw') self.pb2.grid(row=1, column=1, padx=5, pady=5, sticky='nw') l3 = Label(lF1, textvariable=pb1var) l3.grid(row=0, column=0, pady=2, sticky='nw') l4 = Label(lF1, textvariable=pb2var) l4.grid(row=0, column=1, pady=2, sticky='nw') sg1 = Sizegrip(fr) sg1.grid(row=2, column=2, sticky='e') lF1.grid(row=1, column=0, sticky='nesw', pady=5, padx=5) # add to notebook (underline = index for short-cut character) nb.add(fr, text='Sliders & Others', underline=0) #========================================================================= def _toggle_opt(self): # state of the option buttons controlled # by the state of the Option frame label widget for opt in self.allBtns: if opt.winfo_class() != 'TSeparator': if self.cbOpt.instate(('selected', )): opt['state'] = '!disabled' # enable option self.nb.tab(1, state='normal') else: opt['state'] = 'disabled' self.nb.tab(1, state='disabled') self._show_vars() def _show_vars(self): # set text for labels in var_panel to include the control # variable name and current variable value self.vb0['text'] = '{:<11} {:<8}'.format('enabled:', self.enabled.get()) self.vb1['text'] = '{:<11} {:<8}'.format('cheese:', self.cheese.get()) self.vb2['text'] = '{:<11} {:<8}'.format('tomato:', self.tomato.get()) self.vb3['text'] = '{:<11} {:<8}'.format('basil:', self.basil.get()) self.vb4['text'] = '{:<11} {:<8}'.format('oregano:', self.oregano.get()) self.vb5['text'] = '{:<11} {:<8}'.format('happiness:', self.happiness.get()) def sortby(self, tree, col, descending): """Sort tree contents when a column is clicked on.""" # grab values to sort data = [(tree.set(child, col), child) for child in tree.get_children('')] # reorder data data.sort(reverse=descending) for indx, item in enumerate(data): tree.move(item[1], '', indx) # switch the heading so that it will sort in the opposite direction tree.heading(col, command=lambda col=col: self.sortby( tree, col, int(not descending))) # reconfigure tags after ordering list_of_items = tree.get_children('') for i in range(len(list_of_items)): tree.tag_configure(list_of_items[i], background=self.backg[i % 2]) def any_number_range(self, a, b, s=1): """ Generate consecutive values list between two numbers with optional step (default=1).""" if (a == b): return a else: mx = max(a, b) mn = min(a, b) result = [] output = '' # inclusive upper limit. If not needed, delete '+1' in the line below while (mn < mx + 1): # if step is positive we go from min to max if s > 0: result.append(mn) mn += s # if step is negative we go from max to min if s < 0: result.append(mx) mx += s # val maxLen = 0 output = "" for ix, res in enumerate(result[:-1]): # last value ignored if len(str(res)) > maxLen: maxLen = len(str(res)) if maxLen == 1: output = ' '.join(str(i) for i in result) # converts list to string else: for ix, res in enumerate(result): if maxLen == 2: if len(str(res)) == 1: output = output + str(res) + " " * maxLen elif len(str(res)) == 2: output = output + str(res) + " " else: output = output + str(res) #print(output) return output, result def change_style(self, event=None): """set the Style to the content of the Combobox""" content = self.cb.get() try: self.style.theme_use(content) except TclError as err: messagebox.showerror('Error', err) else: root.title(content) def change_theme(self, theme): window = ttktheme.ThemedTk() window.set_theme(theme) root.title(theme) def _on_tab_changed(self, event): event.widget.update_idletasks() tab = event.widget.nametowidget(event.widget.select()) event.widget.configure(height=tab.winfo_reqheight(), width=tab.winfo_reqwidth()) def h_progress(self): widg = self.pbar widg['value'] += 1 * self.dir0 if widg['value'] == 100: widg.state(['background', '!active']) self.dir0 = -1 widg.after(50, self.h_progress) elif widg['value'] == 0: widg.state(['active', '!background']) self.dir0 = 1 widg.after(50, self.h_progress) else: widg.after(50, self.h_progress) def v_progress(self): widg1 = self.pb2 widg1['value'] += 1 * self.dir1 if widg1['value'] == 0: # (dir1-1)*100+16 widg1.state(['active', '!invalid', '!background']) self.dir1 = 1 widg1.after(40, self.v_progress) elif widg1['value'] == 16: # (dir1-1)*100+16 widg1.state(['background', '!invalid', '!active']) widg1.after(40, self.v_progress) elif widg1['value'] == 33: widg1.state(['invalid', '!background', '!active']) widg1.after(40, self.v_progress) elif widg1['value'] == 50: widg1.state(['active', '!invalid', '!background']) widg1.after(40, self.v_progress) elif widg1['value'] == 66: widg1.state(['background', '!invalid', '!active']) widg1.after(40, self.v_progress) elif widg1['value'] == 83: widg1.state(['invalid', '!background', '!active']) widg1.after(40, self.v_progress) elif widg1['value'] == 100: widg1.state(['active', '!invalid', '!background']) self.dir1 = -1 widg1.after(40, self.v_progress) else: widg1.after(40, self.v_progress) def h_scale(self, schvar): v = int(float(schvar)) widg = self.sch imgw = { 0: ['readonly', '!selected', '!background', '!focus', '!active'], 1: ['selected', '!readonly', '!background', '!focus', '!active'] } if v >= 0 and v < 10: widg.state(['active', '!readonly', '!selected']) elif v > 80 and v < 91: widg.state(['focus', '!background', '!readonly', '!selected']) elif v > 90 and v < 100: widg.state(['background', '!invalid', '!focus']) elif v == 100: widg.state(['invalid', '!background']) else: widg.state(imgw[v % 2]) def v_scale(self, scvar): v = int(float(scvar)) widg1 = self.sc imgw = { 0: ['background', '!selected', '!invalid', '!active'], 1: ['selected', '!invalid', '!background', '!active'] } if v >= 0 and v < 5: widg1.state(['active', '!background', '!selected']) elif v > 90: widg1.state(['invalid', '!selected', '!background']) else: widg1.state(imgw[v % 2])
class Config(Toplevel): """Config dialog.""" def __init__(self, master): """Create Config dialog.""" Toplevel.__init__(self, master, class_='MyNotes') self.title(_("Preferences")) self.grab_set() self.protocol("WM_DELETE_WINDOW", self.quit) self.changes = {}, {}, False, False self.minsize(width=430, height=450) # --- 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) okcancel_frame.pack(fill="x", side='bottom') self.notebook.pack(expand=True, fill="both") # --- * General settings self._init_general() # --- * Font settings self._init_font() # --- * Categories self.category_settings = CategoryManager(self.notebook, master) self.notebook.add(self.category_settings, text=_("Categories"), sticky="ewsn", padding=4) # --- * Symbols size = CONFIG.get("Font", "text_size") family = CONFIG.get("Font", "text_family") symbols_settings = Frame(self.notebook, padding=4) self.notebook.add(symbols_settings, text=_("Symbols"), sticky="ewsn", padding=4) txt_frame = Frame(symbols_settings, relief="sunken", borderwidth=1, style="text.TFrame") txt_frame.rowconfigure(0, weight=1) txt_frame.columnconfigure(0, weight=1) 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)) scroll_y = AutoScrollbar(txt_frame, orient='vertical', command=self.symbols.yview) self.symbols.configure(yscrollcommand=scroll_y.set) 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.grid(sticky='ewns') scroll_y.grid(row=0, column=1, sticky='ns') Button(symbols_settings, text=_('Reset'), command=self.reset_symbols).pack(padx=4, pady=4) # --- * AutoCorrect self.autocorrect_settings = AutoCorrectConfig(self.notebook, master) self.notebook.add(self.autocorrect_settings, text=_("AutoCorrect"), sticky="ewsn", padding=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") 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_font(self): font_settings = Frame(self.notebook, padding=4) font_settings.columnconfigure(1, weight=1) self.notebook.add(font_settings, text=_("Font"), sticky="ewsn", padding=4) # ---- title title_size = CONFIG.get("Font", "title_size") title_family = CONFIG.get("Font", "title_family").replace(" ", "\ ") font_title = '{} {}'.format(title_family, title_size) style = CONFIG.get("Font", "title_style").split(",") if style: font_title = font_title + " " + " ".join(style) self.title_font = FontFrame(font_settings, font_title, style=True) # ---- text size = CONFIG.get("Font", "text_size") family = CONFIG.get("Font", "text_family").replace(" ", "\ ") self.text_font = FontFrame(font_settings, '{} {}'.format(family, size)) # ---- mono mono_fonts = [f for f in set(font.families()) if 'Mono' in f] mono_family = CONFIG.get("Font", "mono").replace(" ", "\ ") self.mono_font = FontFrame(font_settings, '{} {}'.format(mono_family, size), size=False, font_list=mono_fonts) add_trace( self.text_font.font_size, 'write', lambda *args: self.mono_font._config_size( self.text_font.font_size, self.mono_font.font)) # ---- placement Label(font_settings, text=_("Title")).grid(row=0, column=0, padx=4, pady=4, sticky="nw") self.title_font.grid(row=0, column=1, sticky="w", padx=20) Separator(font_settings, orient="horizontal").grid(row=1, columnspan=2, sticky="ew", pady=10) Label(font_settings, text=_("Text")).grid(row=2, column=0, padx=4, pady=4, sticky="nw") self.text_font.grid(row=2, column=1, sticky="w", padx=20) Separator(font_settings, orient="horizontal").grid(row=3, columnspan=2, sticky="ew", pady=10) Label(font_settings, text=_("Mono")).grid(row=4, column=0, padx=4, pady=4, sticky="nw") self.mono_font.grid(row=4, column=1, sticky="w", padx=20) def reset_symbols(self): self.symbols.delete('1.0', 'end') self.symbols.insert('1.0', SYMBOLS) def toggle_date(self): if self.date_in_title.get(): self.title_var.set('{} - {}'.format(_('Title'), strftime('%x'))) else: self.title_var.set(_('Title')) def cleanup(self): """Remove unused local data and latex images.""" self.master.cleanup() showinfo(_('Information'), _('Unused local data have been cleaned up.')) def ok(self): """Validate configuration.""" # --- splash supported splash_supp = not self.splash_support.instate(('selected', )) splash_change = splash_supp != CONFIG.getboolean( "General", "splash_supported", fallback=True) # --- font mono_font = self.mono_font.get_font()['family'] text_font = self.text_font.get_font() title_font = self.title_font.get_font() style = "{weight},{slant}".format(**title_font) style = style + ',underline' * title_font['underline'] # --- language language = REV_LANGUAGES[self.lang.get()] # --- symbols symbols = [ l.strip() for l in self.symbols.get("1.0", "end").splitlines() ] # --- autocorrect self.autocorrect_settings.ok() autocorrect = "\t".join( ["%s %s" % (key, val) for key, val in AUTOCORRECT.items()]) # --- update CONFIG CONFIG.set("General", "default_category", self.category_settings.default_category.get().lower()) CONFIG.set("General", "language", language) CONFIG.set("General", "opacity", str(self.opacity.get())) CONFIG.set("General", "position", self.position.get()) CONFIG.set("General", "buttons_position", self.titlebar_disposition.get()) CONFIG.set("General", "date_in_title", str(self.date_in_title.get())) CONFIG.set("General", "symbols", "".join(symbols)) CONFIG.set("General", "trayicon", self.gui.get().lower()) CONFIG.set("General", "autocorrect", autocorrect) CONFIG.set('General', 'splash_supported', str(splash_supp)) CONFIG.set("Font", "text_size", str(text_font['size'])) CONFIG.set("Font", "text_family", text_font['family']) CONFIG.set("Font", "title_family", title_font['family']) CONFIG.set("Font", "title_size", str(title_font['size'])) CONFIG.set("Font", "title_style", style) CONFIG.set("Font", "mono", mono_font) # --- notes config col_changes = {} name_changes = {} new_cat = False for cat in self.category_settings.categories: new_name = self.category_settings.get_name(cat) if cat in CONFIG.options("Categories"): old_color = CONFIG.get("Categories", cat) new_color = COLORS[self.category_settings.get_color(cat)] if new_name != cat: name_changes[cat] = new_name CONFIG.remove_option("Categories", cat) CONFIG.set("Categories", new_name, new_color) if old_color != new_color: col_changes[new_name] = (old_color, new_color) CONFIG.set("Categories", new_name, new_color) else: new_cat = True CONFIG.set("Categories", new_name, COLORS[self.category_settings.get_color(cat)]) save_config() self.changes = col_changes, name_changes, new_cat, splash_change self.destroy() def get_changes(self): return self.changes def translate(self): """Show information dialog about language change.""" showinfo( _("Information"), _("The language setting will take effect after restarting the application" ), parent=self) def change_gui(self): """Show information dialog about gui toolkit change.""" showinfo( "Information", _("The GUI Toolkit setting will take effect after restarting the application" ), parent=self) def display_label(self, value): self.opacity_label.configure(text=" {val} %".format( val=int(float(value)))) def quit(self): self.destroy()
class Config(Toplevel): 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 reset_symbols(self): self.symbols.delete('1.0', 'end') self.symbols.insert('1.0', SYMBOLS) def cleanup(self): ''' Remove unused latex images ''' self.master.cleanup() def validate_font_size(self, combo, d, ch, V): ''' Validation of the size entry content ''' if d == '1': l = [i for i in self.sizes if i[:len(ch)] == ch] if l: i = self.sizes.index(l[0]) combo.current(i) index = combo.index("insert") combo.selection_range(index + 1, "end") combo.icursor(index + 1) return ch.isdigit() else: return True def validate_font_family(self, combo, action, modif, pos, prev_txt, V): """ completion of the text in the path entry with existing folder/file names """ try: sel = combo.selection_get() txt = prev_txt.replace(sel, '') except TclError: txt = prev_txt if action == "0": txt = txt[:int(pos)] + txt[int(pos) + 1:] return True else: txt = txt[:int(pos)] + modif + txt[int(pos):] l = [i for i in self.fonts if i[:len(txt)] == txt] if l: i = self.fonts.index(l[0]) combo.current(i) index = combo.index("insert") combo.delete(0, "end") combo.insert(0, l[0].replace("\ ", " ")) combo.selection_range(index + 1, "end") combo.icursor(index + 1) return True else: return False def ok(self): family = self.font_family.get() if family not in self.fonts: l = [i for i in self.fonts if i[:len(family)] == family] if l: family = l[0] else: family = 'TkDefaultFont' size = self.font_size.get() familytitle = self.fonttitle_family.get() if familytitle not in self.fonts: l = [i for i in self.fonts if i[:len(familytitle)] == familytitle] if l: familytitle = l[0] else: familytitle = 'TkDefaultFont' sizetitle = self.fonttitle_size.get() opacity = "%i" % float(self.opacity_scale.get()) language = self.lang.get().lower()[:2] style = "" if self.is_bold.instate(("selected", )): style += "bold," if self.is_italic.instate(("selected", )): style += "italic," if self.is_underlined.instate(("selected", )): style += "underline," if style: style = style[:-1] symbols = [ l.strip() for l in self.symbols.get("1.0", "end").splitlines() ] CONFIG.set("General", "default_category", self.category_settings.default_category.get().lower()) CONFIG.set("General", "language", language) CONFIG.set("General", "opacity", opacity) CONFIG.set("General", "position", self.position.get()) CONFIG.set("General", "buttons_position", self.titlebar_disposition.get()) CONFIG.set("General", "symbols", "".join(symbols)) CONFIG.set("Font", "text_size", size) CONFIG.set("Font", "text_family", family) CONFIG.set("Font", "title_family", familytitle) CONFIG.set("Font", "title_size", sizetitle) CONFIG.set("Font", "title_style", style) col_changes = {} name_changes = {} for cat in self.category_settings.categories: new_name = self.category_settings.get_name(cat) if cat in CONFIG.options("Categories"): old_color = CONFIG.get("Categories", cat) new_color = COLORS[self.category_settings.get_color(cat)] if new_name != cat: name_changes[cat] = new_name CONFIG.remove_option("Categories", cat) CONFIG.set("Categories", new_name, new_color) if old_color != new_color: col_changes[new_name] = (old_color, new_color) CONFIG.set("Categories", new_name, new_color) else: CONFIG.set("Categories", new_name, COLORS[self.category_settings.get_color(cat)]) save_config() self.changes = col_changes, name_changes self.destroy() def get_changes(self): return self.changes def translate(self): showinfo( "Information", _("The language setting will take effect after restarting the application" ), parent=self) def update_preview(self, event=None): family = self.font_family.get() size = self.font_size.get() self.sample.configure(font="%s %s" % (family.replace(" ", "\ "), size)) def update_preview_title(self, event=None): family = self.fonttitle_family.get() size = self.fonttitle_size.get() config = "%s %s" % (family.replace(" ", "\ "), size) if self.is_bold.instate(("selected", )): config += " bold" if self.is_italic.instate(("selected", )): config += " italic" if self.is_underlined.instate(("selected", )): config += " underline" self.sampletitle.configure(font=config) def display_label(self, value): self.opacity_label.configure(text=" {val} %".format( val=int(float(value)))) def quit(self): self.destroy()
if ram_display: ram.set_value(round(bytes_to_gb(virtual_memory().used), 1)) else: ram.set_value(int(virtual_memory().percent)) if hasattr(sensors_battery(), 'percent'): battery.set(int(sensors_battery().percent)) if sensors_battery().power_plugged: if battery.get() == 100: p_label.config(text=' Fully charged ') else: p_label.config(text='Charging ' + (' ' * (3 - len(str(int(battery.get())))) + str(int(battery.get())) + '%')) else: p_label.config(text=f' Battery ' + (' ' * (3 - len(str(int(battery.get())))) + str(int(battery.get())) + '% ')) else: p_label.config(text='No batt present') battery.set('0') disk.set_value(int(disk_usage('/').percent)) d = datetime.now() clock_hours.set_value(d.strftime('%I').lstrip('0')) clock_minutes.set_value(d.strftime('%M')) root.attributes('-topmost', top.instate(['selected'])) root.update() sleep(0.01) except Exception: break