@@ -485,19 +485,40 @@ def _update_label(self):
485485 # Choose which label set to update (primary or alternate)
486486 active_widgets = self ._widgets_alt if self ._show_alt_label else self ._widgets
487487 active_label_content = self ._label_alt_content if self ._show_alt_label else self ._label_content
488- label_parts = re .split ("(<span.*?>.*?</span>)" , active_label_content )
489- label_parts = [part for part in label_parts if part ]
490488 widget_index = 0
489+
491490 now = datetime .now (ZoneInfo (self ._active_tz )) if self ._active_tz else datetime .now ().astimezone ()
491+
492+ # Finding the datetime format string in the label using keyerror exception.
493+ # This code assumes that there's only 1 time format placeholder in the label.
494+ try :
495+ active_label_content .format (icon = "" , alarm = "" , timedata = now )
496+ except KeyError as ke :
497+ # Remove the quotes around the exception message to get the datetime format.
498+ datetime_format = str (ke )[1 :- 1 ]
499+
500+ datetime_format_idx = active_label_content .find (datetime_format )
501+ closing_braces_idx = active_label_content .find ("}" , datetime_format_idx + len (datetime_format ))
502+
503+ datetime_format = active_label_content [datetime_format_idx :closing_braces_idx ]
504+ active_label_content = active_label_content .replace (
505+ "{" + datetime_format + "}" , now .strftime (datetime_format )
506+ )
507+
492508 current_hour = f"{ now .hour :02d} "
493509 current_minute = f"{ now .minute :02d} "
494510 hour_changed = self ._current_hour != current_hour
495511 minute_changed = self ._current_minute != current_minute
512+
496513 if hour_changed :
497514 self ._current_hour = current_hour
515+
498516 if minute_changed :
499517 self ._current_minute = current_minute
500518
519+ has_alarm = self ._shared_state ._snoozed_alarms or self ._has_enabled_alarms ()
520+ alarm_state_changed = has_alarm != self ._previous_alarm_state
521+
501522 # Temporarily switch locale so strftime outputs are localized
502523 org_locale_time , org_locale_ctype = self ._set_locale_context ()
503524
@@ -513,75 +534,57 @@ def _update_label(self):
513534 self ._timer_label .hide ()
514535 self ._timer_visible = False
515536
537+ clock_icon = self ._get_icon_for_hour (now .hour )
538+ hour_class = f"clock_{ current_hour } "
539+ alarm_icon = alarm_class = ""
540+
541+ if self ._shared_state ._snoozed_alarms :
542+ alarm_class = "icon alarm snooze"
543+ alarm_icon = self .config .alarm_icons .snooze
544+
545+ elif self ._has_enabled_alarms ():
546+ alarm_icon = self .config .alarm_icons .enabled
547+ alarm_class = "icon alarm"
548+
549+ # The icon place holders are replaced with a span tag of the icon string, with all of its appropriate classes
550+ # assigned to it.
551+ label_content_values = {
552+ "icon" : f'<span class="{ hour_class } ">{ clock_icon } </span>' ,
553+ "alarm" : f'<span class="{ alarm_class } ">{ alarm_icon } </span>' ,
554+ "timedata" : now ,
555+ }
556+
557+ active_label_content = active_label_content .format_map (label_content_values )
558+
559+ # If any of the icon placeholders are already in a span tag, then flatten the 2 layers of nested span tags, and
560+ # merge their classes into one span tag, before sending them for parsing.
561+ active_label_content = re .sub (
562+ r'<span(?: class=([\'"])(?P<class_name>[\w -]*)\1)?><span class=([\'"])(?P<class_name2>[\w -]*)\3>(?P<label_name>.*?)</span></span>' ,
563+ r'<span class="\g<class_name> \g<class_name2>">\g<label_name></span>' ,
564+ active_label_content ,
565+ )
566+
567+ label_parts = re .split ("(<span.*?>.*?</span>)" , active_label_content )
568+
516569 for part in label_parts :
517570 part = part .strip ()
518571 if part and widget_index < len (active_widgets ) and isinstance (active_widgets [widget_index ], QLabel ):
519572 if "<span" in part and "</span>" in part :
573+ match = re .search (r'<span class=([\'"])(?P<class_name>[\w -]*)\1>[^>]*</span>' , part )
574+ classes = match .group ("class_name" ).strip () or ""
575+
520576 icon_placeholder = re .sub (r"<span.*?>|</span>" , "" , part ).strip ()
521- if icon_placeholder == "{icon}" :
522- if hour_changed :
523- icon = self ._get_icon_for_hour (now .hour )
524- active_widgets [widget_index ].setText (icon )
525- hour_class = f"clock_{ current_hour } "
526- active_widgets [widget_index ].setProperty ("class" , f"icon { hour_class } " )
527- refresh_widget_style (active_widgets [widget_index ])
528- elif icon_placeholder == "{alarm}" :
529- if self ._shared_state ._snoozed_alarms :
530- active_widgets [widget_index ].setText (self .config .alarm_icons .snooze )
531- active_widgets [widget_index ].setProperty ("class" , "icon alarm snooze" )
532- active_widgets [widget_index ].setVisible (True )
533- refresh_widget_style (active_widgets [widget_index ])
534- elif self ._has_enabled_alarms ():
535- active_widgets [widget_index ].setText (self .config .alarm_icons .enabled )
536- active_widgets [widget_index ].setProperty ("class" , "icon alarm" )
537- active_widgets [widget_index ].setVisible (True )
538- refresh_widget_style (active_widgets [widget_index ])
539- else :
540- active_widgets [widget_index ].setText ("" )
541- active_widgets [widget_index ].setVisible (False )
542-
543- else :
544- active_widgets [widget_index ].setText (icon_placeholder )
577+ active_widgets [widget_index ].setText (icon_placeholder )
578+ active_widgets [widget_index ].setProperty ("class" , classes )
579+ refresh_widget_style (active_widgets [widget_index ])
580+
545581 else :
546- has_alarm = "{alarm}" in part and (self ._shared_state ._snoozed_alarms or self ._has_enabled_alarms ())
547-
548- if "{icon}" in part :
549- icon = self ._get_icon_for_hour (now .hour )
550- part = part .replace ("{icon}" , icon )
551-
552- if "{alarm}" in part :
553- if self ._shared_state ._snoozed_alarms :
554- part = part .replace ("{alarm}" , self .config .alarm_icons .snooze )
555- elif self ._has_enabled_alarms ():
556- part = part .replace ("{alarm}" , self .config .alarm_icons .enabled )
557- else :
558- part = part .replace ("{alarm}" , "" )
559- try :
560- datetime_format_search = re .search (r"\{(.*)}" , part )
561- datetime_format_str = datetime_format_search .group ()
562- datetime_format = datetime_format_search .group (1 )
563- format_label_content = part .replace (datetime_format_str , now .strftime (datetime_format ))
564- except Exception :
565- format_label_content = part
566-
567- active_widgets [widget_index ].setText (format_label_content )
568-
569- alarm_state_changed = has_alarm != self ._previous_alarm_state
570- if has_alarm :
571- if self ._shared_state ._snoozed_alarms :
572- active_widgets [widget_index ].setProperty ("class" , "label alarm snooze" )
573- else :
574- active_widgets [widget_index ].setProperty ("class" , "label alarm" )
582+ active_widgets [widget_index ].setText (part )
583+ if hour_changed or alarm_state_changed :
575584 refresh_widget_style (active_widgets [widget_index ])
576- else :
577- hour_class = f"clock_{ current_hour } "
578- active_widgets [widget_index ].setProperty ("class" , f"label { hour_class } " )
579- if hour_changed or alarm_state_changed :
580- refresh_widget_style (active_widgets [widget_index ])
581-
582- self ._previous_alarm_state = has_alarm
583585 widget_index += 1
584586
587+ self ._previous_alarm_state = has_alarm
585588 self ._restore_locale_context (org_locale_time , org_locale_ctype )
586589
587590 def _update_tooltip (self ):
0 commit comments