Add last name search functionality to PhotoTagger GUI. Implement search and clear buttons for filtering people by last name, enhancing user experience. Update navigation and display logic to reflect filtered results, ensuring proper handling of UI states and feedback when no matches are found.
This commit is contained in:
parent
347a597927
commit
2394afb5ee
@ -2710,13 +2710,24 @@ class PhotoTagger:
|
||||
# Configure row weights
|
||||
main_frame.rowconfigure(0, weight=1)
|
||||
|
||||
# Search controls for filtering people by last name
|
||||
last_name_search_var = tk.StringVar()
|
||||
search_row = ttk.Frame(left_frame)
|
||||
search_row.grid(row=0, column=0, sticky=(tk.W, tk.E), pady=(0, 10))
|
||||
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))
|
||||
|
||||
# Matched person info
|
||||
matched_info_label = ttk.Label(left_frame, text="", font=("Arial", 10, "bold"))
|
||||
matched_info_label.grid(row=0, column=0, pady=(0, 10), sticky=tk.W)
|
||||
matched_info_label.grid(row=1, column=0, pady=(0, 10), sticky=tk.W)
|
||||
|
||||
# Matched person image
|
||||
matched_canvas = tk.Canvas(left_frame, width=300, height=300, bg='white')
|
||||
matched_canvas.grid(row=1, column=0, pady=(0, 10))
|
||||
matched_canvas.grid(row=2, column=0, pady=(0, 10))
|
||||
|
||||
# Save button for this person (will be created after function definitions)
|
||||
save_btn = None
|
||||
@ -2777,6 +2788,7 @@ class PhotoTagger:
|
||||
# Button commands
|
||||
current_matched_index = 0
|
||||
matched_ids = [person_id for person_id, _, _ in person_faces_list if person_id in matches_by_matched and matches_by_matched[person_id]]
|
||||
filtered_matched_ids = None # filtered subset based on last name search
|
||||
|
||||
match_checkboxes = []
|
||||
match_vars = []
|
||||
@ -2846,7 +2858,8 @@ class PhotoTagger:
|
||||
# Save current checkbox states before navigating away
|
||||
save_current_checkbox_states()
|
||||
current_matched_index += 1
|
||||
if current_matched_index < len(matched_ids):
|
||||
active_ids = filtered_matched_ids if filtered_matched_ids is not None else matched_ids
|
||||
if current_matched_index < len(active_ids):
|
||||
update_display()
|
||||
else:
|
||||
finish_auto_match()
|
||||
@ -2874,6 +2887,48 @@ class PhotoTagger:
|
||||
return True
|
||||
return False
|
||||
|
||||
def apply_last_name_filter():
|
||||
"""Filter people by last name and update navigation"""
|
||||
nonlocal filtered_matched_ids, current_matched_index
|
||||
query = last_name_search_var.get().strip().lower()
|
||||
if query:
|
||||
# Filter person_faces_list by last name
|
||||
filtered_people = []
|
||||
for person_id, face, person_name in person_faces_list:
|
||||
# Extract last name from person_name (format: "Last, First")
|
||||
if ',' in person_name:
|
||||
last_name = person_name.split(',')[0].strip().lower()
|
||||
else:
|
||||
last_name = person_name.strip().lower()
|
||||
|
||||
if query in last_name:
|
||||
filtered_people.append((person_id, face, person_name))
|
||||
|
||||
# Get filtered matched_ids
|
||||
filtered_matched_ids = [person_id for person_id, _, _ in filtered_people if person_id in matches_by_matched and matches_by_matched[person_id]]
|
||||
else:
|
||||
filtered_matched_ids = None
|
||||
|
||||
# Reset to first person in filtered list
|
||||
current_matched_index = 0
|
||||
if filtered_matched_ids:
|
||||
update_display()
|
||||
else:
|
||||
# No matches - clear display
|
||||
matched_info_label.config(text="No people match filter")
|
||||
matched_canvas.delete("all")
|
||||
matched_canvas.create_text(150, 150, text="No matches found", fill="gray")
|
||||
matches_canvas.delete("all")
|
||||
update_button_states()
|
||||
|
||||
def clear_last_name_filter():
|
||||
"""Clear filter and show all people"""
|
||||
nonlocal filtered_matched_ids, current_matched_index
|
||||
last_name_search_var.set("")
|
||||
filtered_matched_ids = None
|
||||
current_matched_index = 0
|
||||
update_display()
|
||||
|
||||
def on_quit_auto_match():
|
||||
nonlocal window_destroyed
|
||||
|
||||
@ -2985,10 +3040,11 @@ class PhotoTagger:
|
||||
|
||||
# Create save button now that functions are defined
|
||||
save_btn = ttk.Button(left_frame, text="💾 Save Changes", command=on_confirm_matches)
|
||||
save_btn.grid(row=2, column=0, pady=(0, 10), sticky=(tk.W, tk.E))
|
||||
save_btn.grid(row=3, column=0, pady=(0, 10), sticky=(tk.W, tk.E))
|
||||
|
||||
def update_button_states():
|
||||
"""Update button states based on current position"""
|
||||
active_ids = filtered_matched_ids if filtered_matched_ids is not None else matched_ids
|
||||
# Enable/disable Back button based on position
|
||||
if current_matched_index > 0:
|
||||
back_btn.config(state='normal')
|
||||
@ -2996,15 +3052,16 @@ class PhotoTagger:
|
||||
back_btn.config(state='disabled')
|
||||
|
||||
# Enable/disable Next button based on position
|
||||
if current_matched_index < len(matched_ids) - 1:
|
||||
if current_matched_index < len(active_ids) - 1:
|
||||
next_btn.config(state='normal')
|
||||
else:
|
||||
next_btn.config(state='disabled')
|
||||
|
||||
def update_save_button_text():
|
||||
"""Update save button text with current person name"""
|
||||
if current_matched_index < len(matched_ids):
|
||||
matched_id = matched_ids[current_matched_index]
|
||||
active_ids = filtered_matched_ids if filtered_matched_ids is not None else matched_ids
|
||||
if current_matched_index < len(active_ids):
|
||||
matched_id = active_ids[current_matched_index]
|
||||
# Get person name from the first match for this person
|
||||
matches_for_current_person = matches_by_matched[matched_id]
|
||||
if matches_for_current_person:
|
||||
@ -3042,11 +3099,12 @@ class PhotoTagger:
|
||||
|
||||
def update_display():
|
||||
nonlocal current_matched_index
|
||||
if current_matched_index >= len(matched_ids):
|
||||
active_ids = filtered_matched_ids if filtered_matched_ids is not None else matched_ids
|
||||
if current_matched_index >= len(active_ids):
|
||||
finish_auto_match()
|
||||
return
|
||||
|
||||
matched_id = matched_ids[current_matched_index]
|
||||
matched_id = active_ids[current_matched_index]
|
||||
matches_for_this_person = matches_by_matched[matched_id]
|
||||
|
||||
# Update button states
|
||||
@ -3056,7 +3114,8 @@ class PhotoTagger:
|
||||
update_save_button_text()
|
||||
|
||||
# Update title
|
||||
root.title(f"Auto-Match Face Identification - {current_matched_index + 1}/{len(matched_ids)}")
|
||||
active_ids = filtered_matched_ids if filtered_matched_ids is not None else matched_ids
|
||||
root.title(f"Auto-Match Face Identification - {current_matched_index + 1}/{len(active_ids)}")
|
||||
|
||||
# Get the first match to get matched person info
|
||||
if not matches_for_this_person:
|
||||
@ -3234,6 +3293,14 @@ class PhotoTagger:
|
||||
# Window was destroyed before we could show it
|
||||
return 0
|
||||
|
||||
# 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('<Return>', lambda e: apply_last_name_filter())
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
# Start with first matched person
|
||||
update_display()
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user