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
+66 -6
View File
@@ -17,6 +17,8 @@ from medicine_management_window import MedicineManagementWindow
from medicine_manager import MedicineManager
from pathology_management_window import PathologyManagementWindow
from pathology_manager import PathologyManager
from settings_window import SettingsWindow
from theme_manager import ThemeManager
from ui_manager import UIManager
@@ -44,6 +46,9 @@ class MedTrackerApp:
logger.info(f"Log level: {LOG_LEVEL}")
# Initialize theme manager first
self.theme_manager: ThemeManager = ThemeManager(self.root, logger)
if LOG_LEVEL == "DEBUG":
logger.debug(f"Script name: {sys.argv[0]}")
logger.debug(f"Logs path: {LOG_PATH}")
@@ -54,7 +59,11 @@ class MedTrackerApp:
self.medicine_manager: MedicineManager = MedicineManager(logger=logger)
self.pathology_manager: PathologyManager = PathologyManager(logger=logger)
self.ui_manager: UIManager = UIManager(
root, logger, self.medicine_manager, self.pathology_manager
root,
logger,
self.medicine_manager,
self.pathology_manager,
self.theme_manager,
)
self.data_manager: DataManager = DataManager(
self.filename, logger, self.medicine_manager, self.pathology_manager
@@ -103,7 +112,7 @@ class MedTrackerApp:
import tkinter.ttk as ttk
# --- Main Frame ---
main_frame: ttk.Frame = ttk.Frame(self.root, padding="10")
main_frame: ttk.Frame = ttk.Frame(self.root, padding="10", style="Card.TFrame")
main_frame.grid(row=0, column=0, sticky="nsew")
# Configure root window grid
@@ -206,9 +215,36 @@ class MedTrackerApp:
label="Refresh Data", command=self.refresh_data_display, accelerator="F5"
)
# Theme menu
theme_menu = tk.Menu(menubar, tearoff=0)
menubar.add_cascade(label="Theme", menu=theme_menu)
# Add quick theme options
available_themes = self.theme_manager.get_available_themes()
current_theme = self.theme_manager.get_current_theme()
for theme in available_themes:
theme_menu.add_radiobutton(
label=theme.title(),
command=lambda t=theme: self._change_theme(t),
value=theme == current_theme,
)
theme_menu.add_separator()
theme_menu.add_command(
label="More Settings...",
command=self._open_settings_window,
)
# Help menu
help_menu = tk.Menu(menubar, tearoff=0)
menubar.add_cascade(label="Help", menu=help_menu)
help_menu.add_command(
label="Settings...",
command=self._open_settings_window,
accelerator="F2",
)
help_menu.add_separator()
help_menu.add_command(
label="Keyboard Shortcuts",
command=self._show_keyboard_shortcuts,
@@ -237,6 +273,7 @@ class MedTrackerApp:
self.root.bind("<Delete>", lambda e: self._delete_selected_entry())
self.root.bind("<Escape>", lambda e: self._clear_selection())
self.root.bind("<F1>", lambda e: self._show_keyboard_shortcuts())
self.root.bind("<F2>", lambda e: self._open_settings_window())
# Make the window focusable so it can receive key events
self.root.focus_set()
@@ -276,10 +313,24 @@ Table Operations:
• Double-click: Edit entry
Help:
• F1: Show this help dialog"""
• F1: Show this help dialog
• F2: Open settings window"""
messagebox.showinfo("Keyboard Shortcuts", shortcuts_text, parent=self.root)
def _change_theme(self, theme_name: str) -> None:
"""Change the application theme."""
if self.theme_manager.apply_theme(theme_name):
self.ui_manager.update_status(
f"Theme changed to: {theme_name.title()}", "info"
)
# Refresh the menu to update radio button selection
self._setup_menu()
else:
self.ui_manager.update_status(
f"Failed to apply theme: {theme_name}", "error"
)
def _show_about_dialog(self) -> None:
"""Show about dialog."""
about_text = """TheChart - Medication Tracker
@@ -315,6 +366,11 @@ Use Ctrl+S to save entries and Ctrl+Q to quit."""
self.root, self.medicine_manager, self._refresh_ui_after_config_change
)
def _open_settings_window(self) -> None:
"""Open the settings window."""
self.ui_manager.update_status("Opening settings window", "info")
SettingsWindow(self.root, self.theme_manager, self.ui_manager)
def _refresh_ui_after_config_change(self) -> None:
"""Refresh UI components after pathology or medicine configuration changes."""
self.ui_manager.update_status(
@@ -678,9 +734,13 @@ Use Ctrl+S to save entries and Ctrl+Q to quit."""
# Fallback - just use all columns
display_df = df
# Batch insert for better performance
for _index, row in display_df.iterrows():
self.tree.insert(parent="", index="end", values=list(row))
# Batch insert for better performance with alternating row colors
for index, row in display_df.iterrows():
# Add alternating row tags for better visibility
tag = "evenrow" if index % 2 == 0 else "oddrow"
self.tree.insert(
parent="", index="end", values=list(row), tags=(tag,)
)
logger.debug(f"Loaded {len(display_df)} entries into treeview.")
# Update the graph