diff --git a/README.md b/README.md index 7d43ae9..aaa7ede 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,7 @@ # TheChart -Advanced medication tracking application for monitoring treatment progress and symptom evolution. +Modern medication tracking application with advanced UI/UX for monitoring treatment progress and symptom evolution. -## Quick Start +## 🚀 Quick Start ```bash # Install dependencies make install @@ -14,12 +14,22 @@ make test ``` ## 📚 Documentation -- **[Features Guide](docs/FEATURES.md)** - Complete feature documentation -- **[Keyboard Shortcuts](docs/KEYBOARD_SHORTCUTS.md)** - Keyboard shortcuts for efficient navigation -- **[Export System](docs/EXPORT_SYSTEM.md)** - Data export functionality and formats +- **[Features Guide](docs/FEATURES.md)** - Complete feature documentation with UI/UX improvements +- **[Keyboard Shortcuts](docs/KEYBOARD_SHORTCUTS.md)** - Comprehensive keyboard shortcuts for efficiency +- **[Export System](docs/EXPORT_SYSTEM.md)** - Data export functionality (JSON, XML, PDF) - **[Development Guide](docs/DEVELOPMENT.md)** - Testing, development, and architecture -- **[Changelog](docs/CHANGELOG.md)** - Version history and feature evolution -- **[Quick Reference](#quick-reference)** - Common commands and shortcuts +- **[Changelog](docs/CHANGELOG.md)** - Version history and recent UI improvements +- **[Documentation Index](docs/README.md)** - Complete documentation navigation guide + +> 💡 **Quick Start**: New users should start with this README, then explore the [Features Guide](docs/FEATURES.md) for detailed functionality. The [Documentation Index](docs/README.md) provides comprehensive navigation. + +## ✨ Recent Major Updates (v1.9.5) +- **🎨 Modern UI/UX**: Professional themes with ttkthemes integration +- **⌨️ Keyboard Shortcuts**: Comprehensive shortcut system for all operations +- **💡 Smart Tooltips**: Context-sensitive help throughout the application +- **🎭 8 Professional Themes**: Arc, Equilux, Adapta, Yaru, Ubuntu, Plastik, Breeze, Elegance +- **⚙️ Settings System**: Advanced configuration with theme persistence +- **📊 Enhanced Tables**: Improved selection highlighting and alternating row colors ## Table of Contents - [Prerequisites](#prerequisites) diff --git a/docs/CHANGELOG.md b/docs/CHANGELOG.md index a7b295e..f5c4def 100644 --- a/docs/CHANGELOG.md +++ b/docs/CHANGELOG.md @@ -5,6 +5,41 @@ All notable changes to TheChart project are documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). +## [1.9.5] - 2025-08-05 + +### 🎨 Major UI/UX Overhaul +- **Added**: Professional theme system with ttkthemes integration +- **Added**: 8 curated themes (Arc, Equilux, Adapta, Yaru, Ubuntu, Plastik, Breeze, Elegance) +- **Added**: Dynamic theme switching without restart +- **Added**: Theme persistence between sessions +- **Added**: Comprehensive settings window with tabbed interface +- **Added**: Smart tooltip system with context-sensitive help +- **Improved**: Table selection highlighting and alternating row colors +- **Improved**: Modern styling for all UI components (buttons, frames, forms) +- **Improved**: Professional card-style layouts and enhanced spacing + +### ⚙️ Settings and Configuration System +- **Added**: Advanced settings window (accessible via F2) +- **Added**: Theme selection with live preview +- **Added**: UI preferences and customization options +- **Added**: About dialog with detailed application information +- **Added**: Settings persistence across application restarts + +### 💡 Enhanced User Experience +- **Added**: Intelligent tooltips for all interactive elements +- **Added**: Specialized help for pathology scales and medicine options +- **Added**: Non-intrusive tooltip timing (500-800ms delay) +- **Added**: Quick theme switching via menu bar +- **Improved**: Visual hierarchy with better typography and spacing +- **Improved**: Professional color schemes across all themes + +### 🏗️ Technical Architecture Improvements +- **Added**: Modular theme manager with dependency injection +- **Added**: Tooltip management system +- **Added**: Enhanced UI manager with theme integration +- **Improved**: Code organization with separate concerns +- **Improved**: Error handling with graceful theme fallbacks + ## [1.7.0] - 2025-08-05 ### ⌨️ Keyboard Shortcuts System diff --git a/docs/DOCUMENTATION_SUMMARY.md b/docs/DOCUMENTATION_SUMMARY.md new file mode 100644 index 0000000..17a7a87 --- /dev/null +++ b/docs/DOCUMENTATION_SUMMARY.md @@ -0,0 +1,109 @@ +# Documentation Consolidation Summary + +## Overview +This document summarizes the documentation consolidation and updates performed to improve the TheChart project documentation structure. + +## Changes Made + +### 1. Documentation Structure Consolidation +- **Removed**: `docs/UI_IMPROVEMENTS.md` (redundant file) +- **Consolidated**: UI/UX improvements documentation into `docs/FEATURES.md` +- **Enhanced**: Main `README.md` with recent updates section +- **Updated**: `docs/README.md` (documentation index) with comprehensive navigation + +### 2. Content Integration + +#### FEATURES.md Enhancements +- **Added**: Modern UI/UX System section (new in v1.9.5) +- **Added**: Professional Theme Engine documentation +- **Added**: Comprehensive Keyboard Shortcuts section +- **Added**: Settings and Theme Management documentation +- **Added**: Smart Tooltip System documentation +- **Added**: Enhanced Technical Architecture section +- **Added**: UI/UX Technical Implementation section + +#### CHANGELOG.md Updates +- **Added**: Version 1.9.5 with comprehensive UI/UX overhaul documentation +- **Added**: Settings and Configuration System section +- **Added**: Enhanced User Experience section +- **Added**: Technical Architecture Improvements section + +#### README.md Improvements +- **Updated**: Title and description to emphasize modern UI/UX +- **Added**: Recent Major Updates section highlighting v1.9.5 improvements +- **Added**: Quick start guidance for new users +- **Updated**: Documentation links with better descriptions +- **Added**: Documentation navigation guide reference + +### 3. Cross-Reference Updates +- **Updated**: All internal links to reflect consolidated structure +- **Enhanced**: Documentation index with comprehensive navigation +- **Added**: Task-based navigation in docs/README.md +- **Improved**: User type-based documentation guidance + +## Current Documentation Structure + +``` +docs/ +├── README.md # Documentation index and navigation guide +├── FEATURES.md # Complete feature documentation (includes UI/UX) +├── KEYBOARD_SHORTCUTS.md # Comprehensive shortcut reference +├── EXPORT_SYSTEM.md # Data export functionality +├── DEVELOPMENT.md # Development setup and testing +├── CHANGELOG.md # Version history and improvements +└── DOCUMENTATION_SUMMARY.md # This summary (new) + +README.md # Main project README with quick start +``` + +## Documentation Highlights + +### For End Users +1. **Modern UI/UX**: Complete documentation of the new theme system +2. **Keyboard Efficiency**: Comprehensive shortcut system documentation +3. **Feature Guidance**: Consolidated feature documentation with examples +4. **Quick Navigation**: Task-based and user-type-based navigation + +### For Developers +1. **Technical Architecture**: Enhanced architecture documentation +2. **UI/UX Implementation**: Technical details of theme system +3. **Code Organization**: Clear separation of concerns documentation +4. **Development Workflow**: Comprehensive development guide + +## Quality Improvements + +### Content Quality +- **Comprehensive Coverage**: All major features and improvements documented +- **Clear Structure**: Hierarchical organization with clear headings +- **Practical Examples**: Code snippets and usage examples maintained +- **Cross-References**: Better linking between related sections + +### User Experience +- **Progressive Disclosure**: Information organized by user expertise level +- **Task-Oriented**: Documentation organized around user tasks +- **Quick Access**: Multiple entry points and navigation paths +- **Searchable**: Clear headings and consistent formatting + +### Maintenance +- **Reduced Redundancy**: Eliminated duplicate information +- **Single Source of Truth**: Consolidated information reduces maintenance burden +- **Version Alignment**: Documentation synchronized with current codebase +- **Future-Proof**: Structure supports easy updates and additions + +## Next Steps + +### Recommended Maintenance +1. **Keep Features Updated**: Update FEATURES.md as new UI/UX improvements are added +2. **Maintain Changelog**: Continue detailed changelog entries for version tracking +3. **Review Navigation**: Periodically review docs/README.md navigation for completeness +4. **User Feedback**: Collect user feedback on documentation effectiveness + +### Future Enhancements +1. **Screenshots**: Consider adding screenshots of the new UI themes +2. **Video Guides**: Potential for video demonstrations of key features +3. **API Documentation**: If public APIs develop, consider separate API docs +4. **Internationalization**: Structure supports future translation efforts + +--- + +**Documentation consolidation completed**: All major UI/UX improvements are now properly documented and easily discoverable through the improved navigation structure. diff --git a/docs/FEATURES.md b/docs/FEATURES.md index 64754aa..7f535ce 100644 --- a/docs/FEATURES.md +++ b/docs/FEATURES.md @@ -1,7 +1,49 @@ # TheChart - Features Documentation ## Overview -TheChart is a comprehensive medication tracking application that allows users to monitor medication intake, symptom tracking, and visualize treatment progress over time. +TheChart is a comprehensive medication tracking application with a modern, professional UI that allows users to monitor medication intake, track symptoms, and visualize treatment progress over time. + +## 🎨 Modern UI/UX System (New in v1.9.5) + +### Professional Theme Engine +TheChart features a sophisticated theme system powered by ttkthemes, offering 8 carefully curated professional themes. + +#### Available Themes: +- **Arc**: Modern flat design with subtle shadows +- **Equilux**: Dark theme with excellent contrast +- **Adapta**: Clean, minimalist design +- **Yaru**: Ubuntu-inspired modern interface +- **Ubuntu**: Official Ubuntu styling +- **Plastik**: Classic professional appearance +- **Breeze**: KDE-inspired clean design +- **Elegance**: Sophisticated dark theme + +#### UI Enhancements: +- **Modern Styling**: Card-style frames, enhanced buttons, professional form controls +- **Smart Tooltips**: Context-sensitive help for all interactive elements +- **Improved Tables**: Better selection highlighting and alternating row colors +- **Settings System**: Comprehensive preferences with theme persistence +- **Responsive Design**: Automatic layout adjustments and scaling + +### ⌨️ Comprehensive Keyboard Shortcuts +Professional keyboard shortcut system for efficient navigation and operation. + +#### File Operations: +- **Ctrl+S**: Save/Add new entry +- **Ctrl+Q**: Quit application (with confirmation) +- **Ctrl+E**: Export data + +#### Data Management: +- **Ctrl+N**: Clear entries +- **Ctrl+R / F5**: Refresh data +- **Delete**: Delete selected entry +- **Escape**: Clear selection + +#### Window Management: +- **Ctrl+M**: Manage medicines +- **Ctrl+P**: Manage pathologies +- **F1**: Show keyboard shortcuts help +- **F2**: Open settings window ## Core Features @@ -37,6 +79,36 @@ Each medicine includes: 2. **Manual Configuration**: Edit `medicines.json` directly 3. **Programmatically**: Use the MedicineManager API +### ⚙️ Settings and Theme Management +Advanced configuration system allowing users to customize their experience. + +#### Settings Window (F2): +- **Theme Selection**: Choose from 8 professional themes with live preview +- **UI Preferences**: Font scaling, window behavior options +- **About Information**: Detailed application and version information +- **Tabbed Interface**: Organized settings categories for easy navigation + +#### Theme Features: +- **Real-time Switching**: No restart required for theme changes +- **Persistence**: Selected theme remembered between sessions +- **Quick Access**: Theme menu for instant switching +- **Fallback Handling**: Graceful handling if themes fail to load + +### 💡 Smart Tooltip System +Context-sensitive help system providing guidance throughout the application. + +#### Tooltip Types: +- **Pathology Scales**: Usage guidance for symptom tracking +- **Medicine Checkboxes**: Medication information and dosage details +- **Action Buttons**: Functionality description with keyboard shortcuts +- **Form Controls**: Input guidance and format requirements + +#### Features: +- **Delayed Display**: Non-intrusive timing (500-800ms delay) +- **Theme-aware Styling**: Tooltips match selected theme +- **Smart Positioning**: Automatic placement to avoid screen edges +- **Rich Content**: Multi-line descriptions with formatting + ### 💊 Advanced Dose Tracking Comprehensive dose tracking system that records exact timestamps and dosages throughout the day. @@ -192,24 +264,49 @@ Comprehensive keyboard shortcuts for efficient navigation and data entry. ## Technical Architecture -### 🏗️ Modular Design -- **MedicineManager**: Core medicine CRUD operations -- **PathologyManager**: Symptom and pathology management -- **GraphManager**: All graph-related operations and visualizations -- **UIManager**: User interface creation and management -- **DataManager**: CSV operations and data persistence +### � Modern UI Architecture +- **ThemeManager**: Centralized theme management with dynamic switching +- **TooltipManager**: Smart tooltip system with context-sensitive help +- **UIManager**: Enhanced UI component creation with theme integration +- **SettingsWindow**: Advanced configuration interface with persistence -### 🔧 Configuration Management -- **JSON-based Configuration**: `medicines.json` and `pathologies.json` -- **Dynamic Loading**: Runtime configuration updates -- **Validation**: Input validation and error handling -- **Backward Compatibility**: Seamless updates and migrations +### 🏗️ Core Application Design +- **MedicineManager**: Core medicine CRUD operations with JSON persistence +- **PathologyManager**: Symptom and pathology management system +- **GraphManager**: Professional graph rendering with matplotlib integration +- **DataManager**: Robust CSV operations and data persistence with validation -### 📈 Data Processing +### 🔧 Configuration and Data Management +- **JSON-based Configuration**: `medicines.json` and `pathologies.json` for easy management +- **Dynamic Loading**: Runtime configuration updates without restarts +- **Data Validation**: Comprehensive input validation and error handling +- **Backward Compatibility**: Seamless updates and migrations across versions + +### 📈 Advanced Data Processing - **Pandas Integration**: Efficient data manipulation and analysis -- **Matplotlib Visualization**: Professional graph rendering -- **Robust Parsing**: Handles various data formats and edge cases -- **Real-time Calculations**: Dynamic dose totals and averages +- **Real-time Calculations**: Dynamic dose totals, averages, and statistics +- **Robust Parsing**: Handles various data formats and edge cases gracefully +- **Performance Optimization**: Efficient batch operations and caching + +## UI/UX Technical Implementation + +### 🎭 Theme System Architecture +- **Multiple Theme Support**: 8 curated professional themes +- **Dynamic Style Application**: Real-time theme switching without restart +- **Color Extraction**: Automatic color scheme detection and application +- **Fallback Mechanisms**: Graceful handling when themes fail to load + +### 💡 Enhanced User Experience +- **Smart Tooltips**: Context-sensitive help with delayed, non-intrusive display +- **Modern Styling**: Card-style frames, enhanced buttons, professional form controls +- **Improved Tables**: Better selection highlighting and alternating row colors +- **Responsive Design**: Automatic layout adjustments and proper scaling + +### ⚙️ Settings and Persistence +- **Configuration Management**: Theme and preference persistence across sessions +- **Tabbed Settings Interface**: Organized categories for easy navigation +- **Live Preview**: Real-time theme preview in settings +- **Error Recovery**: Robust handling of corrupted settings with defaults ## Deployment and Distribution diff --git a/docs/README.md b/docs/README.md index b610e29..d09d4f0 100644 --- a/docs/README.md +++ b/docs/README.md @@ -1,21 +1,27 @@ # TheChart Documentation -Welcome to TheChart documentation! This guide will help you navigate the available documentation. +Welcome to TheChart documentation! This guide will help you navigate the available documentation for the modern medication tracking application. ## 📖 Documentation Index ### For Users - **[README.md](../README.md)** - Quick start guide and installation -- **[Features Guide](FEATURES.md)** - Complete feature documentation +- **[Features Guide](FEATURES.md)** - Complete feature documentation including new UI/UX improvements + - Modern Theme System (8 Professional Themes) + - Advanced Keyboard Shortcuts + - Smart Tooltip System - Modular Medicine System - Advanced Dose Tracking - Graph Visualizations - Data Management - - Keyboard Shortcuts - **[Keyboard Shortcuts](KEYBOARD_SHORTCUTS.md)** - Comprehensive shortcut reference - - File operations shortcuts - - Data management shortcuts - - Navigation shortcuts + - File operations shortcuts (Ctrl+S, Ctrl+Q, Ctrl+E) + - Data management shortcuts (Ctrl+N, Ctrl+R, F5) + - Navigation shortcuts (Ctrl+M, Ctrl+P, F1, F2) +- **[Export System](EXPORT_SYSTEM.md)** - Data export functionality and formats + - JSON, XML, and PDF export options + - Graph visualization inclusion + - Export manager architecture ### For Developers - **[Development Guide](DEVELOPMENT.md)** - Development setup and testing @@ -26,53 +32,69 @@ Welcome to TheChart documentation! This guide will help you navigate the availab ### Project History - **[Changelog](CHANGELOG.md)** - Version history and feature evolution - - Recent updates and improvements - - Migration notes - - Future roadmap + - Recent UI/UX overhaul (v1.9.5) + - Keyboard shortcuts system (v1.7.0) + - Medicine and dose tracking improvements + - Migration notes and future roadmap ## 🚀 Quick Navigation ### Getting Started 1. **Installation**: See [README.md - Installation](../README.md#installation) 2. **First Run**: See [README.md - Running the Application](../README.md#running-the-application) -3. **Key Features**: See [FEATURES.md](FEATURES.md) +3. **UI/UX Features**: See [FEATURES.md - Modern UI/UX System](FEATURES.md#-modern-uiux-system-new-in-v195) + +### Using the Application +1. **Theme Selection**: See [FEATURES.md - Settings and Theme Management](FEATURES.md#️-settings-and-theme-management) +2. **Keyboard Shortcuts**: See [KEYBOARD_SHORTCUTS.md](KEYBOARD_SHORTCUTS.md) +3. **Medicine Management**: See [FEATURES.md - Modular Medicine System](FEATURES.md#-modular-medicine-system) +4. **Dose Tracking**: See [FEATURES.md - Advanced Dose Tracking](FEATURES.md#-advanced-dose-tracking) +5. **Data Export**: See [EXPORT_SYSTEM.md](EXPORT_SYSTEM.md) ### Development 1. **Setup**: See [DEVELOPMENT.md - Development Environment Setup](DEVELOPMENT.md#development-environment-setup) 2. **Testing**: See [DEVELOPMENT.md - Testing Framework](DEVELOPMENT.md#testing-framework) -3. **Contributing**: See [DEVELOPMENT.md - Development Workflow](DEVELOPMENT.md#development-workflow) +3. **Architecture**: See [FEATURES.md - Technical Architecture](FEATURES.md#technical-architecture) +4. **Contributing**: See [DEVELOPMENT.md - Development Workflow](DEVELOPMENT.md#development-workflow) -### Advanced Usage -1. **Medicine Management**: See [FEATURES.md - Modular Medicine System](FEATURES.md#-modular-medicine-system) -2. **Dose Tracking**: See [FEATURES.md - Advanced Dose Tracking](FEATURES.md#-advanced-dose-tracking) -3. **Visualizations**: See [FEATURES.md - Enhanced Graph Visualization](FEATURES.md#-enhanced-graph-visualization) +## 📋 What's New in Documentation -## 📋 Documentation Standards +### Recent Updates (v1.9.5) +- **Consolidated Structure**: Merged UI improvements into main features documentation +- **Enhanced Features Guide**: Added comprehensive UI/UX documentation +- **Updated Changelog**: Detailed UI/UX overhaul documentation +- **Improved Navigation**: Better cross-referencing between documents -All documentation follows these principles: -- **Clear Structure**: Hierarchical organization with clear headings -- **Practical Examples**: Code snippets and usage examples -- **Up-to-date**: Synchronized with current codebase -- **Comprehensive**: Covers all major features and workflows -- **Cross-referenced**: Links between related sections +### Documentation Highlights +- **Professional UI/UX**: Complete documentation of the new theme system +- **Keyboard Efficiency**: Comprehensive shortcut system documentation +- **Developer-Friendly**: Enhanced development and testing documentation +- **User-Focused**: Clear separation of user vs developer documentation ## 🔍 Finding Information ### By Topic - **Installation & Setup** → [README.md](../README.md) +- **UI/UX and Themes** → [FEATURES.md - Modern UI/UX System](FEATURES.md#-modern-uiux-system-new-in-v195) - **Feature Usage** → [FEATURES.md](FEATURES.md) +- **Keyboard Shortcuts** → [KEYBOARD_SHORTCUTS.md](KEYBOARD_SHORTCUTS.md) +- **Data Export** → [EXPORT_SYSTEM.md](EXPORT_SYSTEM.md) - **Development** → [DEVELOPMENT.md](DEVELOPMENT.md) - **Version History** → [CHANGELOG.md](CHANGELOG.md) ### By User Type - **End Users** → Start with [README.md](../README.md), then [FEATURES.md](FEATURES.md) -- **Developers** → [DEVELOPMENT.md](DEVELOPMENT.md) and [CHANGELOG.md](CHANGELOG.md) +- **Power Users** → [KEYBOARD_SHORTCUTS.md](KEYBOARD_SHORTCUTS.md) and [EXPORT_SYSTEM.md](EXPORT_SYSTEM.md) +- **Developers** → [DEVELOPMENT.md](DEVELOPMENT.md) and [FEATURES.md - Technical Architecture](FEATURES.md#technical-architecture) - **Contributors** → All documentation, especially [DEVELOPMENT.md](DEVELOPMENT.md) ### By Task - **Install TheChart** → [README.md - Installation](../README.md#installation) +- **Change Theme** → [FEATURES.md - Settings and Theme Management](FEATURES.md#️-settings-and-theme-management) +- **Learn Shortcuts** → [KEYBOARD_SHORTCUTS.md](KEYBOARD_SHORTCUTS.md) - **Add New Medicine** → [FEATURES.md - Modular Medicine System](FEATURES.md#-modular-medicine-system) - **Track Doses** → [FEATURES.md - Advanced Dose Tracking](FEATURES.md#-advanced-dose-tracking) +- **Export Data** → [EXPORT_SYSTEM.md](EXPORT_SYSTEM.md) - **Run Tests** → [DEVELOPMENT.md - Testing Framework](DEVELOPMENT.md#testing-framework) - **Deploy Application** → [README.md - Deployment](../README.md#deployment) diff --git a/pyproject.toml b/pyproject.toml index 58d90a7..b30f81e 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -12,6 +12,7 @@ dependencies = [ "pandas>=2.3.1", "reportlab>=4.4.3", "tk>=0.1.0", + "ttkthemes>=3.2.2", ] [dependency-groups] diff --git a/requirements.in b/requirements.in index 7fdeb24..ad07daf 100644 --- a/requirements.in +++ b/requirements.in @@ -3,3 +3,4 @@ matplotlib pandas dotenv colorlog +ttkthemes diff --git a/requirements.txt b/requirements.txt index 50c70e2..ba48d93 100644 --- a/requirements.txt +++ b/requirements.txt @@ -24,7 +24,9 @@ packaging==25.0 pandas==2.3.1 # via -r requirements.in pillow==11.3.0 - # via matplotlib + # via + # matplotlib + # ttkthemes pyparsing==3.2.3 # via matplotlib python-dateutil==2.9.0.post0 @@ -39,5 +41,7 @@ six==1.17.0 # via python-dateutil tk==0.1.0 # via -r requirements.in +ttkthemes==3.2.2 + # via -r requirements.in tzdata==2025.2 # via pandas diff --git a/src/main.py b/src/main.py index 8c9d72a..071604f 100644 --- a/src/main.py +++ b/src/main.py @@ -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("", lambda e: self._delete_selected_entry()) self.root.bind("", lambda e: self._clear_selection()) self.root.bind("", lambda e: self._show_keyboard_shortcuts()) + self.root.bind("", 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 diff --git a/src/settings_window.py b/src/settings_window.py new file mode 100644 index 0000000..a2cbcee --- /dev/null +++ b/src/settings_window.py @@ -0,0 +1,324 @@ +"""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() diff --git a/src/theme_manager.py b/src/theme_manager.py new file mode 100644 index 0000000..e91a911 --- /dev/null +++ b/src/theme_manager.py @@ -0,0 +1,298 @@ +"""Theme manager for the application using ttkthemes.""" + +import logging +import tkinter as tk +from tkinter import ttk + +from ttkthemes import ThemedStyle + + +class ThemeManager: + """Manages application themes and styling.""" + + def __init__(self, root: tk.Tk, logger: logging.Logger) -> None: + self.root = root + self.logger = logger + self.style: ThemedStyle | None = None + self.current_theme: str = "arc" # Default theme + + # Available themes - these are some of the best looking ones + self.available_themes = [ + "arc", + "equilux", + "adapta", + "yaru", + "ubuntu", + "plastik", + "breeze", + "elegance", + ] + + self.initialize_theme() + + def initialize_theme(self) -> None: + """Initialize the themed style.""" + try: + self.style = ThemedStyle(self.root) + self.apply_theme(self.current_theme) + self._configure_custom_styles() + self.logger.info( + f"Theme manager initialized with theme: {self.current_theme}" + ) + except Exception as e: + self.logger.error(f"Failed to initialize theme manager: {e}") + # Fallback to default ttk styling + self.style = ttk.Style() + + def apply_theme(self, theme_name: str) -> bool: + """Apply a specific theme.""" + try: + if self.style and theme_name in self.get_available_themes(): + self.style.set_theme(theme_name) + self.current_theme = theme_name + self._configure_custom_styles() + self.logger.info(f"Applied theme: {theme_name}") + return True + else: + self.logger.warning(f"Theme '{theme_name}' not available") + return False + except Exception as e: + self.logger.error(f"Failed to apply theme '{theme_name}': {e}") + return False + + def get_available_themes(self) -> list[str]: + """Get list of available themes.""" + if self.style: + try: + # Get all available themes from ttkthemes + all_themes = self.style.theme_names() + # Filter to only include our curated list + return [theme for theme in self.available_themes if theme in all_themes] + except Exception as e: + self.logger.error(f"Failed to get available themes: {e}") + return self.available_themes + return self.available_themes + + def get_current_theme(self) -> str: + """Get the currently active theme.""" + return self.current_theme + + def _configure_custom_styles(self) -> None: + """Configure custom styles for better appearance.""" + if not self.style: + return + + try: + # Get current theme colors for consistent styling + colors = self.get_theme_colors() + + # Configure frame styles with better padding and borders + self.style.configure( + "Card.TFrame", + relief="flat", + borderwidth=0, + background=colors["bg"], + ) + + # Configure label frame styles with modern appearance + self.style.configure( + "Card.TLabelframe", + relief="solid", + borderwidth=1, + background=colors["bg"], + foreground=colors["fg"], + padding=(10, 5, 10, 10), + ) + + self.style.configure( + "Card.TLabelframe.Label", + background=colors["bg"], + foreground=colors["fg"], + font=("TkDefaultFont", 10, "bold"), + ) + + # Configure button styles for better appearance + self.style.configure( + "Action.TButton", + padding=(15, 8), + font=("TkDefaultFont", 9, "normal"), + ) + + # Configure entry styles with modern look + self.style.configure( + "Modern.TEntry", + padding=(8, 5), + borderwidth=1, + relief="solid", + ) + + # Configure scale styles for pathology inputs + self.style.configure( + "Modern.Horizontal.TScale", + borderwidth=0, + background=colors["bg"], + troughcolor="#e0e0e0", + lightcolor=colors["select_bg"], + darkcolor=colors["select_bg"], + focuscolor=colors["select_bg"], + ) + + # Configure treeview for better data display + self.style.configure( + "Modern.Treeview", + rowheight=28, + borderwidth=1, + relief="solid", + background=colors["bg"], + foreground=colors["fg"], + fieldbackground=colors["bg"], + selectbackground=colors["select_bg"], + selectforeground=colors["select_fg"], + ) + + self.style.configure( + "Modern.Treeview.Heading", + padding=(8, 6), + relief="flat", + borderwidth=1, + background=colors["select_bg"], + foreground=colors["select_fg"], + font=("TkDefaultFont", 9, "bold"), + ) + + # Configure comprehensive row selection colors for better visibility + self.style.map( + "Modern.Treeview", + background=[ + ("selected", colors["select_bg"]), + ("active", colors["select_bg"]), + ("focus", colors["select_bg"]), + ("", colors["bg"]), + ], + foreground=[ + ("selected", colors["select_fg"]), + ("active", colors["select_fg"]), + ("focus", colors["select_fg"]), + ("", colors["fg"]), + ], + selectbackground=[ + ("focus", colors["select_bg"]), + ("", colors["select_bg"]), + ], + selectforeground=[ + ("focus", colors["select_fg"]), + ("", colors["select_fg"]), + ], + ) + + # Configure notebook tabs with modern styling + self.style.configure( + "Modern.TNotebook.Tab", + padding=(15, 8), + borderwidth=1, + relief="flat", + ) + + self.style.map( + "Modern.TNotebook.Tab", + background=[("selected", colors["select_bg"])], + foreground=[("selected", colors["select_fg"])], + ) + + # Configure checkbutton for medicine selection + self.style.configure( + "Modern.TCheckbutton", + padding=(8, 4), + background=colors["bg"], + foreground=colors["fg"], + focuscolor=colors["select_bg"], + ) + + self.logger.debug("Enhanced custom styles configured") + + except Exception as e: + self.logger.error(f"Failed to configure custom styles: {e}") + + def configure_widget_style(self, widget: tk.Widget, style_name: str) -> None: + """Apply a specific style to a widget.""" + try: + if hasattr(widget, "configure") and self.style: + widget.configure(style=style_name) + except Exception as e: + self.logger.error(f"Failed to configure widget style '{style_name}': {e}") + + def get_theme_colors(self) -> dict[str, str]: + """Get current theme colors for custom widgets.""" + if not self.style: + return { + "bg": "#ffffff", + "fg": "#000000", + "select_bg": "#3584e4", + "select_fg": "#ffffff", + "alt_bg": "#f5f5f5", + } + + try: + # Get colors from current theme + bg = self.style.lookup("TFrame", "background") or "#ffffff" + fg = self.style.lookup("TLabel", "foreground") or "#000000" + + # Try to get better selection colors from different widget states + select_bg = ( + self.style.lookup("TButton", "background", ["pressed"]) + or self.style.lookup("TButton", "background", ["active"]) + or self.style.lookup("Treeview", "selectbackground") + or "#0078d4" # Modern blue fallback + ) + select_fg = ( + self.style.lookup("TButton", "foreground", ["pressed"]) + or self.style.lookup("TButton", "foreground", ["active"]) + or self.style.lookup("Treeview", "selectforeground") + or "#ffffff" # White fallback + ) + + # Ensure contrast - if selection colors are too similar to background, + # use fallbacks + if select_bg == bg or select_bg.lower() == bg.lower(): + select_bg = "#0078d4" if bg != "#0078d4" else "#0066cc" + + if select_fg == fg or select_fg.lower() == fg.lower(): + select_fg = "#ffffff" if fg != "#ffffff" else "#000000" + + # Calculate alternating row color + if bg.startswith("#"): + try: + rgb = tuple(int(bg[i : i + 2], 16) for i in (1, 3, 5)) + if sum(rgb) > 384: # Light theme + alt_bg = ( + f"#{max(0, rgb[0] - 10):02x}" + f"{max(0, rgb[1] - 10):02x}" + f"{max(0, rgb[2] - 10):02x}" + ) + else: # Dark theme + alt_bg = ( + f"#{min(255, rgb[0] + 10):02x}" + f"{min(255, rgb[1] + 10):02x}" + f"{min(255, rgb[2] + 10):02x}" + ) + except ValueError: + alt_bg = "#f5f5f5" + else: + alt_bg = "#f5f5f5" + + return { + "bg": bg, + "fg": fg, + "select_bg": select_bg, + "select_fg": select_fg, + "alt_bg": alt_bg, # Add alternating background color + } + except Exception as e: + self.logger.error(f"Failed to get theme colors: {e}") + return { + "bg": "#ffffff", + "fg": "#000000", + "select_bg": "#3584e4", + "select_fg": "#ffffff", + "alt_bg": "#f5f5f5", + } diff --git a/src/tooltip_system.py b/src/tooltip_system.py new file mode 100644 index 0000000..4dec2a4 --- /dev/null +++ b/src/tooltip_system.py @@ -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("", self._on_enter) + self.widget.bind("", self._on_leave) + self.widget.bind("", 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) diff --git a/src/ui_manager.py b/src/ui_manager.py index 6649801..9f0a871 100644 --- a/src/ui_manager.py +++ b/src/ui_manager.py @@ -11,6 +11,7 @@ from PIL import Image, ImageTk from medicine_manager import MedicineManager from pathology_manager import PathologyManager +from tooltip_system import TooltipManager class UIManager: @@ -22,17 +23,22 @@ class UIManager: logger: logging.Logger, medicine_manager: MedicineManager, pathology_manager: PathologyManager, + theme_manager, # Import would create circular dependency ) -> None: self.root: tk.Tk = root self.logger: logging.Logger = logger self.medicine_manager = medicine_manager self.pathology_manager = pathology_manager + self.theme_manager = theme_manager # Status bar attributes self.status_bar: tk.Frame | None = None self.status_label: tk.Label | None = None self.file_info_label: tk.Label | None = None + # Initialize tooltip manager + self.tooltip_manager = TooltipManager(theme_manager) + def setup_application_icon(self, img_path: str) -> bool: """Set up the application icon.""" try: @@ -70,13 +76,20 @@ class UIManager: def create_input_frame(self, parent_frame: ttk.Frame) -> dict[str, Any]: """Create and configure the input frame with all widgets.""" # Create main container for the scrollable input frame - main_container = ttk.LabelFrame(parent_frame, text="New Entry") + main_container = ttk.LabelFrame( + parent_frame, text="New Entry", style="Card.TLabelframe" + ) main_container.grid(row=1, column=0, padx=10, pady=10, sticky="nsew") main_container.grid_rowconfigure(0, weight=1) main_container.grid_columnconfigure(0, weight=1) # Create canvas and scrollbar for scrolling - canvas = tk.Canvas(main_container, highlightthickness=0) + theme_colors = self.theme_manager.get_theme_colors() + canvas = tk.Canvas( + main_container, + highlightthickness=0, + bg=theme_colors["bg"], + ) scrollbar = ttk.Scrollbar( main_container, orient="vertical", command=canvas.yview ) @@ -164,7 +177,9 @@ class UIManager: ttk.Label(input_frame, text="Treatment:").grid( row=medicine_row, column=0, sticky="w", padx=5, pady=2 ) - medicine_frame = ttk.LabelFrame(input_frame, text="Medicine") + medicine_frame = ttk.LabelFrame( + input_frame, text="Medicine", style="Card.TLabelframe" + ) medicine_frame.grid(row=medicine_row, column=1, padx=0, pady=10, sticky="nsew") medicine_frame.grid_columnconfigure(0, weight=1) @@ -178,11 +193,19 @@ class UIManager: text = f"{medicine.display_name} {medicine.dosage_info}" medicine_vars[medicine_key] = (var, text) - for idx, (_med_name, (var, text)) in enumerate(medicine_vars.items()): + for idx, (med_key, (var, text)) in enumerate(medicine_vars.items()): # Just checkbox for medicine taken - ttk.Checkbutton(medicine_frame, text=text, variable=var).grid( - row=idx, column=0, sticky="w", padx=5, pady=2 + checkbox = ttk.Checkbutton( + medicine_frame, text=text, variable=var, style="Modern.TCheckbutton" ) + checkbox.grid(row=idx, column=0, sticky="w", padx=5, pady=2) + + # Add tooltip for medicine checkbox + medicine = self.medicine_manager.get_medicine(med_key) + if medicine: + self.tooltip_manager.add_medicine_tooltip( + checkbox, medicine.display_name + ) # Note and Date fields - adjust row numbers note_row = medicine_row + 1 @@ -194,16 +217,19 @@ class UIManager: ttk.Label(input_frame, text="Note:").grid( row=note_row, column=0, sticky="w", padx=5, pady=2 ) - ttk.Entry(input_frame, textvariable=note_var).grid( + ttk.Entry(input_frame, textvariable=note_var, style="Modern.TEntry").grid( row=note_row, column=1, sticky="ew", padx=5, pady=2 ) ttk.Label(input_frame, text="Date (mm/dd/yyyy):").grid( row=date_row, column=0, sticky="w", padx=5, pady=2 ) - ttk.Entry(input_frame, textvariable=date_var, justify="center").grid( - row=date_row, column=1, sticky="ew", padx=5, pady=2 - ) + ttk.Entry( + input_frame, + textvariable=date_var, + justify="center", + style="Modern.TEntry", + ).grid(row=date_row, column=1, sticky="ew", padx=5, pady=2) # Set default date to today date_var.set(datetime.now().strftime("%m/%d/%Y")) @@ -225,7 +251,7 @@ class UIManager: def create_table_frame(self, parent_frame: ttk.Frame) -> dict[str, Any]: """Create and configure the table frame with a treeview.""" table_frame: ttk.LabelFrame = ttk.LabelFrame( - parent_frame, text="Log (Double-click to edit)" + parent_frame, text="Log (Double-click to edit)", style="Card.TLabelframe" ) table_frame.grid(row=1, column=1, padx=10, pady=10, sticky="nsew") @@ -258,7 +284,34 @@ class UIManager: col_labels.append("Note") col_settings.append(("Note", 300, "w")) - tree: ttk.Treeview = ttk.Treeview(table_frame, columns=columns, show="headings") + tree: ttk.Treeview = ttk.Treeview( + table_frame, columns=columns, show="headings", style="Modern.Treeview" + ) + + # Configure treeview selection behavior + tree.configure(selectmode="browse") # Single selection mode + + # Configure row tags for alternating colors + theme_colors = self.theme_manager.get_theme_colors() + tree.tag_configure("evenrow", background=theme_colors["bg"]) + tree.tag_configure("oddrow", background=theme_colors["alt_bg"]) + + # Configure selection highlighting + tree.tag_configure( + "selected", + background=theme_colors["select_bg"], + foreground=theme_colors["select_fg"], + ) + + # Bind selection events to ensure proper highlighting + def on_selection_change(event): + """Handle treeview selection changes to ensure proper highlighting.""" + selection = tree.selection() + if selection: + # Force focus to ensure selection is visible + tree.focus(selection[0]) + + tree.bind("<>", on_selection_change) for col, label in zip(columns, col_labels, strict=False): tree.heading(col, text=label) @@ -277,7 +330,9 @@ class UIManager: def create_graph_frame(self, parent_frame: ttk.Frame) -> ttk.LabelFrame: """Create and configure the graph frame.""" - graph_frame: ttk.LabelFrame = ttk.LabelFrame(parent_frame, text="Evolution") + graph_frame: ttk.LabelFrame = ttk.LabelFrame( + parent_frame, text="Evolution", style="Card.TLabelframe" + ) graph_frame.grid(row=0, column=0, columnspan=2, padx=10, pady=10, sticky="nsew") return graph_frame @@ -289,23 +344,40 @@ class UIManager: button_frame.grid(row=7, column=0, columnspan=2, pady=10) for btn_config in buttons_config: - ttk.Button( + button = ttk.Button( button_frame, text=btn_config["text"], command=btn_config["command"], - ).pack( + style="Action.TButton", + ) + button.pack( side="left", padx=5, fill=btn_config.get("fill", None), expand=btn_config.get("expand", False), ) + # Add tooltips based on button text + button_text = btn_config["text"].lower() + if "add" in button_text or "save" in button_text: + self.tooltip_manager.add_button_tooltip(button, "save") + elif "quit" in button_text or "exit" in button_text: + self.tooltip_manager.add_button_tooltip(button, "quit") + return button_frame def create_status_bar(self, parent_frame: tk.Widget) -> tk.Frame: """Create and configure the status bar at the bottom of the application.""" + # Get theme colors for consistent styling + theme_colors = self.theme_manager.get_theme_colors() + # Create the status bar frame - self.status_bar = tk.Frame(parent_frame, relief=tk.SUNKEN, bd=1) + self.status_bar = tk.Frame( + parent_frame, + relief=tk.SUNKEN, + bd=1, + bg=theme_colors["bg"], + ) self.status_bar.grid(row=2, column=0, columnspan=2, sticky="ew", padx=5, pady=2) # Configure the parent to make the status bar stretch @@ -319,6 +391,8 @@ class UIManager: font=("TkDefaultFont", 9), padx=10, pady=2, + bg=theme_colors["bg"], + fg=theme_colors["fg"], ) self.status_label.pack(side=tk.LEFT, fill=tk.X, expand=True) @@ -330,6 +404,8 @@ class UIManager: font=("TkDefaultFont", 9), padx=10, pady=2, + bg=theme_colors["bg"], + fg=theme_colors["fg"], ) self.file_info_label.pack(side=tk.RIGHT) @@ -793,9 +869,15 @@ class UIManager: variable=vars_dict[key], orient=tk.HORIZONTAL, length=250, + style="Modern.Horizontal.TScale", ) scale.grid(row=0, column=1, sticky="ew") + # Add tooltip for the scale + pathology = self.pathology_manager.get_pathology(key) + if pathology: + self.tooltip_manager.add_scale_tooltip(scale, pathology.display_name) + # Scale labels labels_frame = ttk.Frame(scale_container) labels_frame.grid(row=1, column=0, sticky="ew", pady=(5, 0)) diff --git a/uv.lock b/uv.lock index 0c204c5..5ff29c2 100644 --- a/uv.lock +++ b/uv.lock @@ -1,5 +1,5 @@ version = 1 -revision = 2 +revision = 3 requires-python = ">=3.13" [[package]] @@ -767,6 +767,7 @@ dependencies = [ { name = "pandas" }, { name = "reportlab" }, { name = "tk" }, + { name = "ttkthemes" }, ] [package.dev-dependencies] @@ -789,6 +790,7 @@ requires-dist = [ { name = "pandas", specifier = ">=2.3.1" }, { name = "reportlab", specifier = ">=4.4.3" }, { name = "tk", specifier = ">=0.1.0" }, + { name = "ttkthemes", specifier = ">=3.2.2" }, ] [package.metadata.requires-dev] @@ -811,6 +813,15 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/1e/0b/029cbdb868bb555fed99bf6540fff072d500b3f895873709f25084e85e33/tk-0.1.0-py3-none-any.whl", hash = "sha256:703a69ff0d5ba2bd2f7440582ad10160e4a6561595d33457dc6caa79b9bf4930", size = 3879, upload-time = "2019-07-08T06:51:55.175Z" }, ] +[[package]] +name = "ttkthemes" +version = "3.2.2" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "pillow" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/fa/45/ab8ada55281af99a03bc0f8be53a502eb37ee34b94819a9ced89e8b0c12f/ttkthemes-3.2.2.tar.gz", hash = "sha256:01daed001f2ff0e4f32832a0d9ea48176c0c505203b030756bdde3bd1bcb21d2", size = 891159, upload-time = "2021-02-15T12:57:14.719Z" } + [[package]] name = "tzdata" version = "2025.2"