PySimpleGUI/readme_creator/RUN_ME and START_HERE.py

693 lines
24 KiB
Python
Raw Permalink Normal View History

import time
import subprocess,re,datetime,time,os,platform,json,PySimpleGUI as sg; from subprocess import Popen; from make_real_readme import main
# mkdir
import os
cd = CD = os.path.dirname(os.path.abspath(__file__))
dir_name = os.path.join(cd, 'output')
if not os.path.exists(dir_name): os.mkdir(dir_name)
else: print(f'Такая папка уже есть: "{dir_name}"')
sg.theme('Dark2')
cd = os.path.dirname(os.path.abspath(__file__))
def readfile(filename):
with open(filename, 'r', encoding='utf-8') as ff: return ff.read()
def writefile(fpath, content):
with open(fpath, 'w', encoding='utf-8') as ff: ff.write(content)
def writejson(a_path:str, a_dict:dict) -> None:
with open(a_path, 'w', encoding='utf-8') as output_file: json.dump(a_dict, output_file, ensure_ascii=False, indent=2)
def readjson(a_path:str) -> dict:
with open(a_path, 'r', encoding='utf-8') as f: return json.load(f)
def openfile(a_path):
# File exists?
if not os.path.exists(a_path): return sg.Popup(f"Error! This file doesn't exists: {a_path}")
# check: OS
if 'Windows' in platform.system():
os.startfile(a_path)
elif 'Linux' in platform.system():
Popen(f'exo-open "{a_path}"', shell=True)
def opendir(a_path):
# Folder exists?
if not os.path.exists(a_path): return sg.Popup(f"Error! This directory doesn't exists: {a_path}")
try:
# check: OS
if 'Windows' in platform.system():
os.startfile(a_path)
elif 'Linux' in platform.system():
Popen(f'exo-open --launch FileManager --working-directory "{a_path}"', shell=True)
except Exception as e:
sg.Popen(f"Error, can't open a file: '{e}'")
########################################################################
# __ _ _ #
# / _(_) | | #
# __ __ ___ ___ _ __ | |_ _ __ _ | |__ ___ _ __ ___ #
# \ \ / / / __/ _ \| '_ \| _| |/ _` | | '_ \ / _ \ '__/ _ \ #
# \ V / | (_| (_) | | | | | | | (_| | | | | | __/ | | __/ #
# \_/ \___\___/|_| |_|_| |_|\__, | |_| |_|\___|_| \___| #
# __/ | #
# |___/ #
########################################################################
def load_configs(): return readjson(os.path.join(cd, 'app_configs.json'))
def save_configs(a_config:dict): writejson(os.path.join(cd, 'app_configs.json'), a_config)
APP_CONFIGS = load_configs()
README_OFILENAME = APP_CONFIGS['README_OFILE']
CALL_REFERENCE_OFILENAME = APP_CONFIGS['CALL_REF_OFILE']
##-#-#-# ##-#-#-#
# Post-process logic
##-#-#-# ##-#-#-#
insert_md_section_for__class_methods = False
remove_repeated_sections_classmethods = False
import time
def timeit(f):
def wrapper(*args, **kwargs):
start = time.time()
res = f(*args, **kwargs)
end = time.time()
# print('\nНачало в : ', start)
# print('\n ({}) Начало в : '.format(f.__name__, start))
# print('Окончено в : ', end)
# print('Длительность: ', end - start)
# print('')
return res
return wrapper
class BESTLOG(object):
def __init__(self, filename):
# my_file = logging.FileHandler(filename, mode='w')
# my_file.setLevel(logging.DEBUG)
# my_file.setFormatter(logging.Formatter('%(asctime)s>%(levelname)s: %(message)s'))
# logger = logging.getLogger(__name__)
# logger.setLevel(logging.DEBUG)
# logger.addHandler(my_file)
self.filename = filename
self.json_name = filename + '.json'
self.error_list = []
self.warning_list = []
self.info_list = []
self.debug_list = []
self.tick_amount=1
self.names = self.messages_names = 'error warning info debug'.split(' ')
def tick(self):
self.tick_amount+=1
return self.tick_amount
#######################################################################
# __ _ _ _ #
# / _| | | (_) | #
# | |_ ___ _ __ | |_ _ __ __ _ _ __ ___ _ __ _| | ___ _ __ #
# | _/ _ \| '__| | __| '__/ _` | '_ \/ __| '_ \| | |/ _ \ '__| #
# | || (_) | | | |_| | | (_| | | | \__ \ |_) | | | __/ | #
# |_| \___/|_| \__|_| \__,_|_| |_|___/ .__/|_|_|\___|_| #
# | | #
# |_| #
#######################################################################
def error(self, m, metadata={}):
self.error_list.append([self.tick(), m, metadata])
def warning(self, m, metadata={}):
self.warning_list.append([self.tick(), m, metadata])
def info(self, m, metadata={}):
self.info_list.append([self.tick(), m, metadata])
def debug(self, m, metadata={}):
self.debug_list.append([self.tick(), m, metadata])
##########################################
# __ #
# / _| #
# | |_ ___ _ __ _ __ ___ ___ #
# | _/ _ \| '__| | '_ ` _ \ / _ \ #
# | || (_) | | | | | | | | __/ #
# |_| \___/|_| |_| |_| |_|\___| #
# #
# #
##########################################
def tolist(self): return zip([self.error_list, self.warning_list, self.info_list, self.debug_list], self.names)
def todict(self): return {'error' : self.error_list, 'warning' : self.warning_list, 'info' : self.info_list, 'debug' : self.debug_list}
@timeit
def save(self):
'''
{
'message_type' : message_type,
'message_text' : m_text,
'message_time' : m_time,
'message_metadata' : m_metadata
}
'''
all_messages_list = []
for messages, message_type in self.tolist():
results_ = [{'message_type' : message_type,
'message_text' : m_text,
'message_time' : m_time,
'message_metadata' : m_metadata}
for m_time, m_text, m_metadata in messages]
all_messages_list.extend(results_)
# sort messages on time
all_messages_list = sorted(all_messages_list,
key=lambda x: x['message_time'])
# convert time
# for i in all_messages_list: i['message_time'] = i['message_time'].strftime('%Y-%m-%d %H:%M:%S.%f')
writejson(self.json_name, all_messages_list)
@timeit
def load(self, **kw):
'''
return dict with messages
kw = {
use_psg_color : bool
show_time : bool
}
'''
# plan:
# read json, convert time
# read
all_messages_list = readjson(self.json_name)
# convert time
# for i in all_messages_list: i['message_time'] = datetime.datetime.strptime(i['message_time'], '%Y-%m-%d %H:%M:%S.%f')
def format_message(message):
if kw['show_time']:
return str(message['message_time']) + ':' + message['message_text']
else:
return message['message_text']
#=========#
# 4 lists #
#=========#
error_list = [i for i in all_messages_list if i['message_type'] == 'error']
warning_list = [i for i in all_messages_list if i['message_type'] == 'warning']
info_list = [i for i in all_messages_list if i['message_type'] == 'info']
debug_list = [i for i in all_messages_list if i['message_type'] == 'debug']
#=================#
# and 1 more list #
#=================#
# colors = {'warning' : 'magenta', 'info' : 'black'}
colors = {'warning' : 'blue', 'info' : 'black'}
warning_info_ = []
for message in sorted(warning_list + info_list, key=lambda x: x['message_time']):
if kw['use_psg_color']:
warning_info_.append([ format_message(message),
colors.get(message['message_type']) ])
else:
warning_info_.append(format_message(message))
error_list = [format_message(i) for i in error_list]
warning_list = [format_message(i) for i in warning_list]
info_list = [format_message(i) for i in info_list]
debug_list = [format_message(i) for i in debug_list]
return error_list, warning_list, info_list, debug_list, warning_info_
@timeit
def load_to_listbox(self):
'''
read .json
'''
return sorted(readjson(self.json_name),
key=lambda x: x['message_time'])
@timeit
def compile_call_ref(output_filename='LoG_call_ref', **kw):
''' Compile a "5_call_reference.md" file'''
log_obj = BESTLOG(os.path.join(cd, output_filename))
main(logger=log_obj,
main_md_file='markdown input files/5_call_reference.md',
insert_md_section_for__class_methods=insert_md_section_for__class_methods,
remove_repeated_sections_classmethods=remove_repeated_sections_classmethods,
files_to_include=[],
output_name=CALL_REFERENCE_OFILENAME,
delete_html_comments=True)
log_obj.save()
return log_obj.load(**kw), log_obj.load_to_listbox()
@timeit
def compile_readme(output_filename='LoG', **kw):
''' Compile a "2_readme.md" file'''
log_obj = BESTLOG(os.path.join(cd, output_filename))
main(logger=log_obj,
insert_md_section_for__class_methods=insert_md_section_for__class_methods,
remove_repeated_sections_classmethods=remove_repeated_sections_classmethods,
files_to_include=[0, 1, 2, 3],
output_name=README_OFILENAME,
delete_html_comments=True)
log_obj.save()
return log_obj.load(**kw), log_obj.load_to_listbox()
def compile_all_stuff(**kw):
'''
Compile a "2_ and 5_" .md filess
return output from them
'''
return compile_readme(**kw), compile_call_ref(**kw)
########################################
# _____ #
# | __ \ #
# | |__) |__ _ __ _ _ _ __ #
# | ___/ _ \| '_ \| | | | '_ \ #
# | | | (_) | |_) | |_| | |_) | #
# |_| \___/| .__/ \__,_| .__/ #
# | | | | #
# |_| |_| #
########################################
def md2psg(target_text):
r'''
ib<space>color
i italic
b bold
color = can be word can be color
red #ff00111
green
blue
i?b?\s?\w+?
usage
*i*a** italic
*b*a** bold
*ib*a** italic bold
*ib red*a** italic bold red
*b green*a** bold green
'This was *I*special** message from *B*him**. And from *Igreen*this** to *Ired*this**'
'''
# format
# ======
font_norm = ('Mono 12 ') # (*sg.DEFAULT_FONT, 'italic')
font_bold = ('Mono 12 italic') # (*sg.DEFAULT_FONT, 'italic')
font_italic = ('Mono 12 bold') # (*sg.DEFAULT_FONT, 'bold')
list_of_Ts = []
parts = [i for i in re.compile(r'(\*I?B?[a-z]*?\*[\d\D]*?\*\*)', flags=re.M|re.DOTALL).split(target_text) if i is not None]
for index, text in enumerate(parts):
if index % 2 == 0:
# Normal text
T_text = text
T = sg.T(T_text, size=(len(T_text), 1), pad=(0,0), font=font_norm)
else:
# SPECIAL format
T_parameters = {
'font': font_norm
}
my_format = text[1:].split('*')[0]
# ::: italic
if 'I' in my_format: T_parameters['font'] = font_italic
# ::: bold
if 'B' in my_format: T_parameters['font'] = font_bold
# ::: colors
color_left = my_format.replace('I', '').replace('B', '')
if color_left: T_parameters['text_color'] = color_left
# making psg element
T_text = '*'.join(text.split('*')[2:-2])
T = sg.T(T_text, size=(len(T_text), 1), pad=(0,0), **T_parameters)
list_of_Ts.append(T)
return list_of_Ts
def mini_GUI():
my_font = ("Helvetica", 12)
my_font2 = ("Helvetica", 12, "bold")
my_font3 = ("Helvetica", 15, "bold")
my_font4 = ("Mono", 18, "bold")
def make_tab(word):
def tabs(*layouts):
return sg.TabGroup(
[[ sg.Tab(title, lay, key=f'-tab-{word_}-{index}-')
for index, (title, word_, lay) in enumerate(layouts)
]]
)
return [[
sg.Column(layout=[
[sg.T('debug', font=my_font, text_color='grey')],
[sg.ML(size=(50-15, 15), key=f'-{word}-debug-')],
[sg.T('error', font=my_font, text_color='red')],
[sg.ML(size=(50-15, 15), key=f'-{word}-error-')],
], pad=(0, 0)),
sg.T(' '),
sg.Column(layout=[
[sg.T('warning', font=my_font2)],
[sg.ML(size=(70-12, 15), key=f'-{word}-warning-')],
[sg.T('info', font=my_font2)],
[sg.ML(size=(70-12, 15), key=f'-{word}-info-')],
], pad=(0, 0)),
tabs(
('Text', word, [
[sg.T('warning info', font=my_font3)]
,[sg.ML(size=(110, 30), key=f'-{word}-warning_info-')]
]),
('Listbox', word, [
[sg.T('warning info listbox', font=my_font3)]
,[sg.Listbox([], size=(110, 30-1), key=f'-{word}-listbox-', enable_events=True, background_color='#ffccaa')]
])
)
]]
settings_layout = [
[sg.CB('Toggle progressbar', False, enable_events=True, key='toggle_progressbar')],
[
sg.Frame('Text editor', [[ sg.Combo(['pycharm', 'subl'], default_value='subl', enable_events=True, key='_text_editor_combo_') ]] ),
sg.Frame('Pycharm path:', [[ sg.I('', size=(40, 1), enable_events=True, key='_PyCharm_path_') ]] )
],
[
sg.Frame('⅀∉ Filter "empty tables"', [
[sg.T('''This is for filtering stirng, like:''')],
[sg.T('''Warning ======= We got empty md_table for "EasyPrintClose"''', font='Mono 8')],
[sg.CB('enable', True, key='checkbox_enable_empty_tables_filter', enable_events=True)],
[sg.ML('PrintClose\nEasyPrintClose\nmain\ntheme\nRead',
size=(30,10), enable_events=True, key='_filter_empty_tables_ml_')]]),
sg.Frame('⅀∉ Filter "tkinter class methods"', [
[sg.T('''This is for filtering stirng, like:''')],
[sg.T('''Please, fix ':return:' in 'SetFocus' IF you want to see 'return' row in 'signature table' ''', font='Mono 8')],
[sg.CB('enable', True, enable_events=True, key='checkbox_enable_filter_tkinter_class_methods')],
[sg.ML('SetFocus\nSetTooltip\nUpdate\n__init__\nbind\nexpand\nset_cursor\nset_size',
size=(30,10), enable_events=True, key='_filter_tkinter_class_methods_')]], visible=not True)
]
]
layout = [[sg.TabGroup([[
sg.Tab('readme logs', make_tab('README')),
sg.Tab('Call reference logs', make_tab('CALL_REF')),
sg.Tab('General settings', settings_layout)
]])]]
# ░▒▒▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▒▒░
# ░▒▒▓▓▓ progress bar ▓▓▓▒▒░
# ░▒▒▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▒▒░
from time import sleep; from math import pi, sin; from itertools import count
def next_star():
middle = 100/2
for i in (int(sin(i*pi/middle)*middle + middle) for i in count()): yield i
psg_module_path = str(sg).split("' from '")[1][:-2]
star_bar = sg.Col([
[sg.ProgressBar(max_value=100, orientation='h',
key='_star_bar1_', size=(50,5), bar_color=('blue', 'yellow'))],
[sg.ProgressBar(max_value=100, orientation='h',
key='_star_bar2_', size=(50,5), bar_color=('yellow', 'blue'))],
])
# guia
def empty_line(fontsize=12): return [sg.T('', font=('Mono '+str(fontsize)))]
window = sg.Window('We are live! Again! --- ' + 'Completed making {}, {}'.format(os.path.basename(README_OFILENAME), os.path.basename(CALL_REFERENCE_OFILENAME)), [
[sg.T(size=(30,1), key='-compile-time-'), star_bar],
empty_line(),
[*md2psg(f'The *Bmagenta*PySimpleGUI** module being processed is *Imagenta*"{psg_module_path}"**'), sg.B('< open (__init__.py)', key='open_init_file'), sg.B('< open (psg.py)', key='open_psg_file')],
# [sg.T(f'The **PySimpleGUI** module being processed is *"{psg_module_path}"*')],
empty_line(),
[
sg.B('Run again (F1)', key='-run-')
,sg.Col([
[sg.CB('show time in logs (F2)', False, enable_events=True, key='show_time')],
[sg.CB('Logs with Color (F3)', True, enable_events=True, key='use_psg_color')],
])
,sg.Col([
empty_line(5),
[sg.B('open "db folder"', key='-open_db_folder-')],
])
,sg.Frame('', [[
sg.Col([
[*md2psg('markdown outputFileName *I*FOR** *B*readme **: ')
,sg.I(README_OFILENAME, key='README_OFILE', size=(25, 1))
,sg.B('open in explorer', key='open in explorer_readme')
,sg.B('open in text editor', key='open file - readme')
]
,[*md2psg('markdown outputFileName *I*FOR** *B*call ref**: ')
,sg.I(CALL_REFERENCE_OFILENAME, key='CALL_REF_OFILE', size=(25, 1))
,sg.B('open in explorer', key='open in explorer_calref')
,sg.B('open in text editor', key='open file - calref')
]
])
]], relief=sg.RELIEF_SUNKEN, border_width=4)
]
,*layout
], resizable=True, finalize=True, location=(0,0), return_keyboard_events = True)
def update_time_in_GUI():
window['-compile-time-'](datetime.datetime.today().strftime('%Y-%m-%d %H:%M:%S.%f'))
def update_compilation_in_psg(values):
#
# ░▒▒▓▓▓▓▓◘ compile ◘▓▓▓▓▓▒▒░
#
result_readme__for_txt_n_listbox, result_call_ref__for_txt_n_listbox = compile_all_stuff(
use_psg_color=values['use_psg_color'],
show_time=values['show_time'])
result_readme_txt, result_readme_listbox_items = result_readme__for_txt_n_listbox
result_call_ref_txt, result_call_ref_listbox_items = result_call_ref__for_txt_n_listbox
#
# ░▒▒▓▓▓▓▓◘ define FILTER functions ◘▓▓▓▓▓▒▒░
#
badNames = [ i.strip() for i in values['_filter_tkinter_class_methods_'].split('\n') if i.strip()]
badNames = '|'.join(badNames)
regex_str1 = rf"fix .:return:. in .({badNames})."
badNames = [ i for i in values['_filter_empty_tables_ml_'].split('\n') if i.strip()]
badNames = '|'.join(badNames)
regex_str2 = rf'empty md_table for .({badNames}).'
def is_valid_regex_LogMessage(msg: str):
nonlocal regex_str1, regex_str2
# test 1 - filter tkinter class methods
error1_found = False
if values['checkbox_enable_filter_tkinter_class_methods'] and ':return:' in msg:
error1_found = bool(re.search(regex_str1, msg, flags=re.M|re.DOTALL))
# test 2 - filter "special empty tables"
error2_found = False
if values['checkbox_enable_empty_tables_filter'] and 'empty md_table for' in msg:
error2_found = bool(re.search(regex_str2, msg, flags=re.M|re.DOTALL))
return not error1_found and not error2_found
def filter_log_messages(messages):
if type(messages) is str:
return '\n'.join([msg for msg in messages.split('\n') if is_valid_regex_LogMessage(msg)])
raise TypeError
#
# ▓▓▓ Update GUI ▓▓▓
#
# =========== listbox's
class ParsingError(object):
def __init__(self, log_obj):
self.log_obj = log_obj
self.text = log_obj['message_text']
def __str__(self): return self.__repr__()
def __repr__(self):
'''qwe'''
# {
# 'message_type': 'info',
# 'message_text': 'STARTING',
# 'message_time': 2,
# 'message_metadata': {}
# }
text = self.log_obj['message_text']
metadata = self.log_obj['message_metadata']
lineno = ''
if 'lineno' in metadata.keys(): lineno = "(line:" + str(metadata['lineno']) + ') '
return f'{lineno} {text}'
items1 = [i for i in result_readme_listbox_items if is_valid_regex_LogMessage(i['message_text']) ]
items2 = [i for i in result_call_ref_listbox_items if is_valid_regex_LogMessage(i['message_text']) ]
window['-README-listbox-']([ ParsingError(i) for i in items1])
window['-CALL_REF-listbox-']([ ParsingError(i) for i in items2])
# =========== multitext's
def set_it(prefix = 'CALL_REF', messages_obj = result_call_ref_txt):
t_error, t_warning, t_info, t_debug = ['\n'.join(i) for i in messages_obj[:4]]
t_error = filter_log_messages(t_error)
t_warning = filter_log_messages(t_warning)
t_info = filter_log_messages(t_info)
t_debug = filter_log_messages(t_debug)
window[f'-{prefix}-error-'](t_error)
window[f'-{prefix}-warning-'](t_warning)
window[f'-{prefix}-info-'](t_info)
window[f'-{prefix}-debug-'](t_debug)
# /// colors warning_info
window[f'-{prefix}-warning_info-'].update('')
t_warning_info_obj = messages_obj[-1]
if values['use_psg_color']:
for text, color in t_warning_info_obj:
if not is_valid_regex_LogMessage(text): continue
window[f'-{prefix}-warning_info-'].print(text, text_color=color)
else:
window[f'-{prefix}-warning_info-'](t_warning_info_obj)
# two calls
set_it('README', result_readme_txt)
set_it('CALL_REF', result_call_ref_txt)
# ~~~~~~~~~~~~
# GUI updating
# ~~~~~~~~~~~~
update_time_in_GUI()
values = window.read(timeout=0)[1]
update_compilation_in_psg(values)
p_values = values
window['_PyCharm_path_'](APP_CONFIGS['_PyCharm_path_'])
window['_text_editor_combo_'].update(set_to_index=APP_CONFIGS['_text_editor_combo_']) # index
window['toggle_progressbar'](APP_CONFIGS['toggle_progressbar'])
window['checkbox_enable_empty_tables_filter'](APP_CONFIGS['checkbox_enable_empty_tables_filter'])
window['_filter_empty_tables_ml_'](APP_CONFIGS['_filter_empty_tables_ml_'])
window['checkbox_enable_filter_tkinter_class_methods'](APP_CONFIGS['checkbox_enable_filter_tkinter_class_methods'])
window['_filter_tkinter_class_methods_'](APP_CONFIGS['_filter_tkinter_class_methods_'])
window['show_time'](APP_CONFIGS['show_time'])
window['use_psg_color'](APP_CONFIGS['use_psg_color'])
window['README_OFILE'](APP_CONFIGS['README_OFILE'])
window['CALL_REF_OFILE'](APP_CONFIGS['CALL_REF_OFILE'])
next_val_gen = next_star()
my_timeout = None
while True:
event, values = window(timeout=my_timeout)
if event in ('Exit', None):
# save to disk
# APP_CONFIGS['_PyCharm_path_'] = p_values['_PyCharm_path_']
APP_CONFIGS['_text_editor_combo_'] = 1 if window['_text_editor_combo_'].get() == 'subl' else 0
APP_CONFIGS['toggle_progressbar'] = p_values['toggle_progressbar']
APP_CONFIGS['checkbox_enable_empty_tables_filter'] = p_values['checkbox_enable_empty_tables_filter']
APP_CONFIGS['_filter_empty_tables_ml_'] = p_values['_filter_empty_tables_ml_']
APP_CONFIGS['checkbox_enable_filter_tkinter_class_methods'] = p_values['checkbox_enable_filter_tkinter_class_methods']
APP_CONFIGS['_filter_tkinter_class_methods_'] = p_values['_filter_tkinter_class_methods_']
APP_CONFIGS['show_time'] = p_values['show_time']
APP_CONFIGS['use_psg_color'] = p_values['use_psg_color']
APP_CONFIGS['README_OFILE'] = p_values['README_OFILE']
APP_CONFIGS['CALL_REF_OFILE'] = p_values['CALL_REF_OFILE']
save_configs(APP_CONFIGS)
break
p_values = values
if '__TIMEOUT__' in event:
if values['toggle_progressbar']:
window['_star_bar1_'].UpdateBar(next(next_val_gen))
window['_star_bar2_'].UpdateBar(next(next_val_gen))
if '__TIMEOUT__' not in event:
print('PSG event>', event)
if event == 'toggle_progressbar':
my_timeout = None if not values['toggle_progressbar'] else 100
if event == '-README-listbox-':
metadata = values['-README-listbox-'][0].log_obj['message_metadata']
print(f'metadata = {metadata}')
if event == '-CALL_REF-listbox-':
ParsingError_obj = values['-CALL_REF-listbox-'][0]
metadata = ParsingError_obj.log_obj['message_metadata']
if 'lineno' in metadata.keys():
lineno = metadata['lineno']
texteditor = values['_text_editor_combo_']
psg_module_path_SDK = psg_module_path.replace('__init__.py', 'PySimpleGUI.py')
if 'pycharm' == texteditor:
texteditor = values['_PyCharm_path_']
subprocess.Popen(f'"{texteditor}" --line {lineno} "{psg_module_path_SDK}"', shell=True)
elif 'subl' == texteditor:
subprocess.Popen(f'{texteditor} "{psg_module_path_SDK}:{lineno}"', shell=True)
# if event == '-CALL_REF-listbox-':
# res = values['-CALL_REF-listbox-'][0]
# print(f'res = {res}')
if event == '-run-' or 'F1' in event: update_compilation_in_psg(values)
# folder
if event == '-open_db_folder-': opendir(cd)
# folder
if event == 'open in explorer_readme': opendir(os.path.dirname(os.path.join(cd, values['README_OFILE'])))
if event == 'open in explorer_calref': opendir(os.path.dirname(os.path.join(cd, values['CALL_REF_OFILE'])))
# file
if event == 'open file - readme': openfile(os.path.join(cd, values['README_OFILE']))
if event == 'open file - calref': openfile(os.path.join(cd, values['CALL_REF_OFILE']))
# file
if event == 'open_init_file': openfile(psg_module_path)
if event == 'open_psg_file': openfile(psg_module_path.replace('__init__.py', 'PySimpleGUI.py'))
# hotkeys
if 'F2' in event: window['show_time'](not values['show_time'])
if 'F3' in event: window['use_psg_color'](not values['use_psg_color'])
window.close()
if __name__ == '__main__':
mini_GUI()