fix(battery): wrap charge-limit SVG in Box for CSS styling

DrawingArea ignores CSS background/color. Box wrapper lets
#charge-limit-icon.connected selector render active state.
This commit is contained in:
sankalp committed 2026-07-21 09:17:52 +05:45
1 parent 5cb49522da
commit a2ac3d0f55
1 file changed
+109 -30
+109 -30
View File
@@ -8,9 +8,12 @@ from fabric.widgets.separator import Separator
from services.battery import Battery
from services.gamemode import GameModeService
from shared.capture import CaptureNotifier
from utils.functions import clear_children, format_duration
from utils.gtk_utils import svg_file
_charge_notifier = CaptureNotifier(app_name="Modus")
class EnergyModeButton(Box):
def __init__(
@@ -84,6 +87,62 @@ class EnergyModeButton(Box):
self.mode_icon.remove_style_class("connected")
class ChargeLimitButton(Box):
def __init__(self, battery_service: Battery, parent, **kwargs):
super().__init__(name="energy-mode-button", h_expand=True, **kwargs)
self.battery_service = battery_service
self.parent = parent
self.charge_icon_svg = svg_file("zap.svg", size=16)
self.charge_icon = Box(
children=[self.charge_icon_svg],
name="charge-limit-icon",
)
self.charge_label = Label(
label="Charge Limit",
style_classes="charge-limit-button",
h_align="start",
h_expand=True,
)
start_box = Box(
orientation="horizontal",
spacing=3,
children=[self.charge_icon, self.charge_label],
)
self.button = Button(
child=start_box,
name="charge-limit-button-clickable",
on_clicked=self.on_clicked,
h_expand=True,
)
self.children = [self.button]
self.update_state()
def on_clicked(self, *args):
self.battery_service.toggle_charge_limit()
self.update_state()
cl = self.battery_service.charge_limit
if cl is not None:
state = "enabled" if cl.enabled else "disabled"
_charge_notifier.notify(
"Charge Limit",
f"Battery charge limit {state}",
icon="battery-full-charging-symbolic",
)
def update_state(self, *_):
cl = self.battery_service.charge_limit
if cl is not None and cl.enabled:
self.charge_icon.add_style_class("connected")
else:
self.charge_icon.remove_style_class("connected")
class GameModeButton(Box):
def __init__(self, parent, **kwargs):
super().__init__(name="energy-mode-button", h_expand=True, **kwargs)
@@ -192,6 +251,18 @@ class BatteryControl(Box):
orientation="vertical", spacing=4, name="energy-modes-container"
)
self.charge_limit_section = Box(
orientation="vertical", spacing=8, name="charge-limit-section"
)
self.charge_limit_title = Label(
label="Charge Limit", style_classes="battery-section-title", h_align="start"
)
self.charge_limit_container = Box(
orientation="vertical", spacing=4, name="charge-limit-container"
)
self.game_mode_section = Box(
orientation="vertical", spacing=8, name="game-mode-section"
)
@@ -228,32 +299,38 @@ class BatteryControl(Box):
separator2 = Separator(orientation="h", name="separator")
self.battery_widget.add(separator2)
self.charge_limit_section.add(self.charge_limit_title)
self.charge_limit_section.add(self.charge_limit_container)
self.battery_widget.add(self.charge_limit_section)
separator3 = Separator(orientation="h", name="separator")
self.battery_widget.add(separator3)
self.game_mode_section.add(self.game_mode_title)
self.game_mode_section.add(self.game_mode_container)
self.battery_widget.add(self.game_mode_section)
separator3 = Separator(orientation="h", name="separator")
self.battery_widget.add(separator3)
separator4 = Separator(orientation="h", name="separator")
self.battery_widget.add(separator4)
self.battery_widget.add(self.battery_settings_button)
self.add(self.battery_widget)
self.battery_service.connect("changed", self.on_battery_changed)
if hasattr(self.battery_service, "connect"):
try:
self.battery_service.connect(
"power_profile_changed", self.on_profile_changed
)
except TypeError as e:
logger.warning(
f"[battery_widget] self.battery_service.connect( 'power_profile_changed', se... failed: {e}"
)
# signal does not exist
try:
self.battery_service.connect(
"power_profile_changed", self.on_profile_changed
)
except TypeError as e:
logger.warning(
f"[battery_widget] connect power_profile_changed failed: {e}"
)
# Initialize display
self.update_battery_info()
self.create_energy_mode_buttons()
self.create_charge_limit_button()
self.create_game_mode_button()
def open_battery_settings(self, *args):
@@ -261,12 +338,10 @@ class BatteryControl(Box):
pass
def create_energy_mode_buttons(self):
# Clear existing buttons
for button in self.energy_mode_buttons:
button.destroy()
self.energy_mode_buttons.clear()
# Get available profiles
available_profiles = []
if hasattr(self.battery_service, "get_available_power_profiles"):
available_profiles = (
@@ -282,7 +357,6 @@ class BatteryControl(Box):
self.energy_modes_container.add(no_profiles_label)
return
# Define energy mode mappings with proper icon names
energy_mode_config = {
"balanced": {"display": "Automatic", "icon": "balanced"},
"power-saver": {"display": "Low Power", "icon": "power"},
@@ -290,21 +364,17 @@ class BatteryControl(Box):
"performance": {"display": "High Power", "icon": "performance"},
}
# Define the desired order for energy modes
desired_order = ["balanced", "power-saver", "powersave", "performance"]
# Create ordered list of available profiles
ordered_profiles = []
for profile_name in desired_order:
if profile_name in available_profiles:
ordered_profiles.append(profile_name)
# Add any remaining profiles not in the desired order
for profile in available_profiles:
if profile not in ordered_profiles:
ordered_profiles.append(profile)
# Create button for each available profile in the specified order
for profile in ordered_profiles:
config = energy_mode_config.get(
profile, {"display": profile.title(), "icon": "good"}
@@ -324,11 +394,21 @@ class BatteryControl(Box):
for button in self.energy_mode_buttons:
button.update_state()
def create_game_mode_button(self):
# Clear existing game mode button if any
clear_children(self.game_mode_container)
def create_charge_limit_button(self):
if self.battery_service.charge_limit is None:
self.charge_limit_section.hide()
return
self.charge_limit_section.show()
if not hasattr(self, "charge_limit_button"):
self.charge_limit_button = ChargeLimitButton(
battery_service=self.battery_service,
parent=self,
)
self.charge_limit_container.add(self.charge_limit_button)
self.charge_limit_button.update_state()
# Create game mode button
def create_game_mode_button(self):
clear_children(self.game_mode_container)
self.game_mode_button = GameModeButton(parent=self)
self.game_mode_container.add(self.game_mode_button)
@@ -340,11 +420,9 @@ class BatteryControl(Box):
self.charging_time_label.set_label("")
return
# Update percentage in header
percentage = int(self.battery_service.percent)
self.battery_percentage_label.set_label(f"{percentage}%")
# Update power source and charging info
if self.battery_service.charging:
state = "CHARGING"
elif self.battery_service.discharging:
@@ -371,9 +449,7 @@ class BatteryControl(Box):
self.power_source_label.set_label("Power Source: Battery")
seconds_to_empty = self.battery_service.time_remaining
time_to_empty = format_duration(seconds_to_empty)
if time_to_empty != "N/A" and not time_to_empty.startswith(
"4553h"
): # Filter out unrealistic times
if time_to_empty != "N/A" and not time_to_empty.startswith("4553h"):
self.charging_time_label.set_label(f"{time_to_empty} remaining")
else:
self.charging_time_label.set_label("On Battery Power")
@@ -384,6 +460,9 @@ class BatteryControl(Box):
self.power_source_label.set_label("Power Source: Unknown")
self.charging_time_label.set_label("")
if hasattr(self, "charge_limit_button"):
self.charge_limit_button.update_state()
def on_battery_changed(self, *args):
self.update_battery_info()
@@ -395,12 +474,12 @@ class BatteryControl(Box):
self.battery_service.disconnect_by_func(self.on_battery_changed)
except Exception as e:
logger.warning(
f"[battery_widget] self.battery_service.disconnect_by_func(self.on_battery_c... failed: {e}"
f"[battery_widget] disconnect on_battery_changed failed: {e}"
)
try:
self.battery_service.disconnect_by_func(self.on_profile_changed)
except Exception as e:
logger.warning(
f"[battery_widget] self.battery_service.disconnect_by_func(self.on_profile_c... failed: {e}"
f"[battery_widget] disconnect on_profile_changed failed: {e}"
)
super().destroy()