@@ -485,10 +485,27 @@ 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
491489 now = datetime .now (ZoneInfo (self ._active_tz )) if self ._active_tz else datetime .now ().astimezone ()
490+
491+ # Finding the datetime format string in the label using keyerror exception.
492+ # This code assumes that there's only 1 time format placeholder in the label.
493+ try :
494+ active_label_content .format (icon = "" , alarm = "" , timedata = now )
495+ except KeyError as ke :
496+ # Remove the quotes around the exception message to get the datetime format.
497+ datetime_format = str (ke )[1 :- 1 ]
498+
499+ datetime_format_idx = active_label_content .find (datetime_format )
500+ closing_braces_idx = active_label_content .find ("}" , datetime_format_idx + len (datetime_format ))
501+ datetime_format = active_label_content [datetime_format_idx :closing_braces_idx ]
502+
503+ active_label_content = (
504+ active_label_content [: datetime_format_idx - 1 ]
505+ + now .strftime (datetime_format )
506+ + active_label_content [closing_braces_idx + 1 :]
507+ )
508+
492509 current_hour = f"{ now .hour :02d} "
493510 current_minute = f"{ now .minute :02d} "
494511 hour_changed = self ._current_hour != current_hour
@@ -498,6 +515,9 @@ def _update_label(self):
498515 if minute_changed :
499516 self ._current_minute = current_minute
500517
518+ has_alarm = self ._shared_state ._snoozed_alarms or self ._has_enabled_alarms ()
519+ alarm_state_changed = has_alarm != self ._previous_alarm_state
520+
501521 # Temporarily switch locale so strftime outputs are localized
502522 org_locale_time , org_locale_ctype = self ._set_locale_context ()
503523
@@ -513,75 +533,77 @@ def _update_label(self):
513533 self ._timer_label .hide ()
514534 self ._timer_visible = False
515535
536+ clock_icon = self ._get_icon_for_hour (now .hour )
537+ hour_class = f"clock_{ current_hour } "
538+ alarm_icon = alarm_class = ""
539+
540+ if self ._shared_state ._snoozed_alarms :
541+ alarm_class = "icon alarm snooze"
542+ alarm_icon = self .config .alarm_icons .snooze
543+
544+ elif self ._has_enabled_alarms ():
545+ alarm_icon = self .config .alarm_icons .enabled
546+ alarm_class = "icon alarm"
547+
548+ # The icon place holders are replaced with a span tag of the icon string, with all of its appropriate classes
549+ # assigned to it.
550+ label_content_values = {
551+ "icon" : f'<span class="{ hour_class } ">{ clock_icon } </span>' ,
552+ "alarm" : f'<span class="{ alarm_class } ">{ alarm_icon } </span>' ,
553+ "timedata" : now ,
554+ }
555+
556+ active_label_content = active_label_content .format_map (label_content_values )
557+
558+ # If any of the icon placeholders are already in a span tag, then flatten the 2 layers of nested span tags, and
559+ # merge their classes into one span tag, before sending them for parsing.
560+ active_label_content = re .sub (
561+ r'<span(?: class=([\'"])(?P<class_name>[\w -]*)\1)?><span class=([\'"])(?P<class_name2>[\w -]*)\3>(?P<label_name>.*?)</span></span>' ,
562+ r'<span class="\g<class_name> \g<class_name2>">\g<label_name></span>' ,
563+ active_label_content ,
564+ )
565+
566+ label_parts = re .split ("(<span.*?>.*?</span>)" , active_label_content )
567+
516568 for part in label_parts :
517- part = part .strip ()
518- if part and widget_index < len (active_widgets ) and isinstance (active_widgets [widget_index ], QLabel ):
569+ if not part :
570+ continue
571+
572+ if widget_index < len (active_widgets ):
573+ active_widget = active_widgets [widget_index ]
574+ else :
575+ active_widget = label = QLabel (part )
576+ label .setProperty ("class" , "label alt" if self ._show_alt_label else "label" )
577+ label .setAlignment (Qt .AlignmentFlag .AlignCenter )
578+ label .setCursor (Qt .CursorShape .PointingHandCursor )
579+ content_shadow = self .config .label_shadow .model_dump ()
580+ if content_shadow :
581+ add_shadow (label , content_shadow )
582+ self ._widget_container_layout .addWidget (label )
583+ active_widgets .append (label )
584+
585+ if isinstance (active_widget , QLabel ):
519586 if "<span" in part and "</span>" in part :
587+ match = re .search (r'<span class=([\'"])(?P<class_name>[\w -]*)\1>[^>]*</span>' , part )
588+ classes = match .group ("class_name" ).strip () or ""
589+
520590 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 )
591+ active_widget .setText (icon_placeholder )
592+ active_widget .setProperty ("class" , classes )
593+ refresh_widget_style (active_widget )
594+
545595 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" )
575- 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
596+ active_widget .setText (part )
597+ if hour_changed or alarm_state_changed :
598+ refresh_widget_style (active_widget )
599+ active_widget .setVisible (True )
583600 widget_index += 1
584601
602+ while widget_index < len (active_widgets ):
603+ active_widgets [widget_index ].setVisible (False )
604+ widget_index += 1
605+
606+ self ._previous_alarm_state = has_alarm
585607 self ._restore_locale_context (org_locale_time , org_locale_ctype )
586608
587609 def _update_tooltip (self ):
0 commit comments