9292hw_lib_map = {"AUTO" : "Automatic" , "LHM" : "LibreHardwareMonitor (admin.)" , "PYTHON" : "Python libraries" ,
9393 "STUB" : "Fake random data" , "STATIC" : "Fake static data" }
9494reverse_map = {False : "classic" , True : "reverse" }
95+ weather_unit_map = {"metric" : "metric - °C" , "imperial" : "imperial - °F" , "standard" : "standard - °K" }
96+ weather_lang_map = {"sq" : "Albanian" , "af" : "Afrikaans" , "ar" : "Arabic" , "az" : "Azerbaijani" , "eu" : "Basque" ,
97+ "be" : "Belarusian" , "bg" : "Bulgarian" , "ca" : "Catalan" , "zh_cn" : "Chinese Simplified" ,
98+ "zh_tw" : "Chinese Traditional" , "hr" : "Croatian" , "cz" : "Czech" , "da" : "Danish" , "nl" : "Dutch" ,
99+ "en" : "English" , "fi" : "Finnish" , "fr" : "French" , "gl" : "Galician" , "de" : "German" , "el" : "Greek" ,
100+ "he" : "Hebrew" , "hi" : "Hindi" , "hu" : "Hungarian" , "is" : "Icelandic" , "id" : "Indonesian" ,
101+ "it" : "Italian" , "ja" : "Japanese" , "kr" : "Korean" , "ku" : "Kurmanji (Kurdish)" , "la" : "Latvian" ,
102+ "lt" : "Lithuanian" , "mk" : "Macedonian" , "no" : "Norwegian" , "fa" : "Persian (Farsi)" , "pl" : "Polish" ,
103+ "pt" : "Portuguese" , "pt_br" : "Português Brasil" , "ro" : "Romanian" , "ru" : "Russian" , "sr" : "Serbian" ,
104+ "sk" : "Slovak" , "sl" : "Slovenian" , "sp" : "Spanish" , "sv" : "Swedish" , "th" : "Thai" , "tr" : "Turkish" ,
105+ "ua" : "Ukrainian" , "vi" : "Vietnamese" , "zu" : "Zulu" }
95106
96107MAIN_DIRECTORY = str (Path (__file__ ).parent .resolve ()) + "/"
97108THEMES_DIR = MAIN_DIRECTORY + 'res/themes'
@@ -162,6 +173,9 @@ def __init__(self):
162173 self .window .bind ("<FocusIn>" , self .on_theme_change )
163174 self .window .after (0 , self .on_fan_speed_update )
164175
176+ # Subwindow for weather/ping config.
177+ self .more_config_window = MoreConfigWindow (self )
178+
165179 # Make TK look better with Sun Valley ttk theme
166180 sv_ttk .set_theme ("light" )
167181
@@ -251,6 +265,10 @@ def __init__(self):
251265 "Fans missing from the list? Install lm-sensors package\n "
252266 "and run 'sudo sensors-detect' command, then reboot." )
253267
268+ self .edit_theme_btn = ttk .Button (self .window , text = "Weather & ping" ,
269+ command = lambda : self .on_weatherping_click ())
270+ self .edit_theme_btn .place (x = 170 , y = 510 , height = 50 , width = 130 )
271+
254272 self .edit_theme_btn = ttk .Button (self .window , text = "Edit theme" , command = lambda : self .on_theme_editor_click ())
255273 self .edit_theme_btn .place (x = 310 , y = 510 , height = 50 , width = 130 )
256274
@@ -375,6 +393,9 @@ def load_config_values(self):
375393 self .on_brightness_change ()
376394 self .on_hwlib_change ()
377395
396+ # Load configuration to sub-window as well
397+ self .more_config_window .load_config_values (self .config )
398+
378399 def save_config_values (self ):
379400 self .config ['config' ]['THEME' ] = self .theme_cb .get ()
380401 self .config ['config' ]['HW_SENSORS' ] = [k for k , v in hw_lib_map .items () if v == self .hwlib_cb .get ()][0 ]
@@ -401,9 +422,23 @@ def save_config_values(self):
401422 with open ("config.yaml" , "w" , encoding = 'utf-8' ) as file :
402423 ruamel .yaml .YAML ().dump (self .config , file )
403424
425+ def save_additional_config (self , ping : str , api_key : str , lat : str , long : str , unit : str , lang : str ):
426+ self .config ['config' ]['PING' ] = ping
427+ self .config ['config' ]['WEATHER_API_KEY' ] = api_key
428+ self .config ['config' ]['WEATHER_LATITUDE' ] = lat
429+ self .config ['config' ]['WEATHER_LONGITUDE' ] = long
430+ self .config ['config' ]['WEATHER_UNITS' ] = unit
431+ self .config ['config' ]['WEATHER_LANGUAGE' ] = lang
432+
433+ with open ("config.yaml" , "w" , encoding = 'utf-8' ) as file :
434+ ruamel .yaml .YAML ().dump (self .config , file )
435+
404436 def on_theme_change (self , e = None ):
405437 self .load_theme_preview ()
406438
439+ def on_weatherping_click (self ):
440+ self .more_config_window .show ()
441+
407442 def on_theme_editor_click (self ):
408443 subprocess .Popen (MAIN_DIRECTORY + "theme-editor.py" + " \" " + self .theme_cb .get () + "\" " , shell = True )
409444
@@ -486,6 +521,139 @@ def on_fan_speed_update(self):
486521 self .window .after (500 , self .on_fan_speed_update )
487522
488523
524+ class MoreConfigWindow :
525+ def __init__ (self , main_window : TuringConfigWindow ):
526+ self .window = Toplevel ()
527+ self .window .withdraw ()
528+ self .window .title ('Configure weather & ping' )
529+ self .window .geometry ("750x400" )
530+
531+ self .main_window = main_window
532+
533+ # Make TK look better with Sun Valley ttk theme
534+ sv_ttk .set_theme ("light" )
535+
536+ self .ping_label = ttk .Label (self .window , text = 'Hostname / IP to ping' )
537+ self .ping_label .place (x = 10 , y = 10 )
538+ self .ping_entry = ttk .Entry (self .window )
539+ self .ping_entry .place (x = 190 , y = 5 , width = 250 )
540+
541+ weather_label = ttk .Label (self .window , text = 'Weather forecast (OpenWeatherMap API)' , font = 'bold' )
542+ weather_label .place (x = 10 , y = 70 )
543+
544+ weather_info_label = ttk .Label (self .window ,
545+ text = "To display weather forecast on themes that support it, you need an OpenWeatherMap \" One Call API 3.0\" key.\n "
546+ "You will get 1,000 API calls per day for free. This program is configured to stay under this threshold (~300 calls/day)." )
547+ weather_info_label .place (x = 10 , y = 100 )
548+ weather_api_link_label = ttk .Label (self .window ,
549+ text = "Click here to subscribe to OpenWeatherMap One Call API 3.0." )
550+ weather_api_link_label .place (x = 10 , y = 140 )
551+ weather_api_link_label .config (foreground = "#a3a3ff" , cursor = "hand2" )
552+ weather_api_link_label .bind ("<Button-1>" ,
553+ lambda e : webbrowser .open_new_tab ("https://openweathermap.org/api" ))
554+
555+ self .api_label = ttk .Label (self .window , text = 'OpenWeatherMap API key' )
556+ self .api_label .place (x = 10 , y = 170 )
557+ self .api_entry = ttk .Entry (self .window )
558+ self .api_entry .place (x = 190 , y = 165 , width = 250 )
559+
560+ latlong_label = ttk .Label (self .window ,
561+ text = "You can use online services to get your latitude/longitude e.g. latlong.net (click here)" )
562+ latlong_label .place (x = 10 , y = 210 )
563+ latlong_label .config (foreground = "#a3a3ff" , cursor = "hand2" )
564+ latlong_label .bind ("<Button-1>" ,
565+ lambda e : webbrowser .open_new_tab ("https://www.latlong.net/" ))
566+
567+ self .lat_label = ttk .Label (self .window , text = 'Latitude' )
568+ self .lat_label .place (x = 10 , y = 250 )
569+ self .lat_entry = ttk .Entry (self .window , validate = 'key' ,
570+ validatecommand = (self .window .register (self .validateCoord ), '%P' ))
571+ self .lat_entry .place (x = 80 , y = 245 , width = 100 )
572+
573+ self .long_label = ttk .Label (self .window , text = 'Longitude' )
574+ self .long_label .place (x = 270 , y = 250 )
575+ self .long_entry = ttk .Entry (self .window , validate = 'key' ,
576+ validatecommand = (self .window .register (self .validateCoord ), '%P' ))
577+ self .long_entry .place (x = 340 , y = 245 , width = 100 )
578+
579+ self .unit_label = ttk .Label (self .window , text = 'Units' )
580+ self .unit_label .place (x = 10 , y = 290 )
581+ self .unit_cb = ttk .Combobox (self .window , values = list (weather_unit_map .values ()), state = 'readonly' )
582+ self .unit_cb .place (x = 190 , y = 285 , width = 250 )
583+
584+ self .lang_label = ttk .Label (self .window , text = 'Language' )
585+ self .lang_label .place (x = 10 , y = 330 )
586+ self .lang_cb = ttk .Combobox (self .window , values = list (weather_lang_map .values ()), state = 'readonly' )
587+ self .lang_cb .place (x = 190 , y = 325 , width = 250 )
588+
589+ self .save_btn = ttk .Button (self .window , text = "Save settings" , command = lambda : self .on_save_click ())
590+ self .save_btn .place (x = 590 , y = 340 , height = 50 , width = 130 )
591+
592+ self .window .protocol ("WM_DELETE_WINDOW" , self .on_closing )
593+
594+ def validateCoord (self , coord : str ):
595+ if not coord :
596+ return True
597+ try :
598+ float (coord )
599+ except :
600+ return False
601+ return True
602+
603+ def show (self ):
604+ self .window .deiconify ()
605+
606+ def on_closing (self ):
607+ self .window .withdraw ()
608+
609+ def load_config_values (self , config ):
610+ self .config = config
611+
612+ try :
613+ self .ping_entry .insert (0 , self .config ['config' ]['PING' ])
614+ except :
615+ self .ping_entry .insert (0 , "8.8.8.8" )
616+
617+ try :
618+ self .api_entry .insert (0 , self .config ['config' ]['WEATHER_API_KEY' ])
619+ except :
620+ pass
621+
622+ try :
623+ self .lat_entry .insert (0 , self .config ['config' ]['WEATHER_LATITUDE' ])
624+ except :
625+ self .lat_entry .insert (0 , "45.75" )
626+
627+ try :
628+ self .long_entry .insert (0 , self .config ['config' ]['WEATHER_LONGITUDE' ])
629+ except :
630+ self .long_entry .insert (0 , "45.75" )
631+
632+ try :
633+ self .unit_cb .set (weather_unit_map [self .config ['config' ]['WEATHER_UNITS' ]])
634+ except :
635+ self .unit_cb .set (0 )
636+
637+ try :
638+ self .lang_cb .set (weather_lang_map [self .config ['config' ]['WEATHER_LANGUAGE' ]])
639+ except :
640+ self .lang_cb .set (weather_lang_map ["en" ])
641+
642+ def on_save_click (self ):
643+ self .save_config_values ()
644+ self .on_closing ()
645+
646+ def save_config_values (self ):
647+ ping = self .ping_entry .get ()
648+ api_key = self .api_entry .get ()
649+ lat = self .lat_entry .get ()
650+ long = self .long_entry .get ()
651+ unit = [k for k , v in weather_unit_map .items () if v == self .unit_cb .get ()][0 ]
652+ lang = [k for k , v in weather_lang_map .items () if v == self .lang_cb .get ()][0 ]
653+
654+ self .main_window .save_additional_config (ping , api_key , lat , long , unit , lang )
655+
656+
489657if __name__ == "__main__" :
490658 configurator = TuringConfigWindow ()
491659 configurator .run ()
0 commit comments