From 62bb0dc31f49ef2c3c3b163c391b298a15f4dcc9 Mon Sep 17 00:00:00 2001 From: tanyar09 Date: Mon, 29 Sep 2025 12:46:01 -0400 Subject: [PATCH] Add last name search functionality in PhotoTagger GUI. Implement search and clear buttons for filtering people by last name, enhancing user experience. Update population logic to reflect filtered results and ensure smooth integration with existing data handling. --- photo_tagger.py | 54 +++++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 50 insertions(+), 4 deletions(-) diff --git a/photo_tagger.py b/photo_tagger.py index 7e116cc..ab752b4 100644 --- a/photo_tagger.py +++ b/photo_tagger.py @@ -3338,6 +3338,18 @@ class PhotoTagger: people_frame = ttk.LabelFrame(main_frame, text="People", padding="10") people_frame.grid(row=1, column=0, sticky=(tk.W, tk.E, tk.N, tk.S), padx=(0, 8)) people_frame.columnconfigure(0, weight=1) + + # Search controls (Last Name) + last_name_search_var = tk.StringVar() + search_row = ttk.Frame(people_frame) + search_row.grid(row=0, column=0, columnspan=2, sticky=(tk.W, tk.E), pady=(0, 6)) + search_entry = ttk.Entry(search_row, textvariable=last_name_search_var, width=20) + search_entry.pack(side=tk.LEFT) + search_btn = ttk.Button(search_row, text="Search", width=8) + search_btn.pack(side=tk.LEFT, padx=(6, 0)) + clear_btn = ttk.Button(search_row, text="Clear", width=6) + clear_btn.pack(side=tk.LEFT, padx=(6, 0)) + people_canvas = tk.Canvas(people_frame, bg='white') people_scrollbar = ttk.Scrollbar(people_frame, orient="vertical", command=people_canvas.yview) people_list_inner = ttk.Frame(people_canvas) @@ -3349,9 +3361,9 @@ class PhotoTagger: lambda e: people_canvas.configure(scrollregion=people_canvas.bbox("all")) ) - people_canvas.grid(row=0, column=0, sticky=(tk.W, tk.E, tk.N, tk.S)) - people_scrollbar.grid(row=0, column=1, sticky=(tk.N, tk.S)) - people_frame.rowconfigure(0, weight=1) + people_canvas.grid(row=1, column=0, sticky=(tk.W, tk.E, tk.N, tk.S)) + people_scrollbar.grid(row=1, column=1, sticky=(tk.N, tk.S)) + people_frame.rowconfigure(1, weight=1) # Right panel: Faces for selected person faces_frame = ttk.LabelFrame(main_frame, text="Faces", padding="10") @@ -3399,6 +3411,7 @@ class PhotoTagger: # Load people from DB with counts people_data = [] # list of dicts: {id, name, count, first_name, last_name} + people_filtered = None # filtered subset based on last name search def load_people(): nonlocal people_data @@ -3445,6 +3458,34 @@ class PhotoTagger: 'date_of_birth': date_of_birth or "", 'count': count }) + # Re-apply filter (if any) after loading + try: + apply_last_name_filter() + except Exception: + pass + + # Wire up search controls now that helper functions exist + try: + search_btn.config(command=lambda: apply_last_name_filter()) + clear_btn.config(command=lambda: clear_last_name_filter()) + search_entry.bind('', lambda e: apply_last_name_filter()) + except Exception: + pass + + def apply_last_name_filter(): + nonlocal people_filtered + query = last_name_search_var.get().strip().lower() + if query: + people_filtered = [p for p in people_data if p.get('last_name', '').lower().find(query) != -1] + else: + people_filtered = None + populate_people_list() + + def clear_last_name_filter(): + nonlocal people_filtered + last_name_search_var.set("") + people_filtered = None + populate_people_list() def clear_faces_panel(): for w in faces_inner.winfo_children(): @@ -3618,7 +3659,12 @@ class PhotoTagger: def populate_people_list(): for w in people_list_inner.winfo_children(): w.destroy() - for idx, person in enumerate(people_data): + source = people_filtered if people_filtered is not None else people_data + if not source: + empty_label = ttk.Label(people_list_inner, text="No people match filter", foreground="gray") + empty_label.grid(row=0, column=0, sticky=tk.W, pady=4) + return + for idx, person in enumerate(source): row = ttk.Frame(people_list_inner) row.grid(row=idx, column=0, sticky=(tk.W, tk.E), pady=4) # Freeze per-row values to avoid late-binding issues