diff --git a/src/gui/dashboard_gui.py b/src/gui/dashboard_gui.py index f12a17d..8631691 100644 --- a/src/gui/dashboard_gui.py +++ b/src/gui/dashboard_gui.py @@ -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) diff --git a/src/gui/identify_panel.py b/src/gui/identify_panel.py index c29c9ca..27e47ac 100644 --- a/src/gui/identify_panel.py +++ b/src/gui/identify_panel.py @@ -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()