Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
33 changes: 14 additions & 19 deletions src/core/widgets/glazewm/binding_mode.py
Original file line number Diff line number Diff line change
Expand Up @@ -73,34 +73,29 @@ def _reload_css(self, label: QLabel):
def _update_label(self):
active_widgets = self._widgets_alt if self._show_alt_label else self._widgets
active_label_content = self._label_alt_content if self._show_alt_label else self._label_content

active_label_content = active_label_content.format(
binding_mode=(
self._active_binding_mode.display_name or self._active_binding_mode.name or self._label_if_no_active
),
icon=self._icons.get(self._active_binding_mode.name or "none", self._default_icon),
)

label_parts = re.split("(<span.*?>.*?</span>)", active_label_content)
label_parts = [part for part in label_parts if part]
widget_index = 0

label_options = {
"{binding_mode}": self._active_binding_mode.display_name
or self._active_binding_mode.name
or self._label_if_no_active,
"{icon}": self._icons.get(self._active_binding_mode.name or "none", self._default_icon),
}
for part in label_parts:
part = part.strip()
if part and widget_index < len(active_widgets) and isinstance(active_widgets[widget_index], QLabel):
formatted_text = part
for option, value in label_options.items():
formatted_text = formatted_text.replace(option, str(value))
if "<span" in part and "</span>" in part:
icon = re.sub(r"<span.*?>|</span>", "", part).strip()
if icon in label_options:
active_widgets[widget_index].setProperty(
"class", f"icon {self._active_binding_mode.name or 'none'}"
)
active_widgets[widget_index].setText(formatted_text)
else:
active_widgets[widget_index].setText(icon)
part = re.sub(r"<span.*?>|</span>", "", part).strip()
active_widgets[widget_index].setProperty(
"class", f"icon {self._active_binding_mode.name or 'none'}"
)
active_widgets[widget_index].setText(part)
else:
if widget_index < len(active_widgets) and isinstance(active_widgets[widget_index], QLabel):
active_widgets[widget_index].setText(formatted_text)
active_widgets[widget_index].setText(part)
if active_widgets[widget_index].property("class") == "label-offline":
active_widgets[widget_index].setProperty("class", "label")
if not self._active_binding_mode.name:
Expand Down
43 changes: 23 additions & 20 deletions src/core/widgets/yasb/battery.py
Original file line number Diff line number Diff line change
Expand Up @@ -134,6 +134,8 @@ def _update_label(self):
self.timer.stop()
return

label_parts = re.split("(<span.*?>.*?</span>)", active_label_content)

for part in label_parts:
part = part.strip()
if widget_index < len(active_widgets):
Expand Down Expand Up @@ -161,28 +163,30 @@ def _update_label(self):
health_str = f"{state.health_percent:.1f}" if state.health_percent is not None else "N/A"
chemistry_str = state.chemistry if state.chemistry else "N/A"

active_label_content = active_label_content.format(
percent=str(self._battery_state.percent),
time_remaining=time_remaining,
is_charging=is_charging_str,
icon=charging_icon,
power=rate_str,
voltage=voltage_str,
capacity=capacity_str,
full_capacity=full_capacity_str,
designed_capacity=designed_capacity_str,
temperature=temperature_str,
cycle_count=cycle_count_str,
health=health_str,
chemistry=chemistry_str,
)
label_parts = re.split("(<span.*?>.*?</span>)", active_label_content)

for part in label_parts:
part = part.strip()
if part and widget_index < len(active_widgets):
battery_status = (
part.replace("{percent}", str(self._battery_state.percent))
.replace("{time_remaining}", time_remaining)
.replace("{is_charging}", is_charging_str)
.replace("{icon}", charging_icon)
.replace("{power}", rate_str)
.replace("{voltage}", voltage_str)
.replace("{capacity}", capacity_str)
.replace("{full_capacity}", full_capacity_str)
.replace("{designed_capacity}", designed_capacity_str)
.replace("{temperature}", temperature_str)
.replace("{cycle_count}", cycle_count_str)
.replace("{health}", health_str)
.replace("{chemistry}", chemistry_str)
)
if "<span" in battery_status and "</span>" in battery_status:
if part and widget_index < len(active_widgets) and isinstance(active_widgets[widget_index], QLabel):
if "<span" in part and "</span>" in part:
# icon-only QLabel
widget_label = active_widgets[widget_index]
icon = re.sub(r"<span.*?>|</span>", "", battery_status).strip()
icon = re.sub(r"<span.*?>|</span>", "", part).strip()
widget_label.setText(icon)
# apply status‐class
existing_classes = widget_label.property("class")
Expand All @@ -207,8 +211,7 @@ def _update_label(self):
refresh_widget_style(widget_label)
else:
alt_class = "alt" if self._show_alt_label else ""
formatted_text = battery_status.format(battery_status)
active_widgets[widget_index].setText(formatted_text)
active_widgets[widget_index].setText(part)
active_widgets[widget_index].setProperty("class", f"label {alt_class} status-{threshold}")
refresh_widget_style(active_widgets[widget_index])
widget_index += 1
25 changes: 11 additions & 14 deletions src/core/widgets/yasb/bluetooth.py
Original file line number Diff line number Diff line change
Expand Up @@ -268,8 +268,6 @@ def _toggle_label(self):
def _update_label(self, icon, connected_devices=None):
active_widgets = self._widgets_alt if self._show_alt_label else self._widgets
active_label_content = self.config.label_alt if self._show_alt_label else self.config.label
label_parts = re.split("(<span.*?>.*?</span>)", active_label_content)
label_parts = [part for part in label_parts if part]
widget_index = 0

if connected_devices:
Expand All @@ -291,26 +289,25 @@ def _update_label(self, icon, connected_devices=None):
device_names = self.config.label_no_device
tooltip_text = self.config.label_no_device

label_options = {
"{icon}": icon,
"{device_name}": device_names,
"{device_count}": len(connected_devices) if connected_devices else 0,
}
active_label_content = active_label_content.format(
icon=icon,
device_name=device_names,
device_count=len(connected_devices) if connected_devices else 0,
)

label_parts = re.split("(<span.*?>.*?</span>)", active_label_content)

for part in label_parts:
part = part.strip()
if part:
formatted_text = part
for option, value in label_options.items():
formatted_text = formatted_text.replace(option, str(value))
if "<span" in part and "</span>" in part:
if widget_index < len(active_widgets) and isinstance(active_widgets[widget_index], QLabel):
active_widgets[widget_index].setText(formatted_text)
active_widgets[widget_index].setText(part)
else:
if self.config.max_length and len(formatted_text) > self.config.max_length:
formatted_text = formatted_text[: self.config.max_length] + self.config.max_length_ellipsis
if self.config.max_length and len(part) > self.config.max_length:
part = part[: self.config.max_length] + self.config.max_length_ellipsis
if widget_index < len(active_widgets) and isinstance(active_widgets[widget_index], QLabel):
active_widgets[widget_index].setText(formatted_text)
active_widgets[widget_index].setText(part)
widget_index += 1

if self.config.tooltip:
Expand Down
12 changes: 4 additions & 8 deletions src/core/widgets/yasb/brightness.py
Original file line number Diff line number Diff line change
Expand Up @@ -148,9 +148,6 @@ def _update_label(self):
"""Update the widget label with current brightness."""
active_widgets = self._widgets_alt if self._show_alt_label else self._widgets
active_label_content = self.config.label_alt if self._show_alt_label else self.config.label
label_parts = re.split("(<span.*?>.*?</span>)", active_label_content)
label_parts = [part for part in label_parts if part]
widget_index = 0

percent = self.current_brightness
if percent is None:
Expand All @@ -165,7 +162,9 @@ def _update_label(self):
if self.config.tooltip:
set_tooltip(self, f"Brightness {percent}%")

label_options = {"{icon}": icon, "{percent}": percent}
active_label_content = active_label_content.format(icon=icon, percent=percent)
label_parts = re.split("(<span.*?>.*?</span>)", active_label_content)
widget_index = 0

# Update progress bar
if self.config.progress_bar.enabled and self.progress_widget:
Expand All @@ -178,10 +177,7 @@ def _update_label(self):
for part in label_parts:
part = part.strip()
if part and widget_index < len(active_widgets):
formatted_text = part
for option, value in label_options.items():
formatted_text = formatted_text.replace(option, str(value))
active_widgets[widget_index].setText(formatted_text)
active_widgets[widget_index].setText(part)
widget_index += 1

def _get_brightness_icon(self, brightness: int) -> str:
Expand Down
152 changes: 87 additions & 65 deletions src/core/widgets/yasb/clock.py
Original file line number Diff line number Diff line change
Expand Up @@ -485,10 +485,27 @@ def _update_label(self):
# Choose which label set to update (primary or alternate)
active_widgets = self._widgets_alt if self._show_alt_label else self._widgets
active_label_content = self._label_alt_content if self._show_alt_label else self._label_content
label_parts = re.split("(<span.*?>.*?</span>)", active_label_content)
label_parts = [part for part in label_parts if part]
widget_index = 0
now = datetime.now(ZoneInfo(self._active_tz)) if self._active_tz else datetime.now().astimezone()

# Finding the datetime format string in the label using keyerror exception.
# This code assumes that there's only 1 time format placeholder in the label.
try:
active_label_content.format(icon="", alarm="", timedata=now)
except KeyError as ke:
# Remove the quotes around the exception message to get the datetime format.
datetime_format = str(ke)[1:-1]

datetime_format_idx = active_label_content.find(datetime_format)
closing_braces_idx = active_label_content.find("}", datetime_format_idx + len(datetime_format))
datetime_format = active_label_content[datetime_format_idx:closing_braces_idx]

active_label_content = (
active_label_content[: datetime_format_idx - 1]
+ now.strftime(datetime_format)
+ active_label_content[closing_braces_idx + 1 :]
)

current_hour = f"{now.hour:02d}"
current_minute = f"{now.minute:02d}"
hour_changed = self._current_hour != current_hour
Expand All @@ -498,6 +515,9 @@ def _update_label(self):
if minute_changed:
self._current_minute = current_minute

has_alarm = self._shared_state._snoozed_alarms or self._has_enabled_alarms()
alarm_state_changed = has_alarm != self._previous_alarm_state

# Temporarily switch locale so strftime outputs are localized
org_locale_time, org_locale_ctype = self._set_locale_context()

Expand All @@ -513,75 +533,77 @@ def _update_label(self):
self._timer_label.hide()
self._timer_visible = False

clock_icon = self._get_icon_for_hour(now.hour)
hour_class = f"clock_{current_hour}"
alarm_icon = alarm_class = ""

if self._shared_state._snoozed_alarms:
alarm_class = "icon alarm snooze"
alarm_icon = self.config.alarm_icons.snooze

elif self._has_enabled_alarms():
alarm_icon = self.config.alarm_icons.enabled
alarm_class = "icon alarm"

# The icon place holders are replaced with a span tag of the icon string, with all of its appropriate classes
# assigned to it.
label_content_values = {
"icon": f'<span class="{hour_class}">{clock_icon}</span>',
"alarm": f'<span class="{alarm_class}">{alarm_icon}</span>',
"timedata": now,
}

active_label_content = active_label_content.format_map(label_content_values)

# If any of the icon placeholders are already in a span tag, then flatten the 2 layers of nested span tags, and
# merge their classes into one span tag, before sending them for parsing.
active_label_content = re.sub(
r'<span(?: class=([\'"])(?P<class_name>[\w -]*)\1)?><span class=([\'"])(?P<class_name2>[\w -]*)\3>(?P<label_name>.*?)</span></span>',
r'<span class="\g<class_name> \g<class_name2>">\g<label_name></span>',
active_label_content,
)

label_parts = re.split("(<span.*?>.*?</span>)", active_label_content)

for part in label_parts:
part = part.strip()
if part and widget_index < len(active_widgets) and isinstance(active_widgets[widget_index], QLabel):
if not part:
continue

if widget_index < len(active_widgets):
active_widget = active_widgets[widget_index]
else:
active_widget = label = QLabel(part)
label.setProperty("class", "label alt" if self._show_alt_label else "label")
label.setAlignment(Qt.AlignmentFlag.AlignCenter)
label.setCursor(Qt.CursorShape.PointingHandCursor)
content_shadow = self.config.label_shadow.model_dump()
if content_shadow:
add_shadow(label, content_shadow)
self._widget_container_layout.addWidget(label)
active_widgets.append(label)

if isinstance(active_widget, QLabel):
if "<span" in part and "</span>" in part:
match = re.search(r'<span class=([\'"])(?P<class_name>[\w -]*)\1>[^>]*</span>', part)
classes = match.group("class_name").strip() or ""

icon_placeholder = re.sub(r"<span.*?>|</span>", "", part).strip()
if icon_placeholder == "{icon}":
if hour_changed:
icon = self._get_icon_for_hour(now.hour)
active_widgets[widget_index].setText(icon)
hour_class = f"clock_{current_hour}"
active_widgets[widget_index].setProperty("class", f"icon {hour_class}")
refresh_widget_style(active_widgets[widget_index])
elif icon_placeholder == "{alarm}":
if self._shared_state._snoozed_alarms:
active_widgets[widget_index].setText(self.config.alarm_icons.snooze)
active_widgets[widget_index].setProperty("class", "icon alarm snooze")
active_widgets[widget_index].setVisible(True)
refresh_widget_style(active_widgets[widget_index])
elif self._has_enabled_alarms():
active_widgets[widget_index].setText(self.config.alarm_icons.enabled)
active_widgets[widget_index].setProperty("class", "icon alarm")
active_widgets[widget_index].setVisible(True)
refresh_widget_style(active_widgets[widget_index])
else:
active_widgets[widget_index].setText("")
active_widgets[widget_index].setVisible(False)

else:
active_widgets[widget_index].setText(icon_placeholder)
active_widget.setText(icon_placeholder)
active_widget.setProperty("class", classes)
refresh_widget_style(active_widget)

else:
has_alarm = "{alarm}" in part and (self._shared_state._snoozed_alarms or self._has_enabled_alarms())

if "{icon}" in part:
icon = self._get_icon_for_hour(now.hour)
part = part.replace("{icon}", icon)

if "{alarm}" in part:
if self._shared_state._snoozed_alarms:
part = part.replace("{alarm}", self.config.alarm_icons.snooze)
elif self._has_enabled_alarms():
part = part.replace("{alarm}", self.config.alarm_icons.enabled)
else:
part = part.replace("{alarm}", "")
try:
datetime_format_search = re.search(r"\{(.*)}", part)
datetime_format_str = datetime_format_search.group()
datetime_format = datetime_format_search.group(1)
format_label_content = part.replace(datetime_format_str, now.strftime(datetime_format))
except Exception:
format_label_content = part

active_widgets[widget_index].setText(format_label_content)

alarm_state_changed = has_alarm != self._previous_alarm_state
if has_alarm:
if self._shared_state._snoozed_alarms:
active_widgets[widget_index].setProperty("class", "label alarm snooze")
else:
active_widgets[widget_index].setProperty("class", "label alarm")
refresh_widget_style(active_widgets[widget_index])
else:
hour_class = f"clock_{current_hour}"
active_widgets[widget_index].setProperty("class", f"label {hour_class}")
if hour_changed or alarm_state_changed:
refresh_widget_style(active_widgets[widget_index])

self._previous_alarm_state = has_alarm
active_widget.setText(part)
if hour_changed or alarm_state_changed:
refresh_widget_style(active_widget)
active_widget.setVisible(True)
widget_index += 1

while widget_index < len(active_widgets):
active_widgets[widget_index].setVisible(False)
widget_index += 1

self._previous_alarm_state = has_alarm
self._restore_locale_context(org_locale_time, org_locale_ctype)

def _update_tooltip(self):
Expand Down
Loading