feat: Enhance Identify Panel with responsive face canvas sizing and dynamic updates

This commit introduces a new method `_calculate_face_canvas_size` in the `IdentifyPanel` class to calculate a responsive size for the face canvas based on the available window space. Additionally, the `_update_face_canvas_size` method has been implemented to dynamically adjust the canvas size during window resize events. The dashboard GUI has also been updated to improve layout consistency by fixing the width of the folder input text box. These changes enhance the user experience by ensuring that the face canvas adapts to different screen sizes and resolutions.
This commit is contained in:
tanyar09 2025-10-17 14:43:34 -04:00
parent 4816925a3d
commit f8fefd2983
2 changed files with 117 additions and 14 deletions

View File

@ -1640,12 +1640,12 @@ class DashboardGUI:
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.grid(row=1, column=0, sticky=(tk.W, tk.E), pady=(5, 0))
folder_input_frame.columnconfigure(0, weight=1)
folder_input_frame.grid(row=1, column=0, sticky=tk.W, pady=(5, 0))
# Don't configure column weight since we want fixed-width text box
self.folder_var = tk.StringVar()
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))
folder_entry = tk.Entry(folder_input_frame, textvariable=self.folder_var, font=("Arial", 11), width=50)
folder_entry.grid(row=0, column=0, sticky=tk.W, padx=(0, 10))
def browse_folder():
from tkinter import filedialog
@ -1654,7 +1654,7 @@ class DashboardGUI:
self.folder_var.set(folder_path)
browse_btn = ttk.Button(folder_input_frame, text="Browse", command=browse_folder)
browse_btn.grid(row=0, column=1)
browse_btn.grid(row=0, column=1, sticky=tk.W)
# Recursive option
self.recursive_var = tk.BooleanVar(value=True)

View File

@ -73,6 +73,89 @@ class IdentifyPanel:
return self.main_frame
def _calculate_face_canvas_size(self) -> int:
"""Calculate responsive face canvas size based on available window space"""
try:
# Get the main window to determine available space
root = self.main_frame.winfo_toplevel()
root.update_idletasks() # Ensure geometry is calculated
# Try to get the actual window height first, fall back to screen height
try:
window_height = root.winfo_height()
if window_height <= 1: # Window not yet rendered
window_height = root.winfo_screenheight()
except:
window_height = root.winfo_screenheight()
# Estimate space used by other UI elements (in pixels)
# Title bar + menu: ~80px, filters: ~120px, config: ~60px, form: ~120px, buttons: ~40px, padding: ~40px
used_height = 460
# Calculate available height for face canvas
available_height = window_height - used_height
# Define size constraints
min_size = 200 # Minimum usable size
max_size = 400 # Maximum size (original)
preferred_size = 300 # Good balance for most screens
# Calculate responsive size based on available height
if available_height < 500: # Very small window (laptop with small resolution)
face_size = min_size
elif available_height < 600: # Small laptop screen
face_size = min(max_size, max(min_size, available_height // 2))
elif available_height < 800: # Medium laptop screen
face_size = min(max_size, max(min_size, available_height // 2.5))
else: # Large screen
face_size = preferred_size
# Ensure it's a reasonable size
face_size = max(min_size, min(max_size, int(face_size)))
if self.verbose > 0:
print(f"📐 Window height: {window_height}px, Available: {available_height}px, Face canvas: {face_size}x{face_size}px")
return face_size
except Exception as e:
# Fallback to default size if calculation fails
if self.verbose > 0:
print(f"⚠️ Error calculating face canvas size: {e}, using default 300px")
return 300
def _update_face_canvas_size(self):
"""Update face canvas size dynamically (for window resize events)"""
try:
if 'face_canvas' not in self.components:
return
# Calculate new size
new_size = self._calculate_face_canvas_size()
canvas = self.components['face_canvas']
# Get current size
current_width = canvas.winfo_width()
current_height = canvas.winfo_height()
# Only update if size has changed significantly (avoid constant updates)
if abs(current_width - new_size) > 10 or abs(current_height - new_size) > 10:
# Update canvas size
canvas.configure(width=new_size, height=new_size)
# Refresh the current face image if there's one displayed
if self.current_faces and self.current_face_index < len(self.current_faces):
face_id, photo_id, photo_path, filename, location, face_conf, quality, detector, model = self.current_faces[self.current_face_index]
if self.current_face_crop_path:
self._update_face_image(self.current_face_crop_path, photo_path)
if self.verbose > 0:
print(f"📐 Updated face canvas size to {new_size}x{new_size}px")
except Exception as e:
if self.verbose > 0:
print(f"⚠️ Error updating face canvas size: {e}")
def _create_gui_components(self):
"""Create all GUI components for the identify interface"""
# Create variables for form data
@ -426,8 +509,11 @@ class IdentifyPanel:
main_content_frame = ttk.Frame(left_panel)
main_content_frame.pack(fill=tk.BOTH, expand=True, pady=(0, 10))
# Face image display - flexible height for better layout
self.components['face_canvas'] = tk.Canvas(main_content_frame, width=400, height=400, bg='white', relief='sunken', bd=2)
# Calculate responsive face canvas size based on available space
face_canvas_size = self._calculate_face_canvas_size()
# Face image display - responsive size for better layout on different screens
self.components['face_canvas'] = tk.Canvas(main_content_frame, width=face_canvas_size, height=face_canvas_size, bg='white', relief='sunken', bd=2)
self.components['face_canvas'].pack(pady=(0, 15))
# Person name fields
@ -955,30 +1041,43 @@ class IdentifyPanel:
"""Update the face image display"""
try:
if face_crop_path and os.path.exists(face_crop_path):
# Get current canvas size
canvas = self.components['face_canvas']
canvas_width = canvas.winfo_width()
canvas_height = canvas.winfo_height()
# Use actual canvas size if available, otherwise use configured size
if canvas_width <= 1 or canvas_height <= 1:
# Canvas not yet rendered, use configured size
canvas_width = canvas['width']
canvas_height = canvas['height']
# Load and display face crop
image = Image.open(face_crop_path)
# Resize to exactly fill the 400x400 frame
image = image.resize((400, 400), Image.Resampling.LANCZOS)
# Resize to exactly fill the current canvas frame
image = image.resize((canvas_width, canvas_height), Image.Resampling.LANCZOS)
photo = ImageTk.PhotoImage(image)
# Clear canvas and display image
canvas = self.components['face_canvas']
canvas.delete("all")
# Position image at top-left corner like the original
canvas.create_image(0, 0, image=photo, anchor=tk.NW)
canvas.image = photo # Keep a reference
# Add photo icon exactly at the image's top-right corner
# Image starts at (0, 0) and is 400x400, so top-right corner is at (400, 0)
# Image starts at (0, 0) and fills the canvas
self.gui_core.create_photo_icon(canvas, photo_path, icon_size=25,
face_x=0, face_y=0,
face_width=400, face_height=400,
canvas_width=400, canvas_height=400)
face_width=canvas_width, face_height=canvas_height,
canvas_width=canvas_width, canvas_height=canvas_height)
else:
# Clear canvas if no image
canvas = self.components['face_canvas']
canvas.delete("all")
canvas.create_text(200, 200, text="No face image", fill="gray")
# Center the "No face image" text
canvas_width = canvas.winfo_width() if canvas.winfo_width() > 1 else canvas['width']
canvas_height = canvas.winfo_height() if canvas.winfo_height() > 1 else canvas['height']
canvas.create_text(canvas_width//2, canvas_height//2, text="No face image", fill="gray")
except Exception as e:
print(f"Error updating face image: {e}")
@ -1892,3 +1991,7 @@ class IdentifyPanel:
canvas = self.components['similar_canvas']
canvas.update_idletasks()
canvas.configure(scrollregion=canvas.bbox("all"))
# Update face canvas size if needed (for window resize events)
if hasattr(self, 'components') and 'face_canvas' in self.components:
self._update_face_canvas_size()