Files
ExerciseDiary/utils.py
2026-01-10 16:46:49 +01:00

72 lines
2.4 KiB
Python

import os
import subprocess
from PIL import Image
import customtkinter as ctk
def parse_float(val_str: str) -> float:
"""Safely parse a string to float, handling both '.' and ',' as decimal separators."""
if not val_str:
return None
clean_val = val_str.replace(',', '.')
try:
return float(clean_val)
except ValueError:
return None
def format_float(val: float, precision: int = 1) -> str:
"""Format a float for display."""
if val is None:
return ""
return f"{val:.{precision}f}"
def get_bmi_status(bmi):
if bmi < 16: return "Severely Underweight", "bmi_severely_underweight.svg", "#3498db"
if bmi < 18.5: return "Underweight", "bmi_underweight.svg", "#3498db"
if bmi < 25: return "Normal", "bmi_normal.svg", "#2ecc71"
if bmi < 30: return "Overweight", "bmi_overweight.svg", "#f1c40f"
return "Obese", "bmi_severely_obese.svg", "#e74c3c"
def get_bmi_icon(bmi: float, size: tuple = (100, 100)) -> ctk.CTkImage:
"""
Returns a CTkImage for the given BMI.
Converts SVG to PNG using rsvg-convert if needed.
"""
if bmi is None: return None
_, filename, _ = get_bmi_status(bmi)
base_dir = os.path.dirname(os.path.abspath(__file__))
assets_dir = os.path.join(base_dir, "assets", "bmi_icons")
cache_dir = os.path.join(assets_dir, "png_cache")
svg_path = os.path.join(assets_dir, filename)
png_filename = filename.replace(".svg", f"_{size[0]}x{size[1]}.png")
png_path = os.path.join(cache_dir, png_filename)
if not os.path.exists(svg_path):
print(f"Warning: Icon not found at {svg_path}")
return None
if not os.path.exists(cache_dir):
os.makedirs(cache_dir)
# Convert if PNG doesn't exist
if not os.path.exists(png_path):
try:
subprocess.run([
"rsvg-convert",
"-w", str(size[0]),
"-h", str(size[1]),
"-o", png_path,
svg_path
], check=True)
except (subprocess.CalledProcessError, FileNotFoundError) as e:
print(f"Error converting SVG: {e}")
return None
try:
img = Image.open(png_path)
return ctk.CTkImage(light_image=img, dark_image=img, size=size)
except Exception as e:
print(f"Error loading image: {e}")
return None