Enhance Dashboard GUI with full screen and responsive design features

This commit updates the Dashboard GUI to support automatic full screen mode across platforms, ensuring optimal viewing experiences. It introduces a responsive layout that dynamically adjusts components during window resizing, improving usability. Additionally, typography has been enhanced with larger fonts for better readability. The README has been updated to reflect these new features, emphasizing the unified dashboard's capabilities and user experience improvements.
This commit is contained in:
tanyar09 2025-10-10 11:11:58 -04:00
parent de23fccf6a
commit e5ec0e4aea
3 changed files with 258 additions and 103 deletions

View File

@ -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
---

View File

@ -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('<Configure>', 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("<Enter>", show_tooltip)
widget.bind("<Leave>", 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

View File

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