Refactor template navigation in VideoEditor for improved frame handling and user feedback

This commit updates the navigation methods for templates in the VideoEditor, enhancing the logic to jump to the start frame of the selected template. The feedback messages have been improved to provide clearer information about the selected template and its corresponding frame. Additionally, visual indicators for active templates have been added, allowing users to easily identify which templates are currently in use during video editing sessions.
This commit is contained in:
2025-09-26 17:34:27 +02:00
parent 612d024161
commit b6c7863b77

View File

@@ -2534,56 +2534,62 @@ class VideoEditor:
return False return False
def navigate_to_next_template(self): def navigate_to_next_template(self):
"""Navigate to next template (; key)""" """Navigate to next template (: key) - jump to template's start frame"""
if not self.templates: if not self.templates:
return return
template_ids = sorted(self.templates.keys()) template_ids = sorted(self.templates.keys())
if self.current_template_id is None: if self.current_template_id is None:
# Find first template that starts after current frame # Find first template
for template_id in template_ids: if template_ids:
if self.templates[template_id]['start_frame'] > self.current_frame: template_id = template_ids[0]
self.current_template_id = template_id start_frame = self.templates[template_id]['start_frame']
self._select_best_template_for_frame(self.current_frame) self.current_frame = start_frame
self.show_feedback_message(f"Template {template_id} selected") self.current_template_id = template_id
return self._select_best_template_for_frame(self.current_frame)
self.show_feedback_message(f"Template {template_id} (frame {start_frame})")
return
else: else:
# Find next template # Find next template
current_idx = template_ids.index(self.current_template_id) current_idx = template_ids.index(self.current_template_id)
for i in range(current_idx + 1, len(template_ids)): if current_idx + 1 < len(template_ids):
template_id = template_ids[i] template_id = template_ids[current_idx + 1]
if self.templates[template_id]['start_frame'] > self.current_frame: start_frame = self.templates[template_id]['start_frame']
self.current_template_id = template_id self.current_frame = start_frame
self._select_best_template_for_frame(self.current_frame) self.current_template_id = template_id
self.show_feedback_message(f"Template {template_id} selected") self._select_best_template_for_frame(self.current_frame)
return self.show_feedback_message(f"Template {template_id} (frame {start_frame})")
return
self.show_feedback_message("No next template found") self.show_feedback_message("No next template found")
def navigate_to_previous_template(self): def navigate_to_previous_template(self):
"""Navigate to previous template (: key)""" """Navigate to previous template (; key) - jump to template's start frame"""
if not self.templates: if not self.templates:
return return
template_ids = sorted(self.templates.keys()) template_ids = sorted(self.templates.keys())
if self.current_template_id is None: if self.current_template_id is None:
# Find last template that starts before current frame # Find last template
for template_id in reversed(template_ids): if template_ids:
if self.templates[template_id]['start_frame'] < self.current_frame: template_id = template_ids[-1]
self.current_template_id = template_id start_frame = self.templates[template_id]['start_frame']
self._select_best_template_for_frame(self.current_frame) self.current_frame = start_frame
self.show_feedback_message(f"Template {template_id} selected") self.current_template_id = template_id
return self._select_best_template_for_frame(self.current_frame)
self.show_feedback_message(f"Template {template_id} (frame {start_frame})")
return
else: else:
# Find previous template # Find previous template
current_idx = template_ids.index(self.current_template_id) current_idx = template_ids.index(self.current_template_id)
for i in range(current_idx - 1, -1, -1): if current_idx - 1 >= 0:
template_id = template_ids[i] template_id = template_ids[current_idx - 1]
if self.templates[template_id]['start_frame'] < self.current_frame: start_frame = self.templates[template_id]['start_frame']
self.current_template_id = template_id self.current_frame = start_frame
self._select_best_template_for_frame(self.current_frame) self.current_template_id = template_id
self.show_feedback_message(f"Template {template_id} selected") self._select_best_template_for_frame(self.current_frame)
return self.show_feedback_message(f"Template {template_id} (frame {start_frame})")
return
self.show_feedback_message("No previous template found") self.show_feedback_message("No previous template found")
@@ -3323,6 +3329,32 @@ class VideoEditor:
conf_text = f"{confidence:.2f}" conf_text = f"{confidence:.2f}"
cv2.putText(canvas, conf_text, (sx + 10, sy - 10), cv2.FONT_HERSHEY_SIMPLEX, 0.5, (255, 255, 255), 1) cv2.putText(canvas, conf_text, (sx + 10, sy - 10), cv2.FONT_HERSHEY_SIMPLEX, 0.5, (255, 255, 255), 1)
# Draw template dots for all templates
if not self.is_image_mode and self.templates:
for template_id, template_data in self.templates.items():
# Only draw if this template covers the current frame
if (template_data['start_frame'] <= self.current_frame <= template_data['end_frame']):
# Get template center position from region
x, y, w, h = template_data['region']
center_x = x + w // 2
center_y = y + h // 2
# Map to screen coordinates
sx, sy = self._map_rotated_to_screen(center_x, center_y)
# Draw template dot (different colors for active/inactive)
is_active = (self.current_template_id == template_id)
if is_active:
cv2.circle(canvas, (sx, sy), 6, (0, 255, 0), -1) # Green for active
cv2.circle(canvas, (sx, sy), 6, (255, 255, 255), 2)
else:
cv2.circle(canvas, (sx, sy), 4, (0, 0, 255), -1) # Red for inactive
cv2.circle(canvas, (sx, sy), 4, (255, 255, 255), 1)
# Draw template ID
cv2.putText(canvas, str(template_id), (sx + 8, sy - 8),
cv2.FONT_HERSHEY_SIMPLEX, 0.4, (255, 255, 255), 1)
# Draw selection rectangles for feature extraction/deletion # Draw selection rectangles for feature extraction/deletion
if self.selective_feature_extraction_rect: if self.selective_feature_extraction_rect:
x, y, w, h = self.selective_feature_extraction_rect x, y, w, h = self.selective_feature_extraction_rect
@@ -3541,17 +3573,23 @@ class VideoEditor:
# Handle Ctrl+Right-click for template removal # Handle Ctrl+Right-click for template removal
if event == cv2.EVENT_RBUTTONDOWN and (flags & cv2.EVENT_FLAG_CTRLKEY) and not (flags & cv2.EVENT_FLAG_SHIFTKEY): if event == cv2.EVENT_RBUTTONDOWN and (flags & cv2.EVENT_FLAG_CTRLKEY) and not (flags & cv2.EVENT_FLAG_SHIFTKEY):
if not self.is_image_mode and self.templates: if not self.is_image_mode and self.templates:
# Check if click is near any template region # Check if click is near any template dot (center of template region)
screen_x, screen_y = x, y screen_x, screen_y = x, y
raw_x, raw_y = self._map_screen_to_rotated(screen_x, screen_y) raw_x, raw_y = self._map_screen_to_rotated(screen_x, screen_y)
for template_id, template_data in self.templates.items(): for template_id, template_data in self.templates.items():
tx, ty, tw, th = template_data['region'] # Only check templates that cover current frame
# Check if click is within template region if (template_data['start_frame'] <= self.current_frame <= template_data['end_frame']):
if (tx <= raw_x <= tx + tw and ty <= raw_y <= ty + th): tx, ty, tw, th = template_data['region']
self.remove_template(template_id) center_x = tx + tw // 2
self.save_state() center_y = ty + th // 2
return
# Check if click is within 10px of template center
distance = ((raw_x - center_x) ** 2 + (raw_y - center_y) ** 2) ** 0.5
if distance <= 10:
self.remove_template(template_id)
self.save_state()
return
# Handle right-click for tracking points (no modifiers) # Handle right-click for tracking points (no modifiers)
if event == cv2.EVENT_RBUTTONDOWN and not (flags & (cv2.EVENT_FLAG_CTRLKEY | cv2.EVENT_FLAG_SHIFTKEY)): if event == cv2.EVENT_RBUTTONDOWN and not (flags & (cv2.EVENT_FLAG_CTRLKEY | cv2.EVENT_FLAG_SHIFTKEY)):
@@ -4757,10 +4795,10 @@ class VideoEditor:
print(f"DEBUG: Multi-scale template matching toggled to {self.multi_scale_template_matching}") print(f"DEBUG: Multi-scale template matching toggled to {self.multi_scale_template_matching}")
self.show_feedback_message(f"Multi-scale template matching {'ON' if self.multi_scale_template_matching else 'OFF'}") self.show_feedback_message(f"Multi-scale template matching {'ON' if self.multi_scale_template_matching else 'OFF'}")
self.save_state() self.save_state()
elif key == ord(";"): # Semicolon - Navigate to next template elif key == ord(";"): # Semicolon - Navigate to previous template
self.navigate_to_next_template()
elif key == ord(":"): # Colon - Navigate to previous template
self.navigate_to_previous_template() self.navigate_to_previous_template()
elif key == ord(":"): # Colon - Navigate to next template
self.navigate_to_next_template()
elif key == ord("t"): elif key == ord("t"):
# Marker looping only for videos # Marker looping only for videos
if not self.is_image_mode: if not self.is_image_mode: