Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Tab Navigation Feature Implementation #166

Closed
Closed
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
153 changes: 104 additions & 49 deletions Pose2Sim/synchronization.py
Original file line number Diff line number Diff line change
Expand Up @@ -293,33 +293,101 @@ def handle_key_press(event, frame_textbox, search_around_frames, i, cap, ax_vide
'''

direction = 0
if event.key == 'left':
direction = -1
elif event.key == 'right':
if event.key == 'up':
direction = 1
elif event.key == 'down':
direction = -1

if direction != 0:
handle_frame_navigation(direction, frame_textbox, search_around_frames, i, cap, ax_video, frame_to_json,
pose_dir, json_dir_name, rects, annotations, bounding_boxes_list, fig,
time_range_around_maxspeed, fps, ui)


def handle_toggle_labels(keypoint_texts, containers, btn_toggle):
'''
Handle toggle labels button click.

INPUTS:
- event: Matplotlib event object
- keypoint_texts: List of text objects for keypoint labels
- containers: Dictionary of container objects
- btn_toggle: Button object for toggling label visibility
'''

containers['show_labels'][0] = not containers['show_labels'][0] # Toggle visibility state
for text in keypoint_texts:
text.set_visible(containers['show_labels'][0])
# Update button text
btn_toggle.label.set_text('Hide names' if containers['show_labels'][0] else 'Show names')
plt.draw()
elif event.key == 'tab':
# Handle tab key to cycle through text boxes
textboxes = ['person_textbox', 'main_time_textbox', 'time_RAM_textbox']

# Find current active textbox and determine next one
active_textbox = next((tb for tb in textboxes if tb in ui['controls'] and ui['controls'][tb].active), None)
next_idx = (textboxes.index(active_textbox) + 1) % len(textboxes) if active_textbox in textboxes else 0
next_textbox = textboxes[next_idx]

# Deactivate all textboxes
for tb in textboxes:
if tb in ui['controls'] and tb != next_textbox:
prev_textbox = ui['controls'][tb]
prev_textbox.active = False

# Make sure cursor is completely removed from previous textbox
if hasattr(prev_textbox, 'cursor_visible'):
prev_textbox.cursor_visible = False
if hasattr(prev_textbox, 'cursor'):
prev_textbox.cursor.set_visible(False)
if hasattr(prev_textbox, '_cursor'):
prev_textbox._cursor.set_visible(False)

# Reset the appearance of the previous textbox
if hasattr(prev_textbox, 'ax'):
prev_textbox.ax.set_facecolor(prev_textbox.color)

# Activate new textbox
textbox = ui['controls'][next_textbox]
textbox.active = True
textbox.ax.set_facecolor(textbox.hovercolor)

# Setup textbox for editing
for attr, value in [('eventson', True), ('cursor_visible', True),
('capturekeystrokes', True), ('cursor_index', len(textbox.text))]:
if hasattr(textbox, attr):
setattr(textbox, attr, value)

# Special method calls
if hasattr(textbox, 'set_active'):
textbox.set_active(True)
if hasattr(textbox, 'begin_typing'):
textbox.begin_typing()

# Refresh UI
textbox.set_val(textbox.text)
ui['fig'].canvas.draw_idle()
ui['fig'].canvas.flush_events()

elif event.key == 'enter':
# Check if any textbox is currently active/being edited
textboxes = ['person_textbox', 'main_time_textbox', 'time_RAM_textbox']
active_textbox = None

for tb_name in textboxes:
if tb_name in ui['controls'] and ui['controls'][tb_name].active:
active_textbox = tb_name
break

if active_textbox:
# If a textbox is active, confirm its value by triggering its on_submit callback
textbox = ui['controls'][active_textbox]
current_text = textbox.text

# Deactivate the textbox
textbox.active = False
textbox.cursor_visible = False
if hasattr(textbox, 'cursor'):
textbox.cursor.set_visible(False)
if hasattr(textbox, '_cursor'):
textbox._cursor.set_visible(False)

# Reset appearance
if hasattr(textbox, 'ax'):
textbox.ax.set_facecolor(textbox.color)

# Trigger the on_submit callback manually
if hasattr(textbox, 'on_submit'):
textbox.on_submit(current_text)

# Update UI
ui['fig'].canvas.draw_idle()
else:
# If no textbox is active, handle OK button (close UI)
handle_ok_button(ui)


## Highlighters
Expand Down Expand Up @@ -371,6 +439,19 @@ def on_hover(event, fig, rects, annotations, bounding_boxes_list, selected_idx_c

if event.xdata is None or event.ydata is None:
return

# Access the figure and check if it has a key_press_event connection
# If we're in tab navigation, a previous tab press will have created 'temp_selected_box'
# attribute on one of the rectangle objects
has_temp_selection = False
for rect in rects:
if hasattr(rect, 'temp_selected_box') and rect.temp_selected_box:
has_temp_selection = True
break

if has_temp_selection:
# We're in tab navigation mode, don't interfere with hover effects
return

# First reset all boxes to default style
for idx, (rect, annotation) in enumerate(zip(rects, annotations)):
Expand Down Expand Up @@ -438,33 +519,6 @@ def on_slider_change(val, fps, controls, fig, search_around_frames, cam_index, a
fig.canvas.draw_idle()


def on_key(event, ui, fps, cap, frame_to_json, pose_dir, json_dirs_names, i, search_around_frames, bounding_boxes_list):
'''
Handles keyboard navigation through video frames.

INPUTS:
- event: Matplotlib keyboard event object
- ui: Dictionary containing all UI elements and state
- fps: Frames per second of the video
- cap: Video capture object
- frame_to_json: Mapping of frame numbers to JSON files
- pose_dir: Directory containing pose data
- json_dirs_names: List of JSON directory names
- i: Current camera index
- search_around_frames: Frame ranges to search around for each camera
- bounding_boxes_list: List of bounding boxes for detected persons
'''

if event.key == 'left':
handle_frame_navigation(-1, ui['controls']['main_time_textbox'], search_around_frames, i, cap, ui['ax_video'], frame_to_json,
pose_dir, json_dirs_names[i], ui['containers']['rects'], ui['containers']['annotations'], bounding_boxes_list, ui['fig'],
float(ui['controls']['time_RAM_textbox'].text), fps, ui)
elif event.key == 'right':
handle_frame_navigation(1, ui['controls']['main_time_textbox'], search_around_frames, i, cap, ui['ax_video'], frame_to_json,
pose_dir, json_dirs_names[i], ui['containers']['rects'], ui['containers']['annotations'], bounding_boxes_list, ui['fig'],
float(ui['controls']['time_RAM_textbox'].text), fps, ui)


## UI Update Functions
def update_highlight(current_frame, time_RAM, fps, search_around_frames, cam_index, ax_slider, controls):
'''
Expand Down Expand Up @@ -953,7 +1007,8 @@ def person_ui(frame_rgb, cam_name, frame_number, search_around_frames, time_rang
'rects': [],
'annotations': [],
'bounding_boxes_list': [],
'selected_idx': [0]
'selected_idx': [0],
'temp_selected_idx': [0] # Initialize temp_selected_idx for tab navigation
}

# Create UI dictionary
Expand Down
Loading