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:
parent
4816925a3d
commit
f8fefd2983
@ -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)
|
||||
|
||||
@ -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()
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user