add docstrings in animated_icon and cfd_app_config.py

This commit is contained in:
2025-08-10 10:38:45 +02:00
parent b18bf7fe85
commit 246addc34b
4 changed files with 76 additions and 22 deletions

View File

@@ -1,3 +1,10 @@
"""
A Tkinter widget for displaying animated icons.
This module provides the AnimatedIcon class, a custom Tkinter Canvas widget
that can display various types of animations. It supports both native Tkinter
drawing and Pillow (PIL) for anti-aliased graphics if available.
"""
import tkinter as tk
from math import sin, cos, pi
@@ -9,11 +16,27 @@ except ImportError:
PIL_AVAILABLE = False
def _hex_to_rgb(hex_color):
"""Converts a hex color string to an RGB tuple."""
hex_color = hex_color.lstrip('#')
return tuple(int(hex_color[i:i+2], 16) for i in (0, 2, 4))
class AnimatedIcon(tk.Canvas):
"""A custom Tkinter Canvas widget for displaying animations."""
def __init__(self, master, width=20, height=20, animation_type="counter_arc", color="#2a6fde", highlight_color="#5195ff", use_pillow=False, bg=None):
"""
Initializes the AnimatedIcon widget.
Args:
master: The parent widget.
width (int): The width of the icon.
height (int): The height of the icon.
animation_type (str): The type of animation to display.
Options: "counter_arc", "double_arc", "line", "blink".
color (str): The primary color of the icon.
highlight_color (str): The highlight color of the icon.
use_pillow (bool): Whether to use Pillow for drawing if available.
bg (str): The background color of the canvas.
"""
if bg is None:
try:
bg = master.cget("background")
@@ -40,12 +63,14 @@ class AnimatedIcon(tk.Canvas):
self.photo_image = None
def _draw_frame(self):
"""Draws a single frame of the animation."""
if self.use_pillow:
self._draw_pillow_frame()
else:
self._draw_canvas_frame()
def _draw_canvas_frame(self):
"""Draws a frame using native Tkinter canvas methods."""
self.delete("all")
if self.pulse_animation:
self._draw_canvas_pulse()
@@ -59,6 +84,7 @@ class AnimatedIcon(tk.Canvas):
self._draw_canvas_blink()
def _draw_canvas_pulse(self):
"""Draws the pulse animation using canvas methods."""
center_x, center_y = self.width / 2, self.height / 2
alpha = (sin(self.angle * 5) + 1) / 2 # Faster pulse
r = int(alpha * (self.highlight_color_rgb[0] - self.color_rgb[0]) + self.color_rgb[0])
@@ -88,6 +114,7 @@ class AnimatedIcon(tk.Canvas):
def _draw_canvas_line(self):
"""Draws the line animation using canvas methods."""
center_x, center_y = self.width / 2, self.height / 2
for i in range(8):
angle = self.angle + i * (pi / 4)
@@ -105,6 +132,7 @@ class AnimatedIcon(tk.Canvas):
self.create_line(start_x, start_y, end_x, end_y, fill=color, width=2)
def _draw_canvas_double_arc(self):
"""Draws the double arc animation using canvas methods."""
center_x, center_y = self.width / 2, self.height / 2
radius = min(center_x, center_y) * 0.8
bbox = (center_x - radius, center_y - radius, center_x + radius, center_y + radius)
@@ -118,6 +146,7 @@ class AnimatedIcon(tk.Canvas):
self.create_arc(bbox, start=start_angle2, extent=extent2, style=tk.ARC, outline=self.color, width=2)
def _draw_canvas_counter_arc(self):
"""Draws the counter arc animation using canvas methods."""
center_x, center_y = self.width / 2, self.height / 2
radius_outer = min(center_x, center_y) * 0.8
@@ -131,6 +160,7 @@ class AnimatedIcon(tk.Canvas):
self.create_arc(bbox_inner, start=start_angle2, extent=150, style=tk.ARC, outline=self.color, width=2)
def _draw_canvas_blink(self):
"""Draws the blink animation using canvas methods."""
center_x, center_y = self.width / 2, self.height / 2
radius = min(center_x, center_y) * 0.8
alpha = (sin(self.angle * 2) + 1) / 2 # Slower blinking speed
@@ -141,6 +171,7 @@ class AnimatedIcon(tk.Canvas):
self.create_arc(center_x - radius, center_y - radius, center_x + radius, center_y + radius, start=0, extent=359.9, style=tk.ARC, outline=blink_color, width=4)
def _draw_pillow_frame(self):
"""Draws a frame using Pillow for anti-aliased graphics."""
self.draw.rectangle([0, 0, self.width * 4, self.height * 4], fill=(0, 0, 0, 0))
if self.pulse_animation:
self._draw_pillow_pulse()
@@ -159,6 +190,7 @@ class AnimatedIcon(tk.Canvas):
self.create_image(0, 0, anchor="nw", image=self.photo_image)
def _draw_pillow_pulse(self):
"""Draws the pulse animation using Pillow."""
center_x, center_y = self.width * 2, self.height * 2
alpha = (sin(self.angle * 5) + 1) / 2 # Faster pulse
r = int(alpha * (self.highlight_color_rgb[0] - self.color_rgb[0]) + self.color_rgb[0])
@@ -187,6 +219,7 @@ class AnimatedIcon(tk.Canvas):
self.draw.arc(bbox_inner, start=0, end=360, fill=self.color_rgb, width=7)
def _draw_pillow_line(self):
"""Draws the line animation using Pillow."""
center_x, center_y = self.width * 2, self.height * 2
for i in range(12):
angle = self.angle + i * (pi / 6)
@@ -204,6 +237,7 @@ class AnimatedIcon(tk.Canvas):
self.draw.line([(start_x, start_y), (end_x, end_y)], fill=color, width=6, joint="curve")
def _draw_pillow_double_arc(self):
"""Draws the double arc animation using Pillow."""
center_x, center_y = self.width * 2, self.height * 2
radius = min(center_x, center_y) * 0.8
bbox = (center_x - radius, center_y - radius, center_x + radius, center_y + radius)
@@ -217,6 +251,7 @@ class AnimatedIcon(tk.Canvas):
self.draw.arc(bbox, start=start_angle2, end=start_angle2 + extent2, fill=self.color_rgb, width=5)
def _draw_pillow_counter_arc(self):
"""Draws the counter arc animation using Pillow."""
center_x, center_y = self.width * 2, self.height * 2
radius_outer = min(center_x, center_y) * 0.8
@@ -230,6 +265,7 @@ class AnimatedIcon(tk.Canvas):
self.draw.arc(bbox_inner, start=start_angle2, end=start_angle2 + 150, fill=self.color_rgb, width=7)
def _draw_pillow_blink(self):
"""Draws the blink animation using Pillow."""
center_x, center_y = self.width * 2, self.height * 2
radius = min(center_x, center_y) * 0.8
alpha = (sin(self.angle * 2) + 1) / 2 # Slower blinking speed
@@ -240,6 +276,7 @@ class AnimatedIcon(tk.Canvas):
self.draw.arc((center_x - radius, center_y - radius, center_x + radius, center_y + radius), start=0, end=360, fill=blink_color, width=10)
def _draw_stopped_frame(self):
"""Draws the icon in its stopped (static) state."""
self.delete("all")
if self.use_pillow:
self._draw_pillow_stopped_frame()
@@ -247,6 +284,7 @@ class AnimatedIcon(tk.Canvas):
self._draw_canvas_stopped_frame()
def _draw_canvas_stopped_frame(self):
"""Draws the stopped state using canvas methods."""
if self.animation_type == "line":
self._draw_canvas_line_stopped()
elif self.animation_type == "double_arc":
@@ -257,6 +295,7 @@ class AnimatedIcon(tk.Canvas):
self._draw_canvas_blink_stopped()
def _draw_canvas_line_stopped(self):
"""Draws the stopped state for the line animation."""
center_x, center_y = self.width / 2, self.height / 2
for i in range(8):
angle = i * (pi / 4)
@@ -267,12 +306,14 @@ class AnimatedIcon(tk.Canvas):
self.create_line(start_x, start_y, end_x, end_y, fill=self.highlight_color, width=2)
def _draw_canvas_double_arc_stopped(self):
"""Draws the stopped state for the double arc animation."""
center_x, center_y = self.width / 2, self.height / 2
radius = min(center_x, center_y) * 0.8
bbox = (center_x - radius, center_y - radius, center_x + radius, center_y + radius)
self.create_arc(bbox, start=0, extent=359.9, style=tk.ARC, outline=self.highlight_color, width=2)
def _draw_canvas_counter_arc_stopped(self):
"""Draws the stopped state for the counter arc animation."""
center_x, center_y = self.width / 2, self.height / 2
radius_outer = min(center_x, center_y) * 0.8
bbox_outer = (center_x - radius_outer, center_y - radius_outer, center_x + radius_outer, center_y + radius_outer)
@@ -282,11 +323,13 @@ class AnimatedIcon(tk.Canvas):
self.create_arc(bbox_inner, start=0, extent=359.9, style=tk.ARC, outline=self.color, width=2)
def _draw_canvas_blink_stopped(self):
"""Draws the stopped state for the blink animation."""
center_x, center_y = self.width / 2, self.height / 2
radius = min(center_x, center_y) * 0.8
self.create_arc(center_x - radius, center_y - radius, center_x + radius, center_y + radius, start=0, extent=359.9, style=tk.ARC, outline=self.highlight_color, width=4)
def _draw_pillow_stopped_frame(self):
"""Draws the stopped state using Pillow."""
self.draw.rectangle([0, 0, self.width * 4, self.height * 4], fill=(0, 0, 0, 0))
if self.animation_type == "line":
self._draw_pillow_line_stopped()
@@ -302,6 +345,7 @@ class AnimatedIcon(tk.Canvas):
self.create_image(0, 0, anchor="nw", image=self.photo_image)
def _draw_pillow_line_stopped(self):
"""Draws the stopped state for the line animation using Pillow."""
center_x, center_y = self.width * 2, self.height * 2
for i in range(12):
angle = i * (pi / 6)
@@ -312,12 +356,14 @@ class AnimatedIcon(tk.Canvas):
self.draw.line([(start_x, start_y), (end_x, end_y)], fill=self.highlight_color_rgb, width=6, joint="curve")
def _draw_pillow_double_arc_stopped(self):
"""Draws the stopped state for the double arc animation using Pillow."""
center_x, center_y = self.width * 2, self.height * 2
radius = min(center_x, center_y) * 0.8
bbox = (center_x - radius, center_y - radius, center_x + radius, center_y + radius)
self.draw.arc(bbox, start=0, end=360, fill=self.highlight_color_rgb, width=5)
def _draw_pillow_counter_arc_stopped(self):
"""Draws the stopped state for the counter arc animation using Pillow."""
center_x, center_y = self.width * 2, self.height * 2
radius_outer = min(center_x, center_y) * 0.8
bbox_outer = (center_x - radius_outer, center_y - radius_outer, center_x + radius_outer, center_y + radius_outer)
@@ -327,11 +373,13 @@ class AnimatedIcon(tk.Canvas):
self.draw.arc(bbox_inner, start=0, end=360, fill=self.color_rgb, width=7)
def _draw_pillow_blink_stopped(self):
"""Draws the stopped state for the blink animation using Pillow."""
center_x, center_y = self.width * 2, self.height * 2
radius = min(center_x, center_y) * 0.8
self.draw.arc((center_x - radius, center_y - radius, center_x + radius, center_y + radius), start=0, end=360, fill=self.highlight_color_rgb, width=10)
def _animate(self):
"""The main animation loop."""
if self.running:
self.angle += 0.1
if self.angle > 2 * pi:
@@ -340,21 +388,30 @@ class AnimatedIcon(tk.Canvas):
self.after(30, self._animate)
def start(self, pulse=False):
"""
Starts the animation.
Args:
pulse (bool): If True, plays a pulsing animation instead of the main one.
"""
if not self.running:
self.pulse_animation = pulse
self.running = True
self._animate()
def stop(self):
"""Stops the animation and shows the static 'stopped' frame."""
self.running = False
self.pulse_animation = False
self._draw_stopped_frame()
def hide(self):
"""Stops the animation and clears the canvas."""
self.running = False
self.pulse_animation = False
self.delete("all")
def show_full_circle(self):
"""Shows the static 'stopped' frame without starting the animation."""
if not self.running:
self._draw_stopped_frame()
self._draw_stopped_frame()

View File

@@ -9,24 +9,16 @@ from shared_libs.common_tools import Translate
class AppConfig:
"""Central configuration and system setup manager for the Wire-Py application.
This class serves as a singleton-like container for all global configuration data,
including paths, UI settings, localization, versioning, and system-specific resources.
It ensures that required directories, files, and services are created and configured
before the application starts. Additionally, it provides tools for managing translations.
Key Responsibilities:
- Centralizes all configuration values (paths, UI preferences, localization).
- Ensures required directories and files exist.
- Handles translation setup via `gettext` for multilingual support.
- Manages default settings file generation.
- Configures autostart services using systemd for user-specific launch behavior.
This class is used globally across the application to access configuration data
consistently and perform system-level setup tasks.
"""
Holds static configuration values for the application.
Attributes:
SCRIPT_DIR (str): The absolute path to the directory where the script is running.
MAX_ITEMS_TO_DISPLAY (int): The maximum number of items to show in the file list to prevent performance issues.
BASE_DIR (Path): The user's home directory.
CONFIG_DIR (Path): The directory for storing configuration files.
UI_CONFIG (Dict[str, Any]): A dictionary containing UI-related settings.
"""
# Helper to make icon paths robust, so the script can be run from anywhere
SCRIPT_DIR = os.path.dirname(os.path.abspath(__file__))
MAX_ITEMS_TO_DISPLAY = 1000
@@ -69,7 +61,7 @@ class CfdConfigManager:
@classmethod
def _ensure_config_file(cls):
"""Ensures the config file exists with default values if not present."""
"""Ensures the configuration file exists, creating it with default settings if necessary."""
if not cls._config_file.exists():
try:
cls._config_file.parent.mkdir(parents=True, exist_ok=True)
@@ -80,7 +72,7 @@ class CfdConfigManager:
@classmethod
def load(cls):
"""Loads settings from the JSON file, applying defaults for missing keys."""
"""Loads settings from the JSON file. If the file doesn't exist or is invalid, it loads default settings."""
cls._ensure_config_file()
if cls._config is None:
try:
@@ -105,6 +97,13 @@ class CfdConfigManager:
class LocaleStrings:
"""
Contains all translatable strings for the application, organized by module.
This class centralizes all user-facing strings to make translation and management easier.
The strings are grouped into nested dictionaries corresponding to the part of the application
where they are used (e.g., CFD for the main dialog, VIEW for view-related strings).
"""
# Strings from custom_file_dialog.py
CFD = {
"title": _("Custom File Dialog"),
@@ -250,6 +249,4 @@ class LocaleStrings:
"pictures": _("Pictures"),
"videos": _("Videos"),
"computer": _("Computer"),
}
}