"""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()