fix: add logger import and safe widget access for HUD rebuild

- Add logging import and logger instance
- Add _safe_set_text() helper to handle deleted widgets gracefully
- Use safe access in _refresh_display to prevent RuntimeError on rebuild
- Wrap stylesheet updates in try/except for safety
This commit is contained in:
LemonNexus 2026-02-09 22:55:22 +00:00
parent 7a55e3b246
commit 64a68f3857
1 changed files with 50 additions and 47 deletions

View File

@ -5,12 +5,15 @@ Cleaner, customizable HUD with collapsible sections.
import sys
import json
import logging
from pathlib import Path
from decimal import Decimal
from datetime import datetime, timedelta
from dataclasses import dataclass, asdict, field
from typing import Optional, Dict, Any, List, Set
logger = logging.getLogger(__name__)
# Windows-specific imports for click-through support
if sys.platform == 'win32':
import ctypes
@ -659,72 +662,72 @@ class HUDOverlay(QWidget):
if hasattr(self, 'time_label'):
self.time_label.setText(f"{hours:02d}:{minutes:02d}:{seconds:02d}")
def _safe_set_text(self, widget_name: str, text: str):
"""Safely set text on a widget if it exists and is valid."""
try:
widget = getattr(self, widget_name, None)
if widget is not None:
widget.setText(text)
except RuntimeError:
# Widget was deleted
pass
def _refresh_display(self):
"""Refresh all display labels."""
# Profit/Loss
if hasattr(self, 'profit_label'):
profit = self._stats.profit_loss
color = "#7FFF7F" if profit >= 0 else "#FF7F7F"
self.profit_label.setText(f"{profit:+.2f} PED")
self.profit_label.setStyleSheet(f"font-size: 18px; font-weight: bold; color: {color};")
profit = self._stats.profit_loss
color = "#7FFF7F" if profit >= 0 else "#FF7F7F"
self._safe_set_text('profit_label', f"{profit:+.2f} PED")
if hasattr(self, 'profit_label') and self.profit_label is not None:
try:
self.profit_label.setStyleSheet(f"font-size: 18px; font-weight: bold; color: {color};")
except RuntimeError:
pass
# Return %
if hasattr(self, 'return_label'):
ret = self._stats.return_percentage
if ret >= 100:
color = "#7FFF7F"
elif ret >= 90:
color = "#FFFF7F"
else:
color = "#FF7F7F"
self.return_label.setText(f"{ret:.1f}%")
self.return_label.setStyleSheet(f"font-size: 16px; font-weight: bold; color: {color};")
ret = self._stats.return_percentage
if ret >= 100:
color = "#7FFF7F"
elif ret >= 90:
color = "#FFFF7F"
else:
color = "#FF7F7F"
self._safe_set_text('return_label', f"{ret:.1f}%")
if hasattr(self, 'return_label') and self.return_label is not None:
try:
self.return_label.setStyleSheet(f"font-size: 16px; font-weight: bold; color: {color};")
except RuntimeError:
pass
# Total Cost + Loot
if hasattr(self, 'total_cost_label'):
self.total_cost_label.setText(f"Cost: {self._stats.cost_total:.2f}")
if hasattr(self, 'total_loot_label'):
self.total_loot_label.setText(f"Loot: {self._stats.loot_total:.2f}")
self._safe_set_text('total_cost_label', f"Cost: {self._stats.cost_total:.2f}")
self._safe_set_text('total_loot_label', f"Loot: {self._stats.loot_total:.2f}")
# Cost metrics
if hasattr(self, 'cps_label'):
self.cps_label.setText(f"Shot: {self._stats.cost_per_shot:.4f}")
if hasattr(self, 'cph_label'):
self.cph_label.setText(f"Hit: {self._stats.cost_per_hit:.4f}")
if hasattr(self, 'cphl_label'):
self.cphl_label.setText(f"Heal: {self._stats.cost_per_heal:.4f}")
self._safe_set_text('cps_label', f"Shot: {self._stats.cost_per_shot:.4f}")
self._safe_set_text('cph_label', f"Hit: {self._stats.cost_per_hit:.4f}")
self._safe_set_text('cphl_label', f"Heal: {self._stats.cost_per_heal:.4f}")
# Gear
if hasattr(self, 'weapon_label'):
self.weapon_label.setText(f"🔫 {self._stats.current_weapon[:20]}")
if hasattr(self, 'armor_label'):
self.armor_label.setText(f"🛡️ {self._stats.current_armor[:20]}")
if hasattr(self, 'loadout_label'):
self.loadout_label.setText(f"📋 {self._stats.current_loadout[:20]}")
self._safe_set_text('weapon_label', f"🔫 {self._stats.current_weapon[:20]}")
self._safe_set_text('armor_label', f"🛡️ {self._stats.current_armor[:20]}")
self._safe_set_text('loadout_label', f"📋 {self._stats.current_loadout[:20]}")
# Cost breakdown
if hasattr(self, 'wep_cost_label'):
self.wep_cost_label.setText(f"{self._stats.weapon_cost_total:.2f}")
if hasattr(self, 'arm_cost_label'):
self.arm_cost_label.setText(f"{self._stats.armor_cost_total:.2f}")
if hasattr(self, 'heal_cost_label'):
self.heal_cost_label.setText(f"{self._stats.healing_cost_total:.2f}")
self._safe_set_text('wep_cost_label', f"{self._stats.weapon_cost_total:.2f}")
self._safe_set_text('arm_cost_label', f"{self._stats.armor_cost_total:.2f}")
self._safe_set_text('heal_cost_label', f"{self._stats.healing_cost_total:.2f}")
# Combat
if hasattr(self, 'kills_label'):
self.kills_label.setText(f"Kills: {self._stats.kills}")
if hasattr(self, 'globals_label'):
self.globals_label.setText(f"Globals: {self._stats.globals_count}")
self._safe_set_text('kills_label', f"Kills: {self._stats.kills}")
self._safe_set_text('globals_label', f"Globals: {self._stats.globals_count}")
# Damage stats
if hasattr(self, 'damage_dealt_label'):
self.damage_dealt_label.setText(f"Dealt: {int(self._stats.damage_dealt)}")
if hasattr(self, 'damage_taken_label'):
self.damage_taken_label.setText(f"Taken: {int(self._stats.damage_taken)}")
self._safe_set_text('damage_dealt_label', f"Dealt: {int(self._stats.damage_dealt)}")
self._safe_set_text('damage_taken_label', f"Taken: {int(self._stats.damage_taken)}")
# Shrapnel
if hasattr(self, 'shrapnel_label'):
self.shrapnel_label.setText(f"💎 Shrapnel: {self._stats.shrapnel_total:.2f} PED")
self._safe_set_text('shrapnel_label', f"💎 Shrapnel: {self._stats.shrapnel_total:.2f} PED")
# === Public Update Methods ===