|
Styles
Sept 29, 2020 7:19:48 GMT -8
Post by Uncle Buddy on Sept 29, 2020 7:19:48 GMT -8
from os import path import tkinter as tk from tkinter import ttk import sqlite3 from tkinter import font from files import conn_fig import dev_tools as dt
MAX_WINDOW_HEIGHT = 0.95 MAX_WINDOW_WIDTH = 0.995
''' widget.winfo_class() is a built-in Tkinter method that refers to Tkinter classes such as 'Label' or ttk classes such as 'TLabel'. widget.winfo_subclass() is a custom method that refers to subclasses such as 'Label' that this app creates by inheriting from Tkinter. The purpose of this module is to do with Tkinter widgets what they are saying can only be done with ttk widgets: configure widgets by class instead of one at a time. This is supposed to replace or make unnecessary ttk.Style and themes using methods that novice coders can work with and understand easily while getting predictable results, whereas ttk widgets fall short in that regard. '''
# Groups of widgets that take common formatting changes # when user changes a style preference. If a subclass # fits in one of these groups just add its class name # to one of these tuples. Otherwise it has to be added # to the switch in config_generic() and given a # subfunction there to configure it. Only options that # can be changed by user need to be handled here, like # fg, bg, and font. The intended result is no styling # in the widget construction code except for class names.
# change background to formats['bg']: bg_only_bg = ( 'Frame', 'DatePrefsWidgets', 'PersonsTab', 'NamesTab', 'Treebard', 'IconMenu', 'Main', 'StatusBarTooltips', 'Colorizer', 'Search', 'Notebook', 'Toplevel', 'LabelEntryPair', 'PersonAdd', 'EditablePairs', 'LabelGoTo', 'CanvasScrolledBG1')
# change background to formats['table_head_bg']: bg_only_table_head = ('FrameHilited2',)
# change background to formats['highlight_bg']: bg_only_hilited = ( 'FrameHilited', 'FrameHilited1', 'FrameHilited4', 'LabelTitleBar', 'Sizer', 'KinTip', 'ToolTip', 'ToplevelHilited', 'CanvasScrolledBG2')
# change background, foreground to standard: bg_fg_only_standard = ('Label', 'LabelFrame', 'Sizer')
# change background, foreground to standard and font to input bg_fg_standard_font_input = ( 'Table', 'FindingsTable', 'AttributesTable', 'LabelEntrylike')
# change background, foreground to standard, # font to output, and normally disabled: bg_fg_font_state_disabled = ('LabelStylable', 'MessageCopiable')
class ThemeStyles: def __init__(self, app=None):
self.root = app
def create_custom_theme(self): ''' Customize all widgets with the push of a button without using any ttk widgets or ttk.Style. See ttk_notebook_vs_button_theme_showcase.py for voluminous notes and demo re: theme choices, a study which was necessitated by the inconsistencies of something called ttk which was created to court Windows themes when in fact Tkinter worked fine before that move was made. '''
formats = make_formats_dict()
# DELETE THIS THEME SECTION WHEN NO MORE TTK WIDGETS ARE USED ******
nix = ttk.Style()
nix.theme_create( 'tbard_wdows_theme', parent='alt', # parent='xpnative', # play with this, OK, but RESET TO 'alt'! settings={ 'TNotebook': { 'configure': { 'borderwidth': [1], 'bordercolor': ['pink'], 'padding': [16], 'tabmargins': [6, 24, 24, 24], 'background': formats['bg']}}, 'TNotebook.Tab': { 'configure': { 'padding': [6], 'background': formats['highlight_bg'], 'bordercolor': 'blue', 'width': 12, 'font': formats['output_font'], 'foreground': formats['fg'], 'focuscolor': formats['fg']},
'map': { 'background': [ ('selected', formats['bg'])], 'expand': [('selected', [3, 3, 3, 0])]}},
'TCombobox': { 'configure': { 'foreground': formats['fg'], 'fieldbackground': formats['highlight_bg'], 'selectbackground': 'steelblue', 'selectforeground': 'white'}, 'map': { 'background': [ ('focus', formats['table_head_bg'])]}},
'TEntry': { 'configure': { 'selectbackground': 'steelblue', 'selectforeground': 'white'}},
'TSizegrip': { 'configure': { 'background': formats['bg']}},
})
nix.theme_use('tbard_wdows_theme')
# make combobox dropdown lists formattable globally # this is the only way.. the listbox is tk but the entry is ttk combo_font = formats['input_font'] combo_drop_font = font.Font(family=combo_font[0], size=combo_font[1]) self.root.option_add( "*TCombobox*Listbox*Font", combo_drop_font) self.root.option_add( "*TCombobox*Listbox*Background", formats['highlight_bg']) self.root.option_add( "*TCombobox*Listbox*Foreground", formats['fg']) self.root.option_add( "*TCombobox*Listbox*selectBackground", formats['fg']) self.root.option_add( "*TCombobox*Listbox*selectForeground", formats['highlight_bg'])
# ********************** DELETE ABOVE WHEN NO MORE TTK USED *********
''' The variable formats can't be global in this module because these are reconfiguration functions and the colors that are current when this module first loads are now wrong when the recolorizer runs. A global variable would only run once when this module is imported so the little config functions have been nested inside of the main config_generic() in order to prevent querying the db once for each of the little functions. '''
def get_all_descends (self, ancestor, deep_list): lst = ancestor.winfo_children() for item in lst: deep_list.append(item) self.get_all_descends(item, deep_list) return deep_list
def config_generic(self, parent): ''' Call this for every Toplevel window constructed to apply consistent styling to tkinter widgets so widgets don't have to be styled individually, and usually ttk Styles don't have to be used. Instantiate this class in each module where widgets are made: ST = st.ThemeStyles() When all widgets have been constructed add this line: ST.config_generic(parent). Avoid ttk widgets when possible except those which don't exist in tkinter. This is also called in colorizer to change the color of everything instantly. '''
def config_labelhilited(lab): lab.config( bg=formats['highlight_bg'], fg=formats['fg'])
def config_labelhilited2(lab): bg=formats['table_head_bg'] fg=formats['fg']
def config_labeltip(lab): lab.config( bg=formats['highlight_bg'], fg=formats['fg'], font=formats['status'])
def config_labeltip2(lab): lab.config( bg=formats['table_head_bg'], fg=formats['fg'], font=formats['status'])
def config_labeltipbold(lab): lab.config( bg=formats['highlight_bg'], fg=formats['fg'], font=formats['titlebar_1'])
def config_labelitalic(lab): lab.config( bg=formats['bg'], fg=formats['fg'], font=formats['show_font'])
def config_labelnegative(lab): lab.config( bg=formats['fg'], fg=formats['bg'])
def config_heading1(lab): lab.config(bg=formats['bg'], fg=formats['fg'], font=formats['heading1'])
def config_heading2(lab): lab.config(bg=formats['bg'], fg=formats['fg'], font=formats['heading2'])
def config_heading3(lab): lab.config(bg=formats['bg'], fg=formats['fg'], font=formats['heading3'])
def config_heading4(lab): lab.config(bg=formats['bg'], fg=formats['fg'], font=formats['heading4']) def config_boilerplate(lab): lab.config( bg=formats['bg'], fg=formats['fg'], font=formats['boilerplate'])
def config_labelcolumn(lab): lab.config( bg=formats['bg'], fg=formats['fg'], font=formats['heading3'], anchor='w')
def config_labelcolumnctr(lab): lab.config( bg=formats['table_head_bg'], fg=formats['fg'], font=formats['heading3'], anchor='center')
# ************* special event widgets ********************
# widgets that have highlight/unhighlight events need some # special treatment to keep up with changes of the # color scheme. In the class definition do this: # self.formats = st.make_formats_dict() # And in the highlight/unhighlight methods do this: # bg=self.formats['blah'] ...instead of bg=formats['blah'] # And give them their very own config function here:
def config_notebook_tabs(lab): lab.formats = formats # bec. of color change on click lab.config( bg=formats['highlight_bg'], fg=formats['fg'])
def config_labelsearch(lab): lab.formats = formats lab.config( bg=formats['bg'], fg=formats['fg'])
def config_labeldots(lab): lab.formats = formats # bec. of Enter/Leave... lab.config( bg=formats['bg'], fg=formats['fg'])
def config_labelmovable(lab): lab.formats = formats # bec. of FocusIn/FocusOut... lab.config( bg=formats['highlight_bg'], font=formats['output_font'], fg=formats['fg'])
def config_entrydefaulttext(ent): ent.formats = formats # bec. of FocusIn/FocusOut... ent.config( background=formats['highlight_bg'], font=formats['show_font'])
# ***********************************
def config_buttons(button): button.config( font=(formats['output_font']), activebackground=formats['table_head_bg'], bg=formats['bg'], fg=formats['fg'])
def config_buttons_plain(button): button.config( font=(formats['input_font']), activebackground=formats['table_head_bg'], bg=formats['bg'], fg=formats['fg'])
def config_buttonflathilited(button): button.config( bg=formats['highlight_bg'], fg=formats['fg'], activebackground=formats['fg'], activeforeground=formats['bg'])
def config_radiobuttons(radio): radio.config( bg=formats['bg'], activebackground=formats['highlight_bg'], fg=formats['fg'], selectcolor=formats['highlight_bg'])
def config_radiobuttonhilited(radio): radio.config( bg=formats['highlight_bg'], activebackground=formats['bg'], fg=formats['fg'], selectcolor=formats['bg'])
def config_bg_only_bg(widg): widg.config(bg=formats['bg'])
def config_bg_only_hilited(widg): widg.config(bg=formats['highlight_bg']) def config_bg_only_table_head(widg): widg.config(bg=formats['table_head_bg'])
def config_bg_fg_only_standard(widg): widg.config(bg=formats['bg'], fg=formats['fg'])
def config_separator(sep): ''' has 3 frames with 3 different colors so needs its own reconfigure method ''' sep.colorize()
def config_combos(ent): ent.config(font=formats['input_font']) ent.config_popdown( background=formats['highlight_bg'], foreground=formats['fg'],
selectbackground=formats['fg'], selectforeground=formats['highlight_bg'])
def config_messages(widg): widg.config( bg=formats['highlight_bg'], fg=formats['fg'], font=formats['output_font'])
def config_buttonlabel(widg): widg.config( bg=formats['bg'], fg=formats['fg'], font=formats['input_font'])
def config_labeldots(widg): widg.config( bg=formats['bg'], fg=formats['fg'], font=formats['heading3'])
def config_labelcopiable(widg): widg.config(state='normal') widg.config( bg=formats['bg'], fg=formats['fg']) widg.config(state='readonly') widg.config(readonlybackground=widg.cget('background'))
def config_entry(widg): widg.config( bg=formats['highlight_bg'], fg=formats['fg'], font=formats['input_font'], insertbackground=formats['fg'], disabledbackground=formats['highlight_bg'], disabledforeground=formats['fg'])
def config_unhilited_entry(widg): widg.config( bd=0, bg=formats['bg'], fg=formats['fg'], font=formats['input_font'], insertbackground=formats['fg'], disabledbackground=formats['bg'], disabledforeground=formats['fg'])
def config_bg_fg_standard_font_input(widg): widg.config( bg=formats['bg'], fg=formats['fg'], font=formats['input_font'], insertbackground=formats['fg'], disabledbackground=formats['highlight_bg'], disabledforeground=formats['fg'])
def config_bg_fg_font_state_disabled(widg): widg.config(state='normal') widg.config( bg=formats['bg'], fg=formats['fg'], font=formats['output_font']) widg.config(state='disabled')
def config_text(widg): widg.config( bg=formats['bg'], fg=formats['fg'], insertbackground=formats['fg'])
formats = make_formats_dict()
ancestor_list = [] all_widgets_in_root = self.get_all_descends( parent, ancestor_list)
for widg in (all_widgets_in_root): if (widg.winfo_class() == 'Label' and widg.winfo_subclass() == 'LabelStay'): pass
elif widg.winfo_class() == 'Frame': if widg.winfo_subclass() == 'FrameStay': pass
elif widg.winfo_subclass() in bg_only_bg: config_bg_only_bg(widg)
elif widg.winfo_subclass() in bg_only_table_head: config_bg_only_table_head(widg)
elif widg.winfo_subclass() in bg_only_hilited: config_bg_only_hilited(widg)
elif widg.winfo_subclass() == 'TabBook': config_bg_only_hilited(widg)
elif widg.winfo_subclass() == 'Separator': config_separator(widg)
elif widg.winfo_subclass() == 'EntryDefaultText': config_entrydefaulttext(widg) # tk.Label is class elif widg.winfo_class() == 'Label': # wdg.Label is subclass if widg.winfo_subclass() in bg_fg_only_standard: # new way config_bg_fg_only_standard(widg) elif widg.winfo_subclass() == 'LabelH2': # old way config_heading2(widg) elif widg.winfo_subclass() == 'LabelH3': config_heading3(widg) elif widg.winfo_subclass() == 'LabelColumnCenter': config_labelcolumnctr(widg) elif widg.winfo_subclass() == 'LabelColumn': config_labelcolumn(widg) elif widg.winfo_subclass() == 'LabelBoilerplate': config_boilerplate(widg) elif widg.winfo_subclass() == 'LabelItalic': config_labelitalic(widg) elif widg.winfo_subclass() == 'LabelButtonText': config_buttonlabel(widg) elif widg.winfo_subclass() == 'LabelHilited': config_labelhilited(widg) elif widg.winfo_subclass() == 'LabelHilited2': config_labelhilited2(widg) elif widg.winfo_subclass() == 'LabelHilited3': config_notebook_tabs(widg) elif widg.winfo_subclass() == 'LabelTip': config_labeltip(widg) elif widg.winfo_subclass() == 'LabelTip2': config_labeltip2(widg) elif widg.winfo_subclass() == 'LabelTipBold': config_labeltipbold(widg) elif widg.winfo_subclass() == 'LabelNegative': config_labelnegative(widg) elif widg.winfo_subclass() == 'LabelSearch': config_labelsearch(widg) elif widg.winfo_subclass() == 'LabelDots': config_labeldots(widg) elif widg.winfo_subclass() == ('TitleBarButtonSolidBG'): config_bg_only_hilited(widg) elif widg.winfo_subclass() == 'LabelMovable': config_labelmovable(widg) elif widg.winfo_subclass() in bg_only_table_head: config_bg_only_table_head(widg)
elif widg.winfo_class() == 'Entry': if widg.winfo_subclass() in bg_fg_standard_font_input: config_bg_fg_standard_font_input(widg) elif widg.winfo_subclass() == 'LabelCopiable': config_labelcopiable(widg) elif widg.winfo_subclass() in ('Entry', 'EntryAutofillHilited'): config_entry(widg) elif widg.winfo_subclass() in ('EntryUnhilited', 'EntryAutofill'): config_unhilited_entry(widg)
elif widg.winfo_class() == 'TCombobox': config_combos(widg) if widg.winfo_subclass() == 'Grombo': config_entrydefaulttext(widg) elif widg.winfo_subclass() == 'ClearableReadonlyCombobox': widg.state(['!readonly', 'selected']) config_combos(widg) widg.state(['readonly'])
elif widg.winfo_class() == 'Text': if widg.winfo_subclass() in bg_fg_standard_font_input: config_text(widg)
elif widg.winfo_subclass() in bg_fg_font_state_disabled: config_bg_fg_font_state_disabled(widg)
elif widg.winfo_class() == 'Button': if widg.winfo_subclass() in ('Button', 'ButtonQuiet'): config_buttons(widg) elif widg.winfo_subclass() == 'ButtonPlain': config_buttons_plain(widg) elif widg.winfo_subclass() == 'ButtonFlatHilited': config_buttonflathilited(widg)
elif widg.winfo_class() == 'Message': config_messages(widg)
# elif widg.winfo_class() == 'Radiobutton': elif widg.winfo_class() in ('Radiobutton', 'Checkbutton'): if widg.winfo_subclass() == 'RadiobuttonHilited': config_radiobuttonhilited(widg) elif widg.winfo_subclass() in ('Radiobutton', 'Checkbutton'): config_radiobuttons(widg)
elif widg.winfo_class() == 'Canvas': if widg.winfo_subclass() == 'Canvas': config_bg_only_bg(widg) elif widg.winfo_subclass() == 'CanvasHilited': config_bg_only_hilited(widg) elif widg.winfo_subclass() == 'PedigreeChart': widg.config(bg=formats['bg']) for obj in widg.find_all(): widg.itemconfigure(obj, fill=formats['fg']) if widg.itemcget(obj, 'tags') == 'current_person': widg.itemconfigure(obj, fill=formats['table_head_bg']) elif widg.winfo_subclass() == 'Scrollbar': widg.colorize() elif widg.winfo_class() in ('Frame', 'Toplevel', 'Canvas'): config_bg_only_bg(widg)
config_bg_only_bg(parent) # important
def set_window_max_size(self, parent):
if parent.winfo_class() == 'Toplevel': parent.maxsize( width=int( parent.winfo_screenwidth()*MAX_WINDOW_WIDTH), height=int( parent.winfo_screenheight()*MAX_WINDOW_HEIGHT)) elif parent.master.winfo_class() == 'TNotebook': self.root.maxsize( width=int(self.root.winfo_screenwidth()*MAX_WINDOW_WIDTH), height=int(self.root.winfo_screenheight()*MAX_WINDOW_HEIGHT))
''' see www.colorhunt.co free stuff good lots of themes '''
def get_opening_settings(): conn = sqlite3.connect(conn_fig) cur = conn.cursor() cur.execute(''' SELECT
bg, highlight_bg, table_head_bg, fg, output_font, input_font, font_size, default_bg, default_highlight_bg, default_table_head_bg, default_fg, default_output_font, default_input_font, default_font_size FROM format WHERE format_id = 1''') user_or_default_formats = cur.fetchall()[0] cur.close() conn.close() return user_or_default_formats
def get_formats():
results = get_opening_settings() use_results = [] x = 0 for setting in results[0:7]: if setting is None or setting == '': use_results.append(results[x+7]) # get default if no user setting else: use_results.append(results[x]) x += 1 return use_results
def make_formats_dict(): ''' To add a style, add a string to the end of keys list and a line below values.append... '''
use_results = get_formats()
# use_results is ['#232931', '#393e46', '#2E5447', '#eeeeee', 'courier', 'tahoma', 14]
keys = [ 'bg', 'highlight_bg', 'table_head_bg', 'fg', 'output_font', 'input_font', 'heading1', 'heading2', 'heading3', 'heading4', 'status', 'boilerplate', 'show_font', 'titlebar_0', 'titlebar_1', 'titlebar_2', 'titlebar_3', 'titlebar_hilited_0', 'titlebar_hilited_1', 'titlebar_hilited_2', 'titlebar_hilited_3', 'unshow_font' ] values = []
values.append(use_results[0]) values.append(use_results[1]) values.append(use_results[2]) values.append(use_results[3]) values.append((use_results[4], use_results[6])) values.append((use_results[5], use_results[6])) values.append((use_results[4], use_results[6]*2, 'bold')) values.append((use_results[4], int(use_results[6]*1.5), 'bold')) values.append((use_results[4], int(use_results[6]*1.08), 'bold')) values.append((use_results[4], int(use_results[6]*0.83), 'bold')) values.append((use_results[5], int(use_results[6]*0.83))) values.append((use_results[5], int(use_results[6]*0.66))) values.append((use_results[5], use_results[6], 'italic')) values.append((use_results[5], int(use_results[6]*0.66), 'bold')) values.append((use_results[5], int(use_results[6]*0.88), 'bold')) values.append((use_results[5], int(use_results[6]*1.00), 'bold')) values.append((use_results[5], int(use_results[6]*1.25), 'bold')) values.append((use_results[5], int(use_results[6]*0.66))) values.append((use_results[5], int(use_results[6]*0.88))) values.append((use_results[5], int(use_results[6]*1.00))) values.append((use_results[5], int(use_results[6]*1.25))) values.append((use_results[5], int(use_results[6]*.88), 'italic'))
formats = dict(zip(keys, values)) return formats
formats = make_formats_dict() # print('formats is', formats)
def get_color_schemes():
conn = sqlite3.connect(conn_fig)
cur=conn.cursor()
cur.execute('SELECT bg, highlight_bg, table_head_bg, fg FROM color_scheme')
schemes = cur.fetchall()
cur.close() conn.close()
return schemes
def get_color_schemes_plus():
conn = sqlite3.connect(conn_fig)
cur=conn.cursor()
cur.execute( ''' SELECT bg, highlight_bg, table_head_bg, fg, built_in, color_scheme_id FROM color_scheme ''')
schemes = cur.fetchall()
cur.close() conn.close()
return schemes
|
|