c3c88c63d2
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.
325 lines
10 KiB
Python
325 lines
10 KiB
Python
"""Settings window for TheChart application."""
|
|
|
|
import tkinter as tk
|
|
from tkinter import messagebox, ttk
|
|
|
|
|
|
class SettingsWindow:
|
|
"""Settings window for application preferences."""
|
|
|
|
def __init__(self, parent: tk.Tk, theme_manager, ui_manager) -> None:
|
|
self.parent = parent
|
|
self.theme_manager = theme_manager
|
|
self.ui_manager = ui_manager
|
|
|
|
# Create window
|
|
self.window = tk.Toplevel(parent)
|
|
self.window.title("Settings - TheChart")
|
|
self.window.geometry("500x400")
|
|
self.window.resizable(False, False)
|
|
|
|
# Make window modal
|
|
self.window.transient(parent)
|
|
self.window.grab_set()
|
|
|
|
# Center the window
|
|
self._center_window()
|
|
|
|
# Setup UI
|
|
self._setup_ui()
|
|
|
|
# Set initial values
|
|
self._load_current_settings()
|
|
|
|
def _center_window(self) -> None:
|
|
"""Center the settings window on the parent."""
|
|
self.window.update_idletasks()
|
|
|
|
# Get window dimensions
|
|
window_width = self.window.winfo_reqwidth()
|
|
window_height = self.window.winfo_reqheight()
|
|
|
|
# Get parent window position and size
|
|
parent_x = self.parent.winfo_x()
|
|
parent_y = self.parent.winfo_y()
|
|
parent_width = self.parent.winfo_width()
|
|
parent_height = self.parent.winfo_height()
|
|
|
|
# Calculate centered position
|
|
x = parent_x + (parent_width // 2) - (window_width // 2)
|
|
y = parent_y + (parent_height // 2) - (window_height // 2)
|
|
|
|
self.window.geometry(f"{window_width}x{window_height}+{x}+{y}")
|
|
|
|
def _setup_ui(self) -> None:
|
|
"""Setup the settings UI."""
|
|
# Main container
|
|
main_frame = ttk.Frame(self.window, padding="20", style="Card.TFrame")
|
|
main_frame.pack(fill="both", expand=True)
|
|
|
|
# Title
|
|
title_label = ttk.Label(
|
|
main_frame,
|
|
text="Application Settings",
|
|
font=("TkDefaultFont", 16, "bold"),
|
|
)
|
|
title_label.pack(pady=(0, 20))
|
|
|
|
# Create notebook for different setting categories
|
|
notebook = ttk.Notebook(main_frame, style="Modern.TNotebook")
|
|
notebook.pack(fill="both", expand=True, pady=(0, 20))
|
|
|
|
# Theme settings tab
|
|
self._create_theme_tab(notebook)
|
|
|
|
# UI settings tab
|
|
self._create_ui_tab(notebook)
|
|
|
|
# About tab
|
|
self._create_about_tab(notebook)
|
|
|
|
# Button frame
|
|
button_frame = ttk.Frame(main_frame)
|
|
button_frame.pack(fill="x", pady=(10, 0))
|
|
|
|
# Buttons
|
|
ttk.Button(
|
|
button_frame,
|
|
text="Apply",
|
|
command=self._apply_settings,
|
|
style="Action.TButton",
|
|
).pack(side="right", padx=(5, 0))
|
|
|
|
ttk.Button(
|
|
button_frame,
|
|
text="Cancel",
|
|
command=self._cancel,
|
|
style="Action.TButton",
|
|
).pack(side="right")
|
|
|
|
ttk.Button(
|
|
button_frame,
|
|
text="OK",
|
|
command=self._ok,
|
|
style="Action.TButton",
|
|
).pack(side="right", padx=(0, 5))
|
|
|
|
def _create_theme_tab(self, notebook: ttk.Notebook) -> None:
|
|
"""Create the theme settings tab."""
|
|
theme_frame = ttk.Frame(notebook, style="Card.TFrame")
|
|
notebook.add(theme_frame, text="Theme")
|
|
|
|
# Theme selection
|
|
theme_label_frame = ttk.LabelFrame(
|
|
theme_frame, text="Theme Selection", style="Card.TLabelframe"
|
|
)
|
|
theme_label_frame.pack(fill="x", padx=10, pady=10)
|
|
|
|
ttk.Label(
|
|
theme_label_frame,
|
|
text="Choose your preferred theme:",
|
|
font=("TkDefaultFont", 10),
|
|
).pack(anchor="w", padx=10, pady=(10, 5))
|
|
|
|
# Theme radio buttons
|
|
self.theme_var = tk.StringVar()
|
|
themes = self.theme_manager.get_available_themes()
|
|
|
|
theme_buttons_frame = ttk.Frame(theme_label_frame)
|
|
theme_buttons_frame.pack(fill="x", padx=10, pady=(0, 10))
|
|
|
|
# Create radio buttons in a grid
|
|
for i, theme in enumerate(themes):
|
|
row = i // 3
|
|
col = i % 3
|
|
|
|
ttk.Radiobutton(
|
|
theme_buttons_frame,
|
|
text=theme.title(),
|
|
variable=self.theme_var,
|
|
value=theme,
|
|
style="Modern.TCheckbutton",
|
|
).grid(row=row, column=col, sticky="w", padx=5, pady=2)
|
|
|
|
# Theme preview info
|
|
preview_frame = ttk.LabelFrame(
|
|
theme_frame, text="Theme Preview", style="Card.TLabelframe"
|
|
)
|
|
preview_frame.pack(fill="both", expand=True, padx=10, pady=(0, 10))
|
|
|
|
preview_text = tk.Text(
|
|
preview_frame,
|
|
height=6,
|
|
wrap="word",
|
|
font=("TkDefaultFont", 9),
|
|
state="disabled",
|
|
)
|
|
preview_text.pack(fill="both", expand=True, padx=10, pady=10)
|
|
|
|
# Theme change callback
|
|
def on_theme_change():
|
|
selected_theme = self.theme_var.get()
|
|
preview_text.config(state="normal")
|
|
preview_text.delete("1.0", "end")
|
|
preview_text.insert(
|
|
"1.0",
|
|
f"Selected theme: {selected_theme.title()}\\n\\n"
|
|
"Theme changes will be applied when you click 'Apply' or 'OK'. "
|
|
"The new theme will affect all windows and UI elements "
|
|
"in the application.",
|
|
)
|
|
preview_text.config(state="disabled")
|
|
|
|
self.theme_var.trace("w", lambda *args: on_theme_change())
|
|
|
|
def _create_ui_tab(self, notebook: ttk.Notebook) -> None:
|
|
"""Create the UI settings tab."""
|
|
ui_frame = ttk.Frame(notebook, style="Card.TFrame")
|
|
notebook.add(ui_frame, text="Interface")
|
|
|
|
# Font settings
|
|
font_frame = ttk.LabelFrame(
|
|
ui_frame, text="Font Settings", style="Card.TLabelframe"
|
|
)
|
|
font_frame.pack(fill="x", padx=10, pady=10)
|
|
|
|
ttk.Label(
|
|
font_frame,
|
|
text="Font size adjustments (requires restart):",
|
|
font=("TkDefaultFont", 10),
|
|
).pack(anchor="w", padx=10, pady=10)
|
|
|
|
# Font size scale
|
|
self.font_scale_var = tk.DoubleVar(value=1.0)
|
|
font_scale = ttk.Scale(
|
|
font_frame,
|
|
from_=0.8,
|
|
to=1.5,
|
|
variable=self.font_scale_var,
|
|
orient="horizontal",
|
|
style="Modern.Horizontal.TScale",
|
|
)
|
|
font_scale.pack(fill="x", padx=10, pady=(0, 10))
|
|
|
|
# Scale labels
|
|
scale_labels_frame = ttk.Frame(font_frame)
|
|
scale_labels_frame.pack(fill="x", padx=10, pady=(0, 10))
|
|
|
|
ttk.Label(scale_labels_frame, text="Small").pack(side="left")
|
|
ttk.Label(scale_labels_frame, text="Large").pack(side="right")
|
|
ttk.Label(scale_labels_frame, text="Normal").pack()
|
|
|
|
# Window settings
|
|
window_frame = ttk.LabelFrame(
|
|
ui_frame, text="Window Settings", style="Card.TLabelframe"
|
|
)
|
|
window_frame.pack(fill="x", padx=10, pady=(0, 10))
|
|
|
|
# Remember window size
|
|
self.remember_size_var = tk.BooleanVar(value=True)
|
|
ttk.Checkbutton(
|
|
window_frame,
|
|
text="Remember window size and position",
|
|
variable=self.remember_size_var,
|
|
style="Modern.TCheckbutton",
|
|
).pack(anchor="w", padx=10, pady=10)
|
|
|
|
# Always on top
|
|
self.always_on_top_var = tk.BooleanVar(value=False)
|
|
ttk.Checkbutton(
|
|
window_frame,
|
|
text="Keep window always on top",
|
|
variable=self.always_on_top_var,
|
|
style="Modern.TCheckbutton",
|
|
).pack(anchor="w", padx=10, pady=(0, 10))
|
|
|
|
def _create_about_tab(self, notebook: ttk.Notebook) -> None:
|
|
"""Create the about tab."""
|
|
about_frame = ttk.Frame(notebook, style="Card.TFrame")
|
|
notebook.add(about_frame, text="About")
|
|
|
|
# App info
|
|
info_frame = ttk.LabelFrame(
|
|
about_frame, text="Application Information", style="Card.TLabelframe"
|
|
)
|
|
info_frame.pack(fill="both", expand=True, padx=10, pady=10)
|
|
|
|
about_text = tk.Text(
|
|
info_frame,
|
|
wrap="word",
|
|
font=("TkDefaultFont", 10),
|
|
state="disabled",
|
|
bg=self.theme_manager.get_theme_colors()["bg"],
|
|
fg=self.theme_manager.get_theme_colors()["fg"],
|
|
)
|
|
about_text.pack(fill="both", expand=True, padx=10, pady=10)
|
|
|
|
about_content = """TheChart - Medication Tracker
|
|
|
|
Version: 1.9.5
|
|
Built with: Python, Tkinter, ttkthemes
|
|
|
|
Features:
|
|
• Modern themed interface with multiple themes
|
|
• Medication and pathology tracking
|
|
• Visual graphs and charts
|
|
• Data export capabilities
|
|
• Keyboard shortcuts for efficiency
|
|
• Customizable UI settings
|
|
|
|
This application helps you track your daily medications and health
|
|
conditions with an intuitive, modern interface.
|
|
|
|
Enhanced with ttkthemes for better visual appeal and user experience."""
|
|
|
|
about_text.config(state="normal")
|
|
about_text.insert("1.0", about_content)
|
|
about_text.config(state="disabled")
|
|
|
|
def _load_current_settings(self) -> None:
|
|
"""Load current application settings."""
|
|
# Set current theme
|
|
current_theme = self.theme_manager.get_current_theme()
|
|
self.theme_var.set(current_theme)
|
|
|
|
# Trigger theme change to update preview
|
|
if hasattr(self, "theme_var"):
|
|
self.theme_var.set(current_theme)
|
|
|
|
def _apply_settings(self) -> None:
|
|
"""Apply the selected settings."""
|
|
# Apply theme if changed
|
|
selected_theme = self.theme_var.get()
|
|
current_theme = self.theme_manager.get_current_theme()
|
|
|
|
if selected_theme != current_theme:
|
|
if self.theme_manager.apply_theme(selected_theme):
|
|
self.ui_manager.update_status(
|
|
f"Theme changed to: {selected_theme.title()}", "info"
|
|
)
|
|
else:
|
|
messagebox.showerror(
|
|
"Error",
|
|
f"Failed to apply theme: {selected_theme}",
|
|
parent=self.window,
|
|
)
|
|
return
|
|
|
|
# Apply other settings (font size, window settings, etc.)
|
|
# These would typically be saved to a config file
|
|
|
|
messagebox.showinfo(
|
|
"Settings Applied",
|
|
"Settings have been applied successfully!",
|
|
parent=self.window,
|
|
)
|
|
|
|
def _ok(self) -> None:
|
|
"""Apply settings and close window."""
|
|
self._apply_settings()
|
|
self.window.destroy()
|
|
|
|
def _cancel(self) -> None:
|
|
"""Close window without applying settings."""
|
|
self.window.destroy()
|