Add theme management and settings functionality
Build and Push Docker Image / build-and-push (push) Has been cancelled

- Introduced `ThemeManager` to handle application themes using `ttkthemes`.
- Added `SettingsWindow` for user preferences including theme selection and UI settings.
- Integrated theme selection into the main application with a menu for quick access.
- Enhanced UI components with custom styles based on the selected theme.
- Implemented tooltips for better user guidance across various UI elements.
- Updated dependencies to include `ttkthemes` for improved visual appeal.
This commit is contained in:
William Valentin
2025-08-05 11:58:25 -07:00
parent 86606d56b6
commit c3c88c63d2
14 changed files with 1287 additions and 70 deletions
+163
View File
@@ -0,0 +1,163 @@
"""Tooltip system for enhanced user experience."""
import tkinter as tk
class ToolTip:
"""Create a tooltip for a given widget."""
def __init__(
self,
widget: tk.Widget,
text: str,
delay: int = 500,
wrap_length: int = 250,
) -> None:
self.widget = widget
self.text = text
self.delay = delay
self.wrap_length = wrap_length
self.tooltip: tk.Toplevel | None = None
self.id_after: str | None = None
# Bind events
self.widget.bind("<Enter>", self._on_enter)
self.widget.bind("<Leave>", self._on_leave)
self.widget.bind("<ButtonPress>", self._on_leave)
def _on_enter(self, event: tk.Event | None = None) -> None:
"""Mouse entered widget - schedule tooltip."""
self._cancel_scheduled()
self.id_after = self.widget.after(self.delay, self._show_tooltip)
def _on_leave(self, event: tk.Event | None = None) -> None:
"""Mouse left widget - hide tooltip."""
self._cancel_scheduled()
self._hide_tooltip()
def _cancel_scheduled(self) -> None:
"""Cancel any scheduled tooltip."""
if self.id_after:
self.widget.after_cancel(self.id_after)
self.id_after = None
def _show_tooltip(self) -> None:
"""Display the tooltip."""
if self.tooltip:
return
# Get widget position
x = self.widget.winfo_rootx() + 25
y = self.widget.winfo_rooty() + 25
# Create tooltip window
self.tooltip = tk.Toplevel(self.widget)
self.tooltip.wm_overrideredirect(True)
self.tooltip.wm_geometry(f"+{x}+{y}")
# Create tooltip content
label = tk.Label(
self.tooltip,
text=self.text,
justify="left",
background="#ffffe0",
foreground="#000000",
relief="solid",
borderwidth=1,
font=("TkDefaultFont", "9", "normal"),
wraplength=self.wrap_length,
padx=8,
pady=6,
)
label.pack()
# Make sure tooltip appears above other windows
self.tooltip.lift()
def _hide_tooltip(self) -> None:
"""Hide the tooltip."""
if self.tooltip:
self.tooltip.destroy()
self.tooltip = None
def update_text(self, new_text: str) -> None:
"""Update the tooltip text."""
self.text = new_text
class TooltipManager:
"""Manages tooltips for UI elements."""
def __init__(self, theme_manager) -> None:
self.theme_manager = theme_manager
self.tooltips: list[ToolTip] = []
def add_tooltip(
self,
widget: tk.Widget,
text: str,
delay: int = 500,
wrap_length: int = 250,
) -> ToolTip:
"""Add a tooltip to a widget."""
tooltip = ToolTip(widget, text, delay, wrap_length)
self.tooltips.append(tooltip)
return tooltip
def add_scale_tooltip(self, scale_widget: tk.Widget, pathology_name: str) -> None:
"""Add a specialized tooltip for pathology scales."""
text = (
f"Adjust your {pathology_name} level\\n"
"• Drag the slider to set your current level\\n"
"• Higher values typically indicate worse symptoms\\n"
"• Use the full range for accurate tracking"
)
self.add_tooltip(scale_widget, text, delay=800)
def add_medicine_tooltip(self, widget: tk.Widget, medicine_name: str) -> None:
"""Add a specialized tooltip for medicine checkboxes."""
text = (
f"Mark if you took {medicine_name} today\\n"
"• Check the box when you've taken this medication\\n"
"• This helps track your medication adherence\\n"
"• You can add dose details when editing entries"
)
self.add_tooltip(widget, text, delay=600)
def add_button_tooltip(self, widget: tk.Widget, action: str) -> None:
"""Add a tooltip for action buttons."""
tooltips_map = {
"save": (
"Save your current entry (Ctrl+S)\\nThis will add a new daily record"
),
"export": (
"Export your data to various formats\\n"
"Supports CSV, PDF, and image exports"
),
"refresh": (
"Reload data from file (F5)\\nUpdates the display with latest changes"
),
"settings": (
"Open application settings (F2)\\nCustomize themes and preferences"
),
"quit": (
"Exit the application (Ctrl+Q)\\nYour data will be automatically saved"
),
}
text = tooltips_map.get(action, f"Perform {action} action")
self.add_tooltip(widget, text, delay=400)
def add_menu_tooltip(self, widget: tk.Widget, menu_type: str) -> None:
"""Add tooltips for menu items."""
tooltips_map = {
"theme": (
"Quick theme selection\\nClick to instantly change the app's appearance"
),
"file": "File operations\\nExport data and manage files",
"tools": ("Data management tools\\nConfigure medicines and pathologies"),
"help": ("Get help and information\\nKeyboard shortcuts and about dialog"),
}
text = tooltips_map.get(menu_type, "Menu options")
self.add_tooltip(widget, text, delay=600)