diff --git a/ttkwidgets/autocomplete/autocomplete_entrylistbox.py b/ttkwidgets/autocomplete/autocomplete_entrylistbox.py index f10f4539..4de685fa 100644 --- a/ttkwidgets/autocomplete/autocomplete_entrylistbox.py +++ b/ttkwidgets/autocomplete/autocomplete_entrylistbox.py @@ -2,6 +2,9 @@ Author: Juliette Monsel License: GNU GPLv3 Source: This repository + +Edited by rdbende: use as well to select the completition suggestion, and listboxheight option +to set the height of the listbox """ import tkinter as tk from tkinter import ttk @@ -33,13 +36,16 @@ def __init__(self, master=None, completevalues=[], allow_other_values=False, :param font: font in entry and listbox :param autohidescrollbar: whether to use an :class:`~ttkwidgets.AutoHideScrollbar` or a :class:`ttk.Scrollbar` :type autohidescrollbar: bool + :param listboxheight: the height of the listbox given in rows + :type listboxheight: int :param kwargs: keyword arguments passed to the :class:`ttk.Frame` initializer """ - exportselection = kwargs.pop('exportselection', False) - width = kwargs.pop('width', None) - justify = kwargs.pop('justify', None) - font = kwargs.pop('font', None) - kwargs.setdefault('padding', 4) + exportselection = kwargs.pop("exportselection", False) + width = kwargs.pop("width", None) + justify = kwargs.pop("justify", None) + font = kwargs.pop("font", None) + self._listboxheight = kwargs.pop("listboxheight", 10) + kwargs.setdefault("padding", 4) ttk.Frame.__init__(self, master, **kwargs) self.columnconfigure(0, weight=1) @@ -48,30 +54,33 @@ def __init__(self, master=None, completevalues=[], allow_other_values=False, self._completevalues = completevalues validatecmd = self.register(self._validate) self.entry = ttk.Entry(self, width=width, justify=justify, font=font, - validate='key', exportselection=exportselection, + validate="key", exportselection=exportselection, validatecommand=(validatecmd, "%d", "%S", "%i", "%s", "%P")) - f = ttk.Frame(self, style='border.TFrame', padding=1) - self.listbox = tk.Listbox(f, width=width, font=font, + f = ttk.Frame(self, style="border.TFrame", padding=1) + self.listbox = tk.Listbox(f, width=width, font=font, height=self._listboxheight, exportselection=exportselection, selectmode="browse", - highlightthickness=0, relief='flat') + highlightthickness=0, relief="flat") try: self.listbox.configure(justify=justify) # this is an option only for tk >= 8.6.5 except tk.TclError: pass - self.listbox.pack(fill='both', expand=True) + self.listbox.pack(fill="both", expand=True) if autohidescrollbar: self._scrollbar = AutoHideScrollbar(self, orient=tk.VERTICAL, command=self.listbox.yview) else: self._scrollbar = ttk.Scrollbar(self, orient=tk.VERTICAL, command=self.listbox.yview) self.listbox.configure(yscrollcommand=self._scrollbar.set) - self.entry.grid(sticky='ew') - f.grid(sticky='nsew') - self._scrollbar.grid(row=1, column=1, sticky='ns') + self.entry.grid(sticky="ew") + f.grid(sticky="nsew") + self._scrollbar.grid(row=1, column=1, sticky="ns") for c in self._completevalues: - self.listbox.insert('end', c) + self.listbox.insert(tk.END, c) - self.listbox.bind('<>', self._update_entry) + self.listbox.bind("<>", self._update_entry) self.listbox.bind("", self._listbox_keypress) + # Sometimes it’s annoying that you can’t select the completition + # with Enter, only with Tab, so I added that as well + self.entry.bind("", self._tab) self.entry.bind("", self._tab) self.entry.bind("", self._right) self.entry.bind("", self._down) @@ -83,20 +92,21 @@ def __init__(self, master=None, completevalues=[], allow_other_values=False, def _select_all(self, event): """Select all entry content.""" - self.entry.selection_range(0, 'end') + self.entry.selection_range(0, tk.END) return "break" def _right(self, event): - """Move at the end of selected text on right press.""" + """Move at the end of selected text on Right press.""" if self.entry.selection_present(): self.entry.select_clear() - self.entry.icursor("end") + self.entry.icursor(tk.END) return "break" def _tab(self, event): - """Move at the end of selected text on tab press.""" + """Move at the end of selected text on Tab or Enter press.""" self.entry.select_clear() - self.entry.icursor("end") + self.entry.icursor(tk.END) + self.listbox.event_generate("<>") return "break" def _listbox_keypress(self, event): @@ -105,7 +115,7 @@ def _listbox_keypress(self, event): l = [i for i in self._completevalues if i[0].lower() == key] if l: i = self._completevalues.index(l[0]) - self.listbox.selection_clear(0, "end") + self.listbox.selection_clear(0, tk.END) self.listbox.selection_set(i) self.listbox.see(i) self._update_entry() @@ -114,44 +124,44 @@ def _up(self, event): """Navigate in the listbox with up key.""" try: i = self.listbox.curselection()[0] - self.listbox.selection_clear(0, "end") + self.listbox.selection_clear(0, tk.END) if i <= 0: i = len(self._completevalues) self.listbox.see(i - 1) self.listbox.select_set(i - 1) self.listbox.activate(i - 1) except (tk.TclError, IndexError): - self.listbox.selection_clear(0, "end") + self.listbox.selection_clear(0, tk.END) i = len(self._completevalues) self.listbox.see(i - 1) self.listbox.select_set(i - 1) self.listbox.activate(i - 1) - self.listbox.event_generate('<>') + self.listbox.event_generate("<>") return "break" def _down(self, event): """Navigate in the listbox with down key.""" try: i = self.listbox.curselection()[0] - self.listbox.selection_clear(0, "end") + self.listbox.selection_clear(0, tk.END) if i >= len(self._completevalues) - 1: i = -1 self.listbox.see(i + 1) self.listbox.select_set(i + 1) self.listbox.activate(i + 1) except (tk.TclError, IndexError): - self.listbox.selection_clear(0, "end") + self.listbox.selection_clear(0, tk.END) self.listbox.see(0) self.listbox.select_set(0) self.listbox.activate(0) - self.listbox.event_generate('<>') + self.listbox.event_generate("<>") return "break" def _validate(self, action, modif, pos, prev_txt, new_txt): """Complete the text in the entry with values.""" try: sel = self.entry.selection_get() - txt = prev_txt.replace(sel, '') + txt = prev_txt.replace(sel, "") except tk.TclError: txt = prev_txt if action == "0": @@ -162,13 +172,13 @@ def _validate(self, action, modif, pos, prev_txt, new_txt): l = [i for i in self._completevalues if i[:len(txt)] == txt] if l: i = self._completevalues.index(l[0]) - self.listbox.selection_clear(0, "end") + self.listbox.selection_clear(0, tk.END) self.listbox.selection_set(i) self.listbox.see(i) index = self.entry.index("insert") - self.entry.delete(0, "end") + self.entry.delete(0, tk.END) self.entry.insert(0, l[0].replace("\ ", " ")) - self.entry.selection_range(index + 1, "end") + self.entry.selection_range(index + 1, tk.END) self.entry.icursor(index + 1) return True else: @@ -186,16 +196,16 @@ def _update_entry(self, event=None): sel = self.listbox.get(self.listbox.curselection()[0]) except (tk.TclError, IndexError): return - self.entry.delete(0, "end") + self.entry.delete(0, tk.END) self.entry.insert(0, sel) self.entry.selection_clear() - self.entry.icursor("end") - self.event_generate('<>') + self.entry.icursor(tk.END) + self.event_generate("<>") def keys(self): keys = ttk.Frame.keys(self) - keys.extend(['completevalues', 'allow_other_values', 'exportselection', - 'justify', 'font']) + keys.extend(["completevalues", "allow_other_values", "exportselection", + "justify", "font", "listboxheight"]) return keys def get(self): @@ -203,13 +213,15 @@ def get(self): return self.entry.get() def cget(self, key): - if key == 'allow_other_values': + if key == "allow_other_values": return self._allow_other_values - elif key == 'completevalues': + elif key == "completevalues": return self._completevalues - elif key == 'autohidescrollbar': + elif key == "autohidescrollbar": return isinstance(self._scrollbar, AutoHideScrollbar) - elif key in ['justify', 'font', 'exportselection', 'width']: + elif key == "listboxheight": + return self._listboxheight + elif key in ["justify", "font", "exportselection", "width"]: return self.entry.cget(key) else: return ttk.Frame.cget(self, key) @@ -219,17 +231,17 @@ def configure(self, cnf={}, **kw): kwargs.update(cnf) kwargs.update(kw) # completion settings - self._allow_other_values = kwargs.pop('allow_other_values', self._allow_other_values) - if 'completevalues' in kwargs: - completevalues = kwargs.pop('completevalues') + self._allow_other_values = kwargs.pop("allow_other_values", self._allow_other_values) + if "completevalues" in kwargs: + completevalues = kwargs.pop("completevalues") self._completevalues = completevalues - self.listbox.delete(0, 'end') + self.listbox.delete(0, tk.END) for c in self._completevalues: - self.listbox.insert('end', c) + self.listbox.insert(tk.END, c) # autohidescrollbar autohidescrollbar = isinstance(self._scrollbar, AutoHideScrollbar) - autohidescrollbar2 = kwargs.pop('autohidescrollbar', autohidescrollbar) + autohidescrollbar2 = kwargs.pop("autohidescrollbar", autohidescrollbar) if autohidescrollbar != autohidescrollbar2: self._scrollbar.destroy() if autohidescrollbar2: @@ -237,21 +249,24 @@ def configure(self, cnf={}, **kw): else: self._scrollbar = ttk.Scrollbar(self, orient=tk.VERTICAL, command=self.listbox.yview) self.listbox.configure(yscrollcommand=self._scrollbar.set) - self._scrollbar.grid(row=1, column=1, sticky='ns') + self._scrollbar.grid(row=1, column=1, sticky="ns") # entry/listbox settings entry_listbox_kw = {} - for key in ['font', 'exportselection', 'width']: + for key in ["font", "exportselection", "width"]: if key in kwargs: entry_listbox_kw[key] = kwargs.pop(key) self.entry.configure(entry_listbox_kw) self.listbox.configure(entry_listbox_kw) - if 'justify' in kwargs: - justify = kwargs.pop('justify') + if "justify" in kwargs: + justify = kwargs.pop("justify") self.entry.configure(justify=justify) try: self.listbox.configure(justify=justify) # this is an option only for tk >= 8.6.5 except tk.TclError: pass + if "listboxheight" in kwargs: + self._listboxheight = kwargs.pop("listboxheight", "10") + self.listbox.configure(height=self._listboxheight) # frame settings ttk.Frame.config(self, kwargs) diff --git a/ttkwidgets/font/chooser.py b/ttkwidgets/font/chooser.py index 2d09a5c3..7a058645 100644 --- a/ttkwidgets/font/chooser.py +++ b/ttkwidgets/font/chooser.py @@ -2,6 +2,8 @@ Author: RedFantom License: GNU GPLv3 Source: This repository + +Edited by rdbende: translation, autocompleteentrylistbox, and defult font option """ # Based on an idea by Nelson Brochado (https://www.github.com/nbro/tkinter-kit) import tkinter as tk @@ -10,6 +12,39 @@ from .familylistbox import FontFamilyListbox from .sizedropdown import FontSizeDropdown from .propertiesframe import FontPropertiesFrame +from .familydropdown import FontFamilyDropdown +from locale import getdefaultlocale + + +# --- Translation +EN = {"Font family": "Font family", "Font properties": "Font properties", + "Font size": "Font size", "Cancel": "Cancel", "Font Chooser": "Font Chooser"} + +FR = {"Font family": "Famille", "Font properties": "Propriétés", + "Font size": "Taille", "Cancel": "Annuler", "Font Chooser": "Sélecteur de polices"} + +DE = {"Font family": "Familie", "Font properties": "Eigenschaften", + "Font size": "Schriftgröße", "Cancel": "Abbrechen", "Font Chooser": "Schriftauswahl"} + +HU = {"Font family": "Betűtípus", "Font properties": "Betűstílus", + "Font size": "Méret", "Cancel": "Mégse", "Font Chooser": "Betűtípus"} + +try: + if getdefaultlocale()[0][:2] == "fr": + TR = FR + elif getdefaultlocale()[0][:2] == "de": + TR = DE + elif getdefaultlocale()[0][:2] == "hu": + TR = HU + else: + TR = EN +except ValueError: + TR = EN + + +def tr(text): + """Translate text.""" + return TR.get(text, text) class FontChooser(tk.Toplevel): @@ -18,53 +53,68 @@ class FontChooser(tk.Toplevel): Should only be used through :func:`askfont`. """ - def __init__(self, master=None, **kwargs): + def __init__(self, master=None, title=None, default=("Arial", 9), **kwargs): """ Create a FontChooser. :param master: master window :type master: widget + :param title: dialog title + :type title: str + :param default: set the default font, family and size must be specified: (family, size, options) + :type default: tuple :param kwargs: keyword arguments passed to :class:`tk.Toplevel` initializer """ tk.Toplevel.__init__(self, master, **kwargs) - self.wm_title("Choose a font") + + self.title(title) + self.transient(self.master) self.resizable(False, False) - self.style = ttk.Style() - self.style.configure("FontChooser.TLabel", font=("default", 11), relief=tk.SUNKEN, anchor=tk.CENTER) - self._font_family_header = ttk.Label(self, text="Font family", style="FontChooser.TLabel") - self._font_family_list = FontFamilyListbox(self, callback=self._on_family, height=8) - self._font_label_variable = tk.StringVar() - self._font_label = ttk.Label(self, textvariable=self._font_label_variable, background="white") - self._font_properties_header = ttk.Label(self, text="Font properties", style="FontChooser.TLabel") - self._font_properties_frame = FontPropertiesFrame(self, callback=self._on_properties, label=False) - self._font_size_header = ttk.Label(self, text="Font size", style="FontChooser.TLabel") - self._size_dropdown = FontSizeDropdown(self, callback=self._on_size, width=4) - self._example_label = tk.Label(self, text="Example", anchor=tk.CENTER, background="white", height=2, - relief=tk.SUNKEN) - self._family = None - self._size = 11 - self._bold = False - self._italic = False - self._underline = False - self._overstrike = False + self._family = default[0] + self._size = default[1] + self._bold = True if "bold" in default else False + self._italic = True if "italic" in default else False + self._underline = True if "underline" in default else False + self._overstrike = True if "overstrike" in default else False + + self._font_family_frame = ttk.LabelFrame(self, text=tr("Font family")) + # I don't know why, but search with lowercase characters doesn't work for me + self._font_family_list = FontFamilyListbox(self._font_family_frame, callback=self._on_family, + font=default, listboxheight=8) + self._font_properties_frame = ttk.LabelFrame(self, text=tr("Font properties")) + self._font_properties = FontPropertiesFrame(self._font_properties_frame, callback=self._on_properties, + font=self.__generate_font_tuple()[2:], label=False) + self._font_size_frame = ttk.LabelFrame(self, text=tr("Font size")) + self._size_dropdown = FontSizeDropdown(self._font_size_frame, font=default, callback=self._on_size, width=6) + self._example_label = tk.Label(self, text="AaBbYyZz01", height=2, anchor=tk.CENTER, relief=tk.SOLID, borderwidth=1) + self._font = None - self._ok_button = ttk.Button(self, text="OK", command=self._close) - self._cancel_button = ttk.Button(self, text="Cancel", command=self._cancel) + self._ok_button = ttk.Button(self, text="Ok", command=self._close) + self._cancel_button = ttk.Button(self, text=tr("Cancel"), command=self._cancel) self._grid_widgets() + self._on_change() + + # To be consistent with colorpicker + self.wait_visibility() + self.lift() + self.grab_set() def _grid_widgets(self): """Puts all the child widgets in the correct position.""" - self._font_family_header.grid(row=0, column=1, sticky="nswe", padx=5, pady=5) - self._font_label.grid(row=1, column=1, sticky="nswe", padx=5, pady=(0, 5)) - self._font_family_list.grid(row=2, rowspan=3, column=1, sticky="nswe", padx=5, pady=(0, 5)) - self._font_properties_header.grid(row=0, column=2, sticky="nswe", padx=5, pady=5) - self._font_properties_frame.grid(row=1, rowspan=2, column=2, sticky="we", padx=5, pady=5) - self._font_size_header.grid(row=3, column=2, sticky="we", padx=5, pady=5) - self._size_dropdown.grid(row=4, column=2, sticky="we", padx=5, pady=5) - self._example_label.grid(row=5, column=1, columnspan=2, sticky="nswe", padx=5, pady=5) - self._ok_button.grid(row=6, column=2, sticky="nswe", padx=5, pady=5) - self._cancel_button.grid(row=6, column=1, sticky="nswe", padx=5, pady=5) + self._font_family_frame.grid(row=0, rowspan=2, column=0, sticky="nswe", padx=5, pady=5) + self._font_family_list.grid(row=0, column=0, sticky="nswe", padx=5, pady=(0, 5)) + + self._font_properties_frame.grid(row=0, column=1, columnspan=2, sticky="nswe", padx=5, pady=5) + self._font_properties.pack(anchor=tk.CENTER, pady=15) + + self._font_size_frame.grid(row=1, column=1, columnspan=2, sticky="nswe", padx=5, pady=5) + self._size_dropdown.pack(anchor=tk.CENTER, pady=15) + + self._example_label.grid(row=2, column=0, columnspan=3, sticky="nswe", padx=5, pady=5) + + self._ok_button.grid(row=3, column=1, sticky="e", padx=5, pady=5) + self._cancel_button.grid(row=3, column=2, sticky="e", padx=5, pady=5) def _on_family(self, family): """ @@ -72,7 +122,6 @@ def _on_family(self, family): :param family: family name """ - self._font_label_variable.set(family) self._family = family self._on_change() @@ -146,12 +195,19 @@ def _cancel(self): self.destroy() -def askfont(): +def askfont(master=None, title=tr("Font Chooser"), default=("Arial", 9)): """ - Opens a :class:`FontChooser` toplevel to allow the user to select a font + Opens a :class:`FontChooser` dialog and return the chosen font. :return: font tuple (family_name, size, \*options), :class:`~font.Font` object + + :param master: parent widget + :type master: widget + :param title: dialog title + :type title: str + :param default: set the default font, family and size must be specified: (family, size, options) + :type default: tuple """ - chooser = FontChooser() - chooser.wait_window() + chooser = FontChooser(master, title, default) + chooser.wait_window(chooser) return chooser.font diff --git a/ttkwidgets/font/familydropdown.py b/ttkwidgets/font/familydropdown.py index d4fadcbd..fe3d5933 100644 --- a/ttkwidgets/font/familydropdown.py +++ b/ttkwidgets/font/familydropdown.py @@ -2,10 +2,12 @@ Author: RedFantom License: GNU GPLv3 Source: This repository + +Edited by rdbende: default font family option """ # Based on an idea by Nelson Brochado (https://www.github.com/nbro/tkinter-kit) import tkinter as tk -from tkinter import font +from tkinter import font as tkfont from ttkwidgets.autocomplete import AutocompleteCombobox @@ -14,7 +16,7 @@ class FontFamilyDropdown(AutocompleteCombobox): A dropdown menu to select a font family with callback support and selection property. """ - def __init__(self, master=None, callback=None, **kwargs): + def __init__(self, master=None, callback=None, font=None, **kwargs): """ Create a FontFamilyDropdown. @@ -22,15 +24,18 @@ def __init__(self, master=None, callback=None, **kwargs): :type master: widget :param callback: callable object with single argument: font family name :type callback: function + :param font: set the default font family, family and size must be specified + :type font: tuple :param kwargs: keyword arguments passed on to the :class:`~ttkwidgets.autocomplete.AutocompleteCombobox` initializer """ - font_families = sorted(set(font.families())) - self._fonts = font_families + self._font_families = sorted(set(tkfont.families())) self._font = tk.StringVar(master) self.__callback = callback - AutocompleteCombobox.__init__(self, master, textvariable=self._font, completevalues=font_families, **kwargs) + AutocompleteCombobox.__init__(self, master, textvariable=self._font, completevalues=self._font_families, **kwargs) self.bind("<>", self._on_select) self.bind("", self._on_select) + if font: + self.set(font[0]) def _on_select(self, *args): """ @@ -49,7 +54,7 @@ def selection(self): :return: None if no font is selected and font family name if one is selected. :rtype: None or str """ - if self._font.get() is "" or self._font.get() not in self._fonts: + if self._font.get() == "" or self._font.get() not in self._font_families: return None else: return self._font.get() diff --git a/ttkwidgets/font/familylistbox.py b/ttkwidgets/font/familylistbox.py index ea50e46a..4cf8ce08 100644 --- a/ttkwidgets/font/familylistbox.py +++ b/ttkwidgets/font/familylistbox.py @@ -2,20 +2,23 @@ Author: RedFantom License: GNU GPLv3 Source: This repository + +Edited by rdbende to use AutocompleteEntryListbox to improve font search, +and for allow default font family option """ # Based on an idea by Nelson Brochado (https://www.github.com/nbro/tkinter-kit) import tkinter as tk -from tkinter import font -from ttkwidgets import ScrolledListbox +from tkinter import font as tkfont +from ttkwidgets.autocomplete.autocomplete_entrylistbox import AutocompleteEntryListbox -class FontFamilyListbox(ScrolledListbox): +class FontFamilyListbox(AutocompleteEntryListbox): """ - :class:`~ttkwidgets.ScrolledListbox` listing all font families available on the system with a Scrollbar on the right with the option - of a callback when double clicked and a property to get the font family name. + :class:`~ttkwidgets.AutocompleteEntryListbox` listing all font families available + on the system """ - def __init__(self, master=None, callback=None, **kwargs): + def __init__(self, master=None, callback=None, font=None, **kwargs): """ Create a FontFamilyListbox. @@ -23,17 +26,16 @@ def __init__(self, master=None, callback=None, **kwargs): :type master: widget :param callback: callable object with one argument: the font family name :type callback: function + :param font: set the default font family, family and size must be specified + :type font: tuple :param kwargs: keyword arguments passed to :class:`~ttkwidgets.ScrolledListbox`, in turn passed to :class:`tk.Listbox` """ - ScrolledListbox.__init__(self, master, compound=tk.RIGHT, **kwargs) self._callback = callback - font_names = sorted(set(font.families())) - index = 0 - self.font_indexes = {} - for name in font_names: - self.listbox.insert(index, name) - self.font_indexes[index] = name - index += 1 + self._font_families = sorted(set(tkfont.families())) + AutocompleteEntryListbox.__init__(self, master, completevalues=self._font_families, **kwargs) + if font: + self.listbox.selection_set(self._font_families.index(font[0])) + self.listbox.yview_scroll(self._font_families.index(font[0]), "units") self.listbox.bind("<>", self._on_click) def _on_click(self, *args): @@ -48,12 +50,12 @@ def _on_click(self, *args): @property def selection(self): """ - Selection property. + Selection property. :return: None if no font is selected and font family name if one is selected. :rtype: None or str """ selection = self.listbox.curselection() - if len(selection) is 0: + if len(selection) == 0: return None - return self.font_indexes[self.listbox.curselection()[0]] + return self._font_families[selection[0]] diff --git a/ttkwidgets/font/propertiesframe.py b/ttkwidgets/font/propertiesframe.py index 3ac44e40..f2b585f8 100644 --- a/ttkwidgets/font/propertiesframe.py +++ b/ttkwidgets/font/propertiesframe.py @@ -2,10 +2,39 @@ Author: RedFantom License: GNU GPLv3 Source: This repository + +Edited by rdbende: translation and default font properties option """ # Based on an idea by Nelson Brochado (https://www.github.com/nbro/tkinter-kit) import tkinter as tk from tkinter import ttk +from locale import getdefaultlocale + +# --- Translation +EN = {"Font properties:": "Font properties:"} + +FR = {"Font properties:": "Propriétés"} + +DE = {"Font properties:": "Eigenschaften"} + +HU = {"Font properties:": "Betűstílus"} + +try: + if getdefaultlocale()[0][:2] == "fr": + TR = FR + elif getdefaultlocale()[0][:2] == "de": + TR = DE + elif getdefaultlocale()[0][:2] == "hu": + TR = HU + else: + TR = EN +except ValueError: + TR = EN + + +def tr(text): + """Translate text.""" + return TR.get(text, text) class FontPropertiesFrame(ttk.Frame): @@ -13,7 +42,7 @@ class FontPropertiesFrame(ttk.Frame): Simple frame with buttons for Bold, Italic and Underline font types. """ - def __init__(self, master=None, callback=None, label=True, fontsize=11, **kwargs): + def __init__(self, master=None, callback=None, label=True, font=None, fontsize=11, **kwargs): """ Create a FontPropertiesFrame. @@ -24,6 +53,8 @@ def __init__(self, master=None, callback=None, label=True, fontsize=11, **kwargs :type callback: function :param label: show a header label :type label: str + :param font: set the default font properties + :type font: tuple :param fontsize: size of the font on the buttons :type fontsize: int :param kwargs: keyword arguments passed on to the :class:`ttk.Frame` initializer @@ -32,23 +63,26 @@ def __init__(self, master=None, callback=None, label=True, fontsize=11, **kwargs self._style = ttk.Style() self.__label = label self.__callback = callback - self._header_label = ttk.Label(self, text="Font properties:") + self._header_label = ttk.Label(self, text=tr("Font properties:")) + self._style.configure("Bold.Toolbutton", font=("default", fontsize, "bold"), anchor=tk.CENTER) self._style.configure("Italic.Toolbutton", font=("default", fontsize, "italic"), anchor=tk.CENTER) self._style.configure("Underline.Toolbutton", font=("default", fontsize, "underline"), anchor=tk.CENTER) self._style.configure("Overstrike.Toolbutton", font=("default", fontsize, "overstrike"), anchor=tk.CENTER) - self._bold = tk.BooleanVar() - self._italic = tk.BooleanVar() - self._underline = tk.BooleanVar() - self._overstrike = tk.BooleanVar() - self._bold_button = ttk.Checkbutton(self, style="Bold.Toolbutton", text="B", width=2, command=self._on_click, - variable=self._bold) + + self._bold = tk.BooleanVar(value=True if "bold" in font else False) + self._italic = tk.BooleanVar(value=True if "italic" in font else False) + self._underline = tk.BooleanVar(value=True if "underline" in font else False) + self._overstrike = tk.BooleanVar(value=True if "overstrike" in font else False) + + self._bold_button = ttk.Checkbutton(self, style="Bold.Toolbutton", text="B", width=2, + command=self._on_click, variable=self._bold, offvalue=False) self._italic_button = ttk.Checkbutton(self, style="Italic.Toolbutton", text="I", width=2, - command=self._on_click, variable=self._italic) + command=self._on_click, variable=self._italic, offvalue=False) self._underline_button = ttk.Checkbutton(self, style="Underline.Toolbutton", text="U", width=2, - command=self._on_click, variable=self._underline) + command=self._on_click, variable=self._underline, offvalue=False) self._overstrike_button = ttk.Checkbutton(self, style="Overstrike.Toolbutton", text="O", width=2, - command=self._on_click, variable=self._overstrike) + command=self._on_click, variable=self._overstrike, offvalue=False) self._grid_widgets() def _grid_widgets(self): @@ -65,8 +99,18 @@ def _grid_widgets(self): def _on_click(self): """Handles clicks and calls callback.""" + if callable(self.__callback): - self.__callback((self.bold, self.italic, self.underline, self.overstrike)) + self.__callback((self.__generate_prop_tuple())) + + def __generate_prop_tuple(self): + """ + Generate a prop tuple for tkinter widgets based on the user's entries. + + :return: prop tuple (*options) + """ + prop = (self._bold.get(), self._italic.get(), self._underline.get(), self._overstrike.get()) + return prop @property def bold(self): diff --git a/ttkwidgets/font/selectframe.py b/ttkwidgets/font/selectframe.py index aea0446f..c13084b9 100644 --- a/ttkwidgets/font/selectframe.py +++ b/ttkwidgets/font/selectframe.py @@ -2,10 +2,13 @@ Author: RedFantom License: GNU GPLv3 Source: This repository + +Edited by rdbende: default font option """ # Based on an idea by Nelson Brochado (https://www.github.com/nbro/tkinter-kit) +import tkinter as tk from tkinter import ttk -from tkinter import font +from tkinter import font as tkfont from .familydropdown import FontFamilyDropdown from .propertiesframe import FontPropertiesFrame from .sizedropdown import FontSizeDropdown @@ -18,27 +21,35 @@ class FontSelectFrame(ttk.Frame): For :class:`~font.Font` object, use :obj:`font` property. """ - def __init__(self, master=None, callback=None, **kwargs): + def __init__(self, master=None, callback=None, default=("Arial", 9), **kwargs): """ :param master: master widget :type master: widget :param callback: callback passed argument (`str` family, `int` size, `bool` bold, `bool` italic, `bool` underline) :type callback: function + :param default: set the default font, family and size must be specified: (family, size, options) + :type default: tuple :param kwargs: keyword arguments passed on to the :class:`ttk.Frame` initializer """ ttk.Frame.__init__(self, master, **kwargs) self.__callback = callback - self._family = None - self._size = 11 - self._bold = False - self._italic = False - self._underline = False - self._overstrike = False - self._family_dropdown = FontFamilyDropdown(self, callback=self._on_family) - self._size_dropdown = FontSizeDropdown(self, callback=self._on_size, width=4) - self._properties_frame = FontPropertiesFrame(self, callback=self._on_properties, label=False) + self._family = default[0] + self._size = default[1] + + self._bold = True if "bold" in default else False + self._italic = True if "italic" in default else False + self._underline = True if "underline" in default else False + self._overstrike = True if "overstrike" in default else False + + self._family_dropdown = FontFamilyDropdown(self, font=default, callback=self._on_family) + self._size_dropdown = FontSizeDropdown(self, font=default, callback=self._on_size, width=6) + self._properties_frame = FontPropertiesFrame(self, callback=self._on_properties, font=self.__generate_font_tuple()[2:], label=False) self._grid_widgets() + # Unfortunately we can't just call _on_change, + # because if the callback function uses the returned value (like in the example) + # it raises error, because the widget basically does not exist until the end of __init__ + # self._on_change() def _grid_widgets(self): """ @@ -65,7 +76,7 @@ def _on_size(self, size): """ self._size = size self._on_change() - + def _on_properties(self, properties): """ Callback if properties are changed @@ -74,16 +85,17 @@ def _on_properties(self, properties): """ self._bold, self._italic, self._underline, self._overstrike = properties self._on_change() - + def _on_change(self): """Call callback if any property is changed.""" if callable(self.__callback): - self.__callback((self._family, self._size, self._bold, self._italic, self._underline, self._overstrike)) + font = self.__generate_font_tuple() + self.__callback(font) def __generate_font_tuple(self): """ Generate a font tuple for tkinter widgets based on the user's entries. - + :return: font tuple (family_name, size, *options) """ if not self._family: @@ -102,17 +114,17 @@ def __generate_font_tuple(self): @property def font(self): """ - Font property. - - :return: a :class:`~font.Font` object if family is set, else None - :rtype: :class:`~font.Font` or None + Selected font. + + :return: font tuple (family_name, size, \*options), :class:`~font.Font` object """ - if not self._family: + if self._family is None: return None, None - font_obj = font.Font(family=self._family, size=self._size, - weight=font.BOLD if self._bold else font.NORMAL, - slant=font.ITALIC if self._italic else font.ROMAN, - underline=1 if self._underline else 0, - overstrike=1 if self._overstrike else 0) - font_tuple = self.__generate_font_tuple() - return font_tuple, font_obj + else: + font_tuple = self.__generate_font_tuple() + font_obj = tkfont.Font(family=self._family, size=self._size, + weight=tkfont.BOLD if self._bold else tkfont.NORMAL, + slant=tkfont.ITALIC if self._italic else tkfont.ROMAN, + underline=1 if self._underline else 0, + overstrike=1 if self._overstrike else 0) + return font_tuple, font_obj diff --git a/ttkwidgets/font/sizedropdown.py b/ttkwidgets/font/sizedropdown.py index 4ab9be87..61e36d9f 100644 --- a/ttkwidgets/font/sizedropdown.py +++ b/ttkwidgets/font/sizedropdown.py @@ -2,6 +2,8 @@ Author: RedFantom License: GNU GPLv3 Source: This repository + +Edited by rdbende: default font size option """ # Based on an idea by Nelson Brochado (https://www.github.com/nbro/tkinter-kit) from ttkwidgets.autocomplete import AutocompleteCombobox @@ -12,12 +14,14 @@ class FontSizeDropdown(AutocompleteCombobox): A dropdown with default font sizes """ - def __init__(self, master=None, callback=None, **kwargs): + def __init__(self, master=None, callback=None, font=None, **kwargs): """ :param master: master widget :type master: widget :param callback: callback on click with single argument: `int` size :type callback: function + :param font: set the default font family, family and size must be specified + :type font: tuple :param kwargs: keyword arguments passed on to the :class:`~ttkwidgets.autocomplete.AutocompleteCombobox` initializer """ int_values = [8, 9, 10, 11, 12, 14, 16, 18, 20, 22, 24, 26, 28, 36, 48, 72] @@ -26,7 +30,8 @@ def __init__(self, master=None, callback=None, **kwargs): self.bind("<>", self._on_click) self.bind("", self._on_click) self.__callback = callback - self.insert(0, "12") + if font: + self.set(font[1]) def _on_click(self, event): """ @@ -45,7 +50,7 @@ def selection(self): :return: None if no value is selected and size if selected. :rtype: None or int """ - if self.get() is "": + if self.get() == "": return None else: return int(self.get())