2021-09-21 22:21:36 +00:00
import PySimpleGUI as sg
import sys
import datetime
"""
Another simple Desktop Widget using PySimpleGUI
The " Days UNTIL _______ " Desktop Widget ( Like Rainmeter )
This widget counts the number of days UNTIL some date of your choosing .
Maybe you want to track the number of days until an anniversary ?
Unlike other demos , this one is being released as a . pyw file . If launched on Windows , open with Pythonw . exe so
that you don ' t get a console Window. That ' s how these desktop widgets are supposed to be launched , with no
console . I usually launch them from another Python program that starts them all at once using the Exec APIs
built into PySimpleGUI .
Copyright 2021 PySimpleGUI Project
"""
ALPHA = 0.9 # Initial alpha until user changes
THEME = ' Dark green 3 ' # Initial theme until user changes
2022-02-17 00:51:47 +00:00
sg . user_settings_filename ( filename = ' DaysUntil.json ' )
2021-09-21 22:21:36 +00:00
refresh_font = sg . user_settings_get_entry ( ' -refresh font- ' , ' Courier 8 ' )
title_font = sg . user_settings_get_entry ( ' -title font- ' , ' Courier 8 ' )
main_number_font = sg . user_settings_get_entry ( ' -main number font- ' , ' Courier 70 ' )
main_info_size = ( None , 1 )
# May add ability to change theme from the user interface. For now forcing to constant
UPDATE_FREQUENCY_MILLISECONDS = 1000 * 60 * 60 # update every hour
def choose_theme ( location ) :
layout = [ [ sg . Text ( f ' Current theme { sg . theme ( ) } ' ) ] ,
[ sg . Listbox ( values = sg . theme_list ( ) , size = ( 20 , 20 ) , key = ' -LIST- ' , enable_events = True ) ] ,
[ sg . OK ( ) , sg . Cancel ( ) ] ]
window = sg . Window ( ' Look and Feel Browser ' , layout , location = location , keep_on_top = True )
old_theme = sg . theme ( )
while True : # Event Loop
event , values = window . read ( )
if event in ( sg . WIN_CLOSED , ' Exit ' , ' OK ' , ' Cancel ' ) :
break
sg . theme ( values [ ' -LIST- ' ] [ 0 ] )
test_window = make_window ( location = ( location [ 0 ] - 200 , location [ 1 ] ) , test_window = True )
test_window . read ( close = True )
window . close ( )
if event == ' OK ' and values [ ' -LIST- ' ] :
sg . theme ( values [ ' -LIST- ' ] [ 0 ] )
sg . user_settings_set_entry ( ' -theme- ' , values [ ' -LIST- ' ] [ 0 ] )
return values [ ' -LIST- ' ] [ 0 ]
else :
sg . theme ( old_theme )
return None
def make_window ( location , test_window = False ) :
title_font = sg . user_settings_get_entry ( ' -title font- ' , ' Courier 8 ' )
title = sg . user_settings_get_entry ( ' -title- ' , ' ' )
main_number_font = sg . user_settings_get_entry ( ' -main number font- ' , ' Courier 70 ' )
if not test_window :
theme = sg . user_settings_get_entry ( ' -theme- ' , THEME )
sg . theme ( theme )
alpha = sg . user_settings_get_entry ( ' -alpha- ' , ALPHA )
# ------------------- Window Layout -------------------
# If this is a test window (for choosing theme), then uses some extra Text Elements to display theme info
# and also enables events for the elements to make the window easy to close
if test_window :
top_elements = [ [ sg . Text ( title , font = title_font , justification = ' c ' , k = ' -TITLE- ' , enable_events = True ) ] ,
[ sg . Text ( ' Click to close ' , font = title_font , enable_events = True ) ] ,
[ sg . Text ( ' This is theme ' , font = title_font , enable_events = True ) ] ,
[ sg . Text ( sg . theme ( ) , font = title_font , enable_events = True ) ] ]
right_click_menu = [ [ ' ' ] , [ ' Exit ' , ] ]
else :
top_elements = [ [ sg . Text ( title , size = ( 20 , 1 ) , font = title_font , justification = ' c ' , k = ' -TITLE- ' ) ] ]
right_click_menu = [ [ ' ' ] ,
[ ' Choose Date ' , ' Choose Title ' , ' --- ' , ' Set Title Font ' , ' Set Main Font ' , ' Edit Me ' , ' Change Theme ' , ' --- ' , ' Refresh ' , ' Show Refresh Info ' , ' Hide Refresh Info ' , ' --- ' , ' Alpha ' , [ str ( x ) for x in range ( 1 , 11 ) ] , ' --- ' , ' Show Debug Info ' , ' Route Print To Screen ' , ' Stop print to screen ' , ' Exit ' , ] ]
layout = top_elements + \
[ [ sg . pin ( sg . Text ( ' 0 ' , size = main_info_size , font = main_number_font , k = ' -MAIN INFO NUM- ' , justification = ' c ' , enable_events = test_window , pad = ( 0 , 0 ) ) ) ] ,
[ sg . pin ( sg . Text ( size = ( 15 , None ) , font = refresh_font , k = ' -REFRESHED- ' , justification = ' c ' , visible = sg . user_settings_get_entry ( ' -show refresh- ' , False ) ) ) ] ]
try :
window = sg . Window ( ' Day Number ' , layout , location = location , no_titlebar = True , grab_anywhere = True , margins = ( 0 , 0 ) , element_justification = ' c ' ,
element_padding = ( 0 , 0 ) , alpha_channel = alpha , finalize = True , right_click_menu = right_click_menu , right_click_menu_tearoff = False ,
keep_on_top = True , enable_close_attempted_event = True )
except Exception as e :
if sg . popup_yes_no ( ' Error creating your window ' , e , ' These are your current settings: ' , sg . user_settings ( ) ,
' Do you want to delete your settings file? ' ) == ' Yes ' :
sg . user_settings_delete_filename ( )
sg . popup ( ' Settings deleted. ' , ' Please restart your program ' )
exit ( )
window = None
return window
def main ( location ) :
if sg . user_settings_get_entry ( ' -end date- ' , None ) is None :
sg . popup ( ' You have no yet set up an end date - set an end date to begin. ' ,
' When you close this Window you will be shown a calendar to choose an ending date. ' )
new_end = sg . popup_get_date ( keep_on_top = True )
if new_end is not None :
sg . user_settings_set_entry ( ' -end date- ' , new_end )
else :
sg . popup_error ( ' You have to set an end date to use this program. Try again later when you are ready to begin for real.... ' )
exit ( )
loc = sg . user_settings_get_entry ( ' -location- ' , location )
if sg . user_settings_get_entry ( ' -print to debug- ' , False ) is True :
mprint = sg . Print
else :
mprint = print
window = make_window ( loc )
saved_date = sg . user_settings_get_entry ( ' -end date- ' , ( 1 , 1 , 2021 ) )
end_date = datetime . datetime ( saved_date [ 2 ] , saved_date [ 0 ] , saved_date [ 1 ] )
while True : # Event Loop
# First update the status information
delta = end_date - datetime . datetime . now ( )
title_data = delta . days + 1
msg_num = f ' { title_data } '
window [ ' -MAIN INFO NUM- ' ] . update ( msg_num )
# for debugging show the last update date time
window [ ' -REFRESHED- ' ] . update ( datetime . datetime . now ( ) . strftime ( " % m/ %d / % Y \n % I: % M: % S % p " ) + \
f ' \n End date ' + end_date . strftime ( " % m/ %d / % Y " ) )
# -------------- Start of normal event loop --------------
event , values = window . read ( timeout = UPDATE_FREQUENCY_MILLISECONDS )
mprint ( event , values )
if event == sg . WIN_CLOSE_ATTEMPTED_EVENT or event == ' Exit ' :
sg . user_settings_set_entry ( ' -location- ' , window . current_location ( ) ) # The line of code to save the position before exiting
break
if event == ' Edit Me ' :
sg . execute_editor ( __file__ )
elif event == ' Choose Date ' :
new_end = sg . popup_get_date ( location = window . current_location ( ) , keep_on_top = True )
if new_end is not None :
end_date = datetime . datetime ( new_end [ 2 ] , new_end [ 0 ] , new_end [ 1 ] )
sg . user_settings_set_entry ( ' -end date- ' , new_end )
elif event == ' Choose Title ' :
new_title = sg . popup_get_text ( ' Choose a title for your date ' , default_text = sg . user_settings_get_entry ( ' -title- ' , ' ' ) , location = window . current_location ( ) , keep_on_top = True )
if new_title is not None :
window [ ' -TITLE- ' ] . update ( new_title )
sg . user_settings_set_entry ( ' -title- ' , new_title )
elif event == ' Show Refresh Info ' :
window [ ' -REFRESHED- ' ] . update ( visible = True )
sg . user_settings_set_entry ( ' -show refresh- ' , True )
elif event == ' Hide Refresh Info ' :
window [ ' -REFRESHED- ' ] . update ( visible = False )
sg . user_settings_set_entry ( ' -show refresh- ' , False )
elif event in [ str ( x ) for x in range ( 1 , 11 ) ] :
window . set_alpha ( int ( event ) / 10 )
sg . user_settings_set_entry ( ' -alpha- ' , int ( event ) / 10 )
elif event == ' Change Theme ' :
loc = window . current_location ( )
if choose_theme ( loc ) is not None :
# this is result of hacking code down to 99 lines in total. Not tried it before. Interesting test.
_ , window = window . close ( ) , make_window ( loc )
elif event == ' Set Main Font ' :
font = sg . popup_get_text ( ' Main Information Font and Size (e.g. courier 70) ' , default_text = sg . user_settings_get_entry ( ' -main number font- ' ) , keep_on_top = True , location = window . current_location ( ) )
if font :
sg . user_settings_set_entry ( ' -main number font- ' , font )
_ , window = window . close ( ) , make_window ( loc )
elif event == ' Set Title Font ' :
font = sg . popup_get_text ( ' Title Font and Size (e.g. courier 8) ' , default_text = sg . user_settings_get_entry ( ' -title font- ' ) , keep_on_top = True , location = window . current_location ( ) )
if font :
sg . user_settings_set_entry ( ' -title font- ' , font )
_ , window = window . close ( ) , make_window ( loc )
elif event == ' Show Debug Info ' :
mprint ( sg . get_versions ( ) )
elif event == ' Route Print To Screen ' :
mprint = sg . Print
elif event == ' Stop print to screen ' :
mprint = print
window . close ( )
if __name__ == ' __main__ ' :
# To start the window at a specific location, get this location on the command line
# The location should be in form x,y with no spaces
if len ( sys . argv ) > 1 :
location = sys . argv [ 1 ] . split ( ' , ' )
location = ( int ( location [ 0 ] ) , int ( location [ 1 ] ) )
else :
location = ( None , None )
main ( location )