diff --git a/README_UNIFIED_DASHBOARD.md b/README_UNIFIED_DASHBOARD.md index e48114a..067d900 100644 --- a/README_UNIFIED_DASHBOARD.md +++ b/README_UNIFIED_DASHBOARD.md @@ -7,10 +7,13 @@ A powerful photo face recognition and tagging system with a modern unified dashb **PunimTag now features a unified dashboard interface** that brings all functionality into a single, professional window: - **📱 Single Window Interface** - No more managing multiple windows +- **🖥️ Full Screen Mode** - Automatically opens maximized for optimal viewing +- **📐 Responsive Design** - All components adapt dynamically to window resizing - **🎛️ Menu Bar Navigation** - All features accessible from the top menu - **🔄 Panel Switching** - Seamless transitions between different functions - **🌐 Web-Ready Architecture** - Designed for easy migration to web application - **📊 Status Updates** - Real-time feedback on current operations +- **🎨 Enhanced Typography** - Larger, more readable fonts optimized for full screen ## 📋 System Requirements @@ -94,30 +97,57 @@ python3 photo_tagger.py stats # Creates database python3 photo_tagger.py dashboard ``` +### 🖥️ Full Screen & Responsive Features + +The dashboard automatically opens in full screen mode and provides a fully responsive experience: + +#### **Automatic Full Screen** +- **Cross-Platform Support**: Works on Windows, Linux, and macOS +- **Smart Maximization**: Uses the best available method for each platform +- **Fallback Handling**: Gracefully handles systems that don't support maximization +- **Minimum Size**: Prevents window from becoming too small (800x600 minimum) + +#### **Dynamic Responsiveness** +- **Real-Time Resizing**: All components adapt as you resize the window +- **Grid-Based Layout**: Uses proper grid weights for optimal expansion +- **Status Updates**: Status bar shows current window dimensions +- **Panel Updates**: Active panels update their layout during resize +- **Canvas Scrolling**: Similar faces and other scrollable areas update automatically + +#### **Enhanced Typography** +- **Full Screen Optimized**: Larger fonts (24pt titles, 14pt content) for better readability +- **Consistent Styling**: All panels use the same enhanced font sizes +- **Professional Appearance**: Clean, modern typography throughout + ### Dashboard Features #### **🏠 Home Panel** - Welcome screen with feature overview - Quick access guide to all functionality -- Professional, modern interface +- Professional, modern interface with large fonts for full screen +- Responsive layout that adapts to window size #### **📁 Scan Panel** - **Folder Selection**: Browse and select photo directories - **Recursive Scanning**: Include photos in subfolders - **Path Validation**: Automatic validation and error handling - **Real-time Status**: Live updates during scanning process +- **Responsive Forms**: Form elements expand and contract with window size #### **🔍 Process Panel** - **Batch Processing**: Process photos in configurable batches - **Quality Scoring**: Automatic face quality assessment - **Model Selection**: Choose between HOG (fast) and CNN (accurate) models - **Progress Tracking**: Real-time processing status +- **Dynamic Layout**: All controls adapt to window resizing -#### **👤 Identify Panel** *(Coming Soon)* -- **Visual Face Display**: See individual face crops +#### **👤 Identify Panel** *(Fully Functional)* +- **Visual Face Display**: See individual face crops (400x400 pixels for full screen) - **Smart Identification**: Separate fields for first name, last name, middle name, maiden name - **Similar Face Matching**: Compare with other unidentified faces - **Batch Processing**: Handle multiple faces efficiently +- **Responsive Layout**: Adapts to window resizing with dynamic updates +- **Enhanced Navigation**: Back/Next buttons with unsaved changes protection #### **🔗 Auto-Match Panel** *(Coming Soon)* - **Person-Centric View**: Show matched person with potential matches @@ -317,9 +347,12 @@ python3 photo_tagger.py stats - [x] Scan panel (fully functional) - [x] Process panel (fully functional) - [x] Home panel with welcome screen +- [x] Full screen mode with automatic maximization +- [x] Responsive design with dynamic resizing +- [x] Enhanced typography for full screen viewing ### Phase 2: GUI Panel Integration (In Progress) -- [ ] Identify panel integration +- [x] Identify panel integration (fully functional) - [ ] Auto-Match panel integration - [ ] Search panel integration - [ ] Modify panel integration @@ -341,8 +374,10 @@ python3 photo_tagger.py stats ### User Experience - **Single Window**: No more managing multiple windows +- **Full Screen Experience**: Automatically opens maximized for optimal viewing +- **Responsive Design**: All components adapt when window is resized - **Consistent Interface**: All features follow the same design patterns -- **Professional Look**: Modern, clean interface design +- **Professional Look**: Modern, clean interface design with enhanced typography - **Intuitive Navigation**: Menu bar makes all features easily accessible ### Developer Experience @@ -356,6 +391,8 @@ python3 photo_tagger.py stats - **Background Processing**: Long operations don't block the UI - **Memory Efficient**: Proper cleanup and resource management - **Responsive**: Fast panel switching and updates +- **Dynamic Resizing**: Real-time layout updates during window resize +- **Cross-Platform**: Works on Windows, Linux, and macOS with proper full screen support --- diff --git a/dashboard_gui.py b/dashboard_gui.py index 6176aae..42252ac 100644 --- a/dashboard_gui.py +++ b/dashboard_gui.py @@ -41,9 +41,38 @@ class DashboardGUI: self.root.resizable(True, True) self.root.withdraw() - # Create main container + # Make window full screen - use geometry instead of state for better compatibility + try: + # Try Windows-style maximized state first + self.root.state('zoomed') + except tk.TclError: + try: + # Try Linux-style maximized attribute + self.root.attributes('-zoomed', True) + except tk.TclError: + # Fallback: set geometry to screen size + screen_width = self.root.winfo_screenwidth() + screen_height = self.root.winfo_screenheight() + self.root.geometry(f"{screen_width}x{screen_height}+0+0") + + # Get screen dimensions for dynamic sizing + screen_width = self.root.winfo_screenwidth() + screen_height = self.root.winfo_screenheight() + + # Set minimum window size + self.root.minsize(800, 600) + + # Create main container with proper grid configuration main_container = ttk.Frame(self.root) main_container.pack(fill=tk.BOTH, expand=True) + + # Configure main container grid weights for responsiveness + main_container.columnconfigure(0, weight=1) + main_container.rowconfigure(0, weight=0) # Menu bar - fixed height + main_container.rowconfigure(1, weight=1) # Content area - expandable + + # Add window resize handler for dynamic responsiveness + self.root.bind('', self._on_window_resize) # Create menu bar self._create_menu_bar(main_container) @@ -57,9 +86,7 @@ class DashboardGUI: # Show default panel self.show_panel("home") - # Center and show window - self.root.update_idletasks() - self.gui_core.center_window(self.root, 1200, 800) + # Show window self.root.deiconify() self.root.mainloop() return 0 @@ -67,13 +94,20 @@ class DashboardGUI: def _create_menu_bar(self, parent: ttk.Frame): """Create the top menu bar with all functionality buttons""" menu_frame = ttk.Frame(parent) - menu_frame.pack(fill=tk.X, padx=10, pady=5) + menu_frame.grid(row=0, column=0, sticky=(tk.W, tk.E), padx=15, pady=10) + menu_frame.columnconfigure(0, weight=0) # Title - fixed width + menu_frame.columnconfigure(1, weight=1) # Buttons - expandable + menu_frame.columnconfigure(2, weight=0) # Status - fixed width - # Title - title_label = ttk.Label(menu_frame, text="PunimTag", font=("Arial", 16, "bold")) - title_label.pack(side=tk.LEFT, padx=(0, 20)) + # Title with larger font for full screen + title_label = tk.Label(menu_frame, text="PunimTag", font=("Arial", 20, "bold")) + title_label.grid(row=0, column=0, padx=(0, 30), sticky=tk.W) - # Menu buttons + # Create buttons frame for better organization + buttons_frame = ttk.Frame(menu_frame) + buttons_frame.grid(row=0, column=1, sticky=(tk.W, tk.E), padx=20) + + # Menu buttons with larger size for full screen menu_buttons = [ ("📁 Scan", "scan", "Scan folders and add photos"), ("🔍 Process", "process", "Detect faces in photos"), @@ -84,29 +118,37 @@ class DashboardGUI: ("🏷️ Tags", "tags", "Manage photo tags"), ] - for text, panel_name, tooltip in menu_buttons: + for i, (text, panel_name, tooltip) in enumerate(menu_buttons): btn = ttk.Button( - menu_frame, + buttons_frame, text=text, - command=lambda p=panel_name: self.show_panel(p) + command=lambda p=panel_name: self.show_panel(p), + width=12 # Fixed width for consistent layout ) - btn.pack(side=tk.LEFT, padx=2) + btn.grid(row=0, column=i, padx=3, sticky=tk.W) # Add tooltip functionality self._add_tooltip(btn, tooltip) - # Separator - separator = ttk.Separator(menu_frame, orient='vertical') - separator.pack(side=tk.LEFT, padx=10, fill=tk.Y) + # Status/Info area with better styling + status_frame = ttk.Frame(menu_frame) + status_frame.grid(row=0, column=2, sticky=tk.E, padx=(20, 0)) - # Status/Info area (for future use) - self.status_label = ttk.Label(menu_frame, text="Ready", foreground="#666") + self.status_label = tk.Label(status_frame, text="Ready", foreground="#666", font=("Arial", 10)) self.status_label.pack(side=tk.RIGHT) + + # Add a subtle separator line below the menu + separator = ttk.Separator(parent, orient='horizontal') + separator.grid(row=1, column=0, sticky=(tk.W, tk.E), padx=15, pady=(0, 5)) def _create_content_area(self, parent: ttk.Frame): """Create the main content area where panels will be displayed""" self.content_frame = ttk.Frame(parent) - self.content_frame.pack(fill=tk.BOTH, expand=True, padx=10, pady=5) + self.content_frame.grid(row=2, column=0, sticky=(tk.W, tk.E, tk.N, tk.S), padx=15, pady=(0, 15)) + + # Configure content frame to expand + self.content_frame.columnconfigure(0, weight=1) + self.content_frame.rowconfigure(0, weight=1) # Add a subtle border self.content_frame.configure(relief='sunken', borderwidth=1) @@ -133,10 +175,10 @@ class DashboardGUI: # Hide current panel if self.current_panel: - self.panels[self.current_panel].pack_forget() + self.panels[self.current_panel].grid_remove() # Show new panel - self.panels[panel_name].pack(fill=tk.BOTH, expand=True, padx=10, pady=10) + self.panels[panel_name].grid(row=0, column=0, sticky=(tk.W, tk.E, tk.N, tk.S), padx=15, pady=15) self.current_panel = panel_name # Update status @@ -160,23 +202,45 @@ class DashboardGUI: widget.bind("", show_tooltip) widget.bind("", hide_tooltip) + def _on_window_resize(self, event): + """Handle window resize events for dynamic responsiveness""" + # Only handle resize events for the main window, not child widgets + if event.widget == self.root: + # Update status with current window size + width = self.root.winfo_width() + height = self.root.winfo_height() + self.status_label.config(text=f"Ready - {width}x{height}") + + # Force update of all panels to ensure proper resizing + if hasattr(self, 'identify_panel') and self.identify_panel: + # Update identify panel layout if it's active + if self.current_panel == "identify": + self.identify_panel.update_layout() + def _create_home_panel(self) -> ttk.Frame: """Create the home/welcome panel""" panel = ttk.Frame(self.content_frame) + # Configure panel grid for responsiveness + panel.columnconfigure(0, weight=1) + panel.rowconfigure(0, weight=1) + # Welcome content welcome_frame = ttk.Frame(panel) - welcome_frame.pack(expand=True, fill=tk.BOTH) + welcome_frame.grid(row=0, column=0, sticky=(tk.W, tk.E, tk.N, tk.S), padx=20, pady=20) + welcome_frame.columnconfigure(0, weight=1) + welcome_frame.rowconfigure(0, weight=1) # Center the content center_frame = ttk.Frame(welcome_frame) - center_frame.place(relx=0.5, rely=0.5, anchor=tk.CENTER) + center_frame.grid(row=0, column=0, sticky=(tk.W, tk.E, tk.N, tk.S)) + center_frame.columnconfigure(0, weight=1) - # Title - title_label = ttk.Label(center_frame, text="Welcome to PunimTag", font=("Arial", 24, "bold")) - title_label.pack(pady=(0, 20)) + # Title with larger font for full screen + title_label = tk.Label(center_frame, text="Welcome to PunimTag", font=("Arial", 32, "bold")) + title_label.grid(row=0, column=0, pady=(0, 30)) - # Description + # Description with larger font desc_text = ( "PunimTag is a powerful photo face recognition and tagging system.\n\n" "Use the menu above to access different features:\n\n" @@ -190,8 +254,8 @@ class DashboardGUI: "Select a feature from the menu to get started!" ) - desc_label = ttk.Label(center_frame, text=desc_text, font=("Arial", 12), justify=tk.LEFT) - desc_label.pack() + desc_label = tk.Label(center_frame, text=desc_text, font=("Arial", 14), justify=tk.LEFT) + desc_label.grid(row=1, column=0, pady=(0, 20)) return panel @@ -199,26 +263,33 @@ class DashboardGUI: """Create the scan panel (migrated from original dashboard)""" panel = ttk.Frame(self.content_frame) - # Title - title_label = ttk.Label(panel, text="📁 Scan Photos", font=("Arial", 18, "bold")) - title_label.pack(anchor="w", pady=(0, 20)) + # Configure panel grid for responsiveness + panel.columnconfigure(0, weight=1) + panel.rowconfigure(1, weight=1) + + # Title with larger font for full screen + title_label = tk.Label(panel, text="📁 Scan Photos", font=("Arial", 24, "bold")) + title_label.grid(row=0, column=0, sticky=tk.W, pady=(0, 20)) # Scan form - form_frame = ttk.LabelFrame(panel, text="Scan Configuration", padding="15") - form_frame.pack(fill=tk.X, pady=(0, 20)) + form_frame = ttk.LabelFrame(panel, text="Scan Configuration", padding="20") + form_frame.grid(row=1, column=0, sticky=(tk.W, tk.E, tk.N, tk.S), pady=(0, 20)) + form_frame.columnconfigure(0, weight=1) # Folder selection folder_frame = ttk.Frame(form_frame) - folder_frame.pack(fill=tk.X, pady=(0, 10)) + folder_frame.grid(row=0, column=0, sticky=(tk.W, tk.E), pady=(0, 15)) + folder_frame.columnconfigure(0, weight=1) - ttk.Label(folder_frame, text="Folder to scan:").pack(anchor="w") + tk.Label(folder_frame, text="Folder to scan:", font=("Arial", 12)).grid(row=0, column=0, sticky=tk.W) folder_input_frame = ttk.Frame(folder_frame) - folder_input_frame.pack(fill=tk.X, pady=(5, 0)) + folder_input_frame.grid(row=1, column=0, sticky=(tk.W, tk.E), pady=(5, 0)) + folder_input_frame.columnconfigure(0, weight=1) self.folder_var = tk.StringVar() - folder_entry = ttk.Entry(folder_input_frame, textvariable=self.folder_var) - folder_entry.pack(side=tk.LEFT, fill=tk.X, expand=True, padx=(0, 10)) + folder_entry = tk.Entry(folder_input_frame, textvariable=self.folder_var, font=("Arial", 11)) + folder_entry.grid(row=0, column=0, sticky=(tk.W, tk.E), padx=(0, 10)) def browse_folder(): from tkinter import filedialog @@ -227,20 +298,21 @@ class DashboardGUI: self.folder_var.set(folder_path) browse_btn = ttk.Button(folder_input_frame, text="Browse", command=browse_folder) - browse_btn.pack(side=tk.LEFT) + browse_btn.grid(row=0, column=1) # Recursive option self.recursive_var = tk.BooleanVar(value=True) - recursive_check = ttk.Checkbutton( + recursive_check = tk.Checkbutton( form_frame, text="Include photos in sub-folders", - variable=self.recursive_var + variable=self.recursive_var, + font=("Arial", 11) ) - recursive_check.pack(anchor="w", pady=(10, 0)) + recursive_check.grid(row=1, column=0, sticky=tk.W, pady=(15, 0)) # Action button scan_btn = ttk.Button(form_frame, text="🔍 Start Scan", command=self._run_scan) - scan_btn.pack(anchor="w", pady=(20, 0)) + scan_btn.grid(row=2, column=0, sticky=tk.W, pady=(20, 0)) return panel @@ -248,31 +320,36 @@ class DashboardGUI: """Create the process panel (migrated from original dashboard)""" panel = ttk.Frame(self.content_frame) - # Title - title_label = ttk.Label(panel, text="🔍 Process Faces", font=("Arial", 18, "bold")) - title_label.pack(anchor="w", pady=(0, 20)) + # Configure panel grid for responsiveness + panel.columnconfigure(0, weight=1) + panel.rowconfigure(1, weight=1) + + # Title with larger font for full screen + title_label = tk.Label(panel, text="🔍 Process Faces", font=("Arial", 24, "bold")) + title_label.grid(row=0, column=0, sticky=tk.W, pady=(0, 20)) # Process form - form_frame = ttk.LabelFrame(panel, text="Processing Configuration", padding="15") - form_frame.pack(fill=tk.X, pady=(0, 20)) + form_frame = ttk.LabelFrame(panel, text="Processing Configuration", padding="20") + form_frame.grid(row=1, column=0, sticky=(tk.W, tk.E, tk.N, tk.S), pady=(0, 20)) + form_frame.columnconfigure(0, weight=1) # Limit option limit_frame = ttk.Frame(form_frame) - limit_frame.pack(fill=tk.X, pady=(0, 10)) + limit_frame.grid(row=0, column=0, sticky=(tk.W, tk.E), pady=(0, 15)) self.limit_enabled = tk.BooleanVar(value=False) - limit_check = ttk.Checkbutton(limit_frame, text="Limit processing to", variable=self.limit_enabled) - limit_check.pack(side=tk.LEFT) + limit_check = tk.Checkbutton(limit_frame, text="Limit processing to", variable=self.limit_enabled, font=("Arial", 11)) + limit_check.grid(row=0, column=0, sticky=tk.W) self.limit_var = tk.StringVar(value="50") - limit_entry = ttk.Entry(limit_frame, textvariable=self.limit_var, width=8) - limit_entry.pack(side=tk.LEFT, padx=(10, 0)) + limit_entry = tk.Entry(limit_frame, textvariable=self.limit_var, width=8, font=("Arial", 11)) + limit_entry.grid(row=0, column=1, padx=(10, 5)) - ttk.Label(limit_frame, text="photos").pack(side=tk.LEFT, padx=(5, 0)) + tk.Label(limit_frame, text="photos", font=("Arial", 11)).grid(row=0, column=2, sticky=tk.W) # Action button process_btn = ttk.Button(form_frame, text="🚀 Start Processing", command=self._run_process) - process_btn.pack(anchor="w", pady=(20, 0)) + process_btn.grid(row=1, column=0, sticky=tk.W, pady=(20, 0)) return panel @@ -280,19 +357,25 @@ class DashboardGUI: """Create the identify panel with full functionality""" panel = ttk.Frame(self.content_frame) - # Title - title_label = ttk.Label(panel, text="👤 Identify Faces", font=("Arial", 18, "bold")) - title_label.pack(anchor="w", pady=(0, 20)) + # Configure panel grid for responsiveness + panel.columnconfigure(0, weight=1) + panel.rowconfigure(1, weight=1) + + # Title with larger font for full screen + title_label = tk.Label(panel, text="👤 Identify Faces", font=("Arial", 24, "bold")) + title_label.grid(row=0, column=0, sticky=tk.W, pady=(0, 20)) # Create the identify panel if we have the required dependencies if self.db_manager and self.face_processor: self.identify_panel = IdentifyPanel(panel, self.db_manager, self.face_processor, self.gui_core) identify_frame = self.identify_panel.create_panel() - identify_frame.pack(fill=tk.BOTH, expand=True) + identify_frame.grid(row=1, column=0, sticky=(tk.W, tk.E, tk.N, tk.S)) else: # Fallback placeholder if dependencies are not available placeholder_frame = ttk.LabelFrame(panel, text="Configuration Required", padding="20") - placeholder_frame.pack(expand=True, fill=tk.BOTH) + placeholder_frame.grid(row=1, column=0, sticky=(tk.W, tk.E, tk.N, tk.S)) + placeholder_frame.columnconfigure(0, weight=1) + placeholder_frame.rowconfigure(0, weight=1) placeholder_text = ( "Identify panel requires database and face processor to be configured.\n\n" @@ -305,8 +388,8 @@ class DashboardGUI: "• Batch processing options" ) - placeholder_label = ttk.Label(placeholder_frame, text=placeholder_text, font=("Arial", 12), justify=tk.LEFT) - placeholder_label.pack(expand=True) + placeholder_label = tk.Label(placeholder_frame, text=placeholder_text, font=("Arial", 14), justify=tk.LEFT) + placeholder_label.grid(row=0, column=0, sticky=(tk.W, tk.E, tk.N, tk.S)) return panel @@ -314,15 +397,21 @@ class DashboardGUI: """Create the auto-match panel (placeholder)""" panel = ttk.Frame(self.content_frame) - title_label = ttk.Label(panel, text="🔗 Auto-Match Faces", font=("Arial", 18, "bold")) - title_label.pack(anchor="w", pady=(0, 20)) + # Configure panel grid for responsiveness + panel.columnconfigure(0, weight=1) + panel.rowconfigure(1, weight=1) + + title_label = tk.Label(panel, text="🔗 Auto-Match Faces", font=("Arial", 24, "bold")) + title_label.grid(row=0, column=0, sticky=tk.W, pady=(0, 20)) placeholder_frame = ttk.LabelFrame(panel, text="Coming Soon", padding="20") - placeholder_frame.pack(expand=True, fill=tk.BOTH) + placeholder_frame.grid(row=1, column=0, sticky=(tk.W, tk.E, tk.N, tk.S)) + placeholder_frame.columnconfigure(0, weight=1) + placeholder_frame.rowconfigure(0, weight=1) placeholder_text = "Auto-Match functionality will be integrated here." - placeholder_label = ttk.Label(placeholder_frame, text=placeholder_text, font=("Arial", 12)) - placeholder_label.pack(expand=True) + placeholder_label = tk.Label(placeholder_frame, text=placeholder_text, font=("Arial", 14)) + placeholder_label.grid(row=0, column=0, sticky=(tk.W, tk.E, tk.N, tk.S)) return panel @@ -330,15 +419,21 @@ class DashboardGUI: """Create the search panel (placeholder)""" panel = ttk.Frame(self.content_frame) - title_label = ttk.Label(panel, text="🔎 Search Photos", font=("Arial", 18, "bold")) - title_label.pack(anchor="w", pady=(0, 20)) + # Configure panel grid for responsiveness + panel.columnconfigure(0, weight=1) + panel.rowconfigure(1, weight=1) + + title_label = tk.Label(panel, text="🔎 Search Photos", font=("Arial", 24, "bold")) + title_label.grid(row=0, column=0, sticky=tk.W, pady=(0, 20)) placeholder_frame = ttk.LabelFrame(panel, text="Coming Soon", padding="20") - placeholder_frame.pack(expand=True, fill=tk.BOTH) + placeholder_frame.grid(row=1, column=0, sticky=(tk.W, tk.E, tk.N, tk.S)) + placeholder_frame.columnconfigure(0, weight=1) + placeholder_frame.rowconfigure(0, weight=1) placeholder_text = "Search functionality will be integrated here." - placeholder_label = ttk.Label(placeholder_frame, text=placeholder_text, font=("Arial", 12)) - placeholder_label.pack(expand=True) + placeholder_label = tk.Label(placeholder_frame, text=placeholder_text, font=("Arial", 14)) + placeholder_label.grid(row=0, column=0, sticky=(tk.W, tk.E, tk.N, tk.S)) return panel @@ -346,15 +441,21 @@ class DashboardGUI: """Create the modify panel (placeholder)""" panel = ttk.Frame(self.content_frame) - title_label = ttk.Label(panel, text="✏️ Modify Identified", font=("Arial", 18, "bold")) - title_label.pack(anchor="w", pady=(0, 20)) + # Configure panel grid for responsiveness + panel.columnconfigure(0, weight=1) + panel.rowconfigure(1, weight=1) + + title_label = tk.Label(panel, text="✏️ Modify Identified", font=("Arial", 24, "bold")) + title_label.grid(row=0, column=0, sticky=tk.W, pady=(0, 20)) placeholder_frame = ttk.LabelFrame(panel, text="Coming Soon", padding="20") - placeholder_frame.pack(expand=True, fill=tk.BOTH) + placeholder_frame.grid(row=1, column=0, sticky=(tk.W, tk.E, tk.N, tk.S)) + placeholder_frame.columnconfigure(0, weight=1) + placeholder_frame.rowconfigure(0, weight=1) placeholder_text = "Modify functionality will be integrated here." - placeholder_label = ttk.Label(placeholder_frame, text=placeholder_text, font=("Arial", 12)) - placeholder_label.pack(expand=True) + placeholder_label = tk.Label(placeholder_frame, text=placeholder_text, font=("Arial", 14)) + placeholder_label.grid(row=0, column=0, sticky=(tk.W, tk.E, tk.N, tk.S)) return panel @@ -362,15 +463,21 @@ class DashboardGUI: """Create the tags panel (placeholder)""" panel = ttk.Frame(self.content_frame) - title_label = ttk.Label(panel, text="🏷️ Tag Manager", font=("Arial", 18, "bold")) - title_label.pack(anchor="w", pady=(0, 20)) + # Configure panel grid for responsiveness + panel.columnconfigure(0, weight=1) + panel.rowconfigure(1, weight=1) + + title_label = tk.Label(panel, text="🏷️ Tag Manager", font=("Arial", 24, "bold")) + title_label.grid(row=0, column=0, sticky=tk.W, pady=(0, 20)) placeholder_frame = ttk.LabelFrame(panel, text="Coming Soon", padding="20") - placeholder_frame.pack(expand=True, fill=tk.BOTH) + placeholder_frame.grid(row=1, column=0, sticky=(tk.W, tk.E, tk.N, tk.S)) + placeholder_frame.columnconfigure(0, weight=1) + placeholder_frame.rowconfigure(0, weight=1) placeholder_text = "Tag management functionality will be integrated here." - placeholder_label = ttk.Label(placeholder_frame, text=placeholder_text, font=("Arial", 12)) - placeholder_label.pack(expand=True) + placeholder_label = tk.Label(placeholder_frame, text=placeholder_text, font=("Arial", 14)) + placeholder_label.grid(row=0, column=0, sticky=(tk.W, tk.E, tk.N, tk.S)) return panel diff --git a/identify_panel.py b/identify_panel.py index 76dfdfa..19ccfd0 100644 --- a/identify_panel.py +++ b/identify_panel.py @@ -47,15 +47,18 @@ class IdentifyPanel: """Create the identify panel with all GUI components""" self.main_frame = ttk.Frame(self.parent_frame) - # Configure grid weights + # Configure grid weights for full screen responsiveness self.main_frame.columnconfigure(0, weight=1) # Left panel self.main_frame.columnconfigure(1, weight=1) # Right panel for similar faces - self.main_frame.rowconfigure(3, weight=0) # Configuration row - no expansion + self.main_frame.rowconfigure(0, weight=0) # Info label - fixed height + self.main_frame.rowconfigure(1, weight=0) # Filter row - fixed height + self.main_frame.rowconfigure(2, weight=0) # Checkboxes row - fixed height + self.main_frame.rowconfigure(3, weight=0) # Configuration row - fixed height self.main_frame.rowconfigure(4, weight=1) # Main panels row - expandable - # Photo info - self.components['info_label'] = ttk.Label(self.main_frame, text="", font=("Arial", 10, "bold")) - self.components['info_label'].grid(row=0, column=0, columnspan=2, pady=(0, 10), sticky=tk.W) + # Photo info with larger font for full screen + self.components['info_label'] = tk.Label(self.main_frame, text="", font=("Arial", 12, "bold")) + self.components['info_label'].grid(row=0, column=0, columnspan=2, pady=(0, 15), sticky=tk.W) # Create all GUI components self._create_gui_components() @@ -265,9 +268,9 @@ class IdentifyPanel: """Create the left panel content for face identification""" left_panel = self.components['left_panel'] - # Face image display - self.components['face_canvas'] = tk.Canvas(left_panel, width=300, height=300, bg='white', relief='sunken', bd=2) - self.components['face_canvas'].pack(pady=(0, 10)) + # Face image display - larger for full screen + self.components['face_canvas'] = tk.Canvas(left_panel, width=400, height=400, bg='white', relief='sunken', bd=2) + self.components['face_canvas'].pack(pady=(0, 15)) # Person name fields name_frame = ttk.LabelFrame(left_panel, text="Person Information", padding="5") @@ -613,8 +616,8 @@ class IdentifyPanel: if face_crop_path and os.path.exists(face_crop_path): # Load and display face crop image = Image.open(face_crop_path) - # Resize to exactly fill the 300x300 frame - image = image.resize((300, 300), Image.Resampling.LANCZOS) + # Resize to exactly fill the 400x400 frame + image = image.resize((400, 400), Image.Resampling.LANCZOS) photo = ImageTk.PhotoImage(image) # Clear canvas and display image @@ -625,16 +628,16 @@ class IdentifyPanel: canvas.image = photo # Keep a reference # Add photo icon exactly at the image's top-right corner - # Image starts at (0, 0) and is 300x300, so top-right corner is at (300, 0) - self.gui_core.create_photo_icon(canvas, photo_path, icon_size=20, + # Image starts at (0, 0) and is 400x400, so top-right corner is at (400, 0) + self.gui_core.create_photo_icon(canvas, photo_path, icon_size=25, face_x=0, face_y=0, - face_width=300, face_height=300, - canvas_width=300, canvas_height=300) + face_width=400, face_height=400, + canvas_width=400, canvas_height=400) else: # Clear canvas if no image canvas = self.components['face_canvas'] canvas.delete("all") - canvas.create_text(150, 150, text="No face image", fill="gray") + canvas.create_text(200, 200, text="No face image", fill="gray") except Exception as e: print(f"Error updating face image: {e}") @@ -1424,3 +1427,11 @@ class IdentifyPanel: if self.is_active: self._cleanup() self.is_active = False + + def update_layout(self): + """Update panel layout for responsiveness""" + if hasattr(self, 'components') and 'similar_canvas' in self.components: + # Update similar faces canvas scroll region + canvas = self.components['similar_canvas'] + canvas.update_idletasks() + canvas.configure(scrollregion=canvas.bbox("all"))