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:
118
croppa/main.py
118
croppa/main.py
@@ -2534,56 +2534,62 @@ class VideoEditor:
|
||||
return False
|
||||
|
||||
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:
|
||||
return
|
||||
|
||||
template_ids = sorted(self.templates.keys())
|
||||
if self.current_template_id is None:
|
||||
# Find first template that starts after current frame
|
||||
for template_id in template_ids:
|
||||
if self.templates[template_id]['start_frame'] > self.current_frame:
|
||||
self.current_template_id = template_id
|
||||
self._select_best_template_for_frame(self.current_frame)
|
||||
self.show_feedback_message(f"Template {template_id} selected")
|
||||
return
|
||||
# Find first template
|
||||
if template_ids:
|
||||
template_id = template_ids[0]
|
||||
start_frame = self.templates[template_id]['start_frame']
|
||||
self.current_frame = start_frame
|
||||
self.current_template_id = template_id
|
||||
self._select_best_template_for_frame(self.current_frame)
|
||||
self.show_feedback_message(f"Template {template_id} (frame {start_frame})")
|
||||
return
|
||||
else:
|
||||
# Find next template
|
||||
current_idx = template_ids.index(self.current_template_id)
|
||||
for i in range(current_idx + 1, len(template_ids)):
|
||||
template_id = template_ids[i]
|
||||
if self.templates[template_id]['start_frame'] > self.current_frame:
|
||||
self.current_template_id = template_id
|
||||
self._select_best_template_for_frame(self.current_frame)
|
||||
self.show_feedback_message(f"Template {template_id} selected")
|
||||
return
|
||||
if current_idx + 1 < len(template_ids):
|
||||
template_id = template_ids[current_idx + 1]
|
||||
start_frame = self.templates[template_id]['start_frame']
|
||||
self.current_frame = start_frame
|
||||
self.current_template_id = template_id
|
||||
self._select_best_template_for_frame(self.current_frame)
|
||||
self.show_feedback_message(f"Template {template_id} (frame {start_frame})")
|
||||
return
|
||||
|
||||
self.show_feedback_message("No next template found")
|
||||
|
||||
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:
|
||||
return
|
||||
|
||||
template_ids = sorted(self.templates.keys())
|
||||
if self.current_template_id is None:
|
||||
# Find last template that starts before current frame
|
||||
for template_id in reversed(template_ids):
|
||||
if self.templates[template_id]['start_frame'] < self.current_frame:
|
||||
self.current_template_id = template_id
|
||||
self._select_best_template_for_frame(self.current_frame)
|
||||
self.show_feedback_message(f"Template {template_id} selected")
|
||||
return
|
||||
# Find last template
|
||||
if template_ids:
|
||||
template_id = template_ids[-1]
|
||||
start_frame = self.templates[template_id]['start_frame']
|
||||
self.current_frame = start_frame
|
||||
self.current_template_id = template_id
|
||||
self._select_best_template_for_frame(self.current_frame)
|
||||
self.show_feedback_message(f"Template {template_id} (frame {start_frame})")
|
||||
return
|
||||
else:
|
||||
# Find previous template
|
||||
current_idx = template_ids.index(self.current_template_id)
|
||||
for i in range(current_idx - 1, -1, -1):
|
||||
template_id = template_ids[i]
|
||||
if self.templates[template_id]['start_frame'] < self.current_frame:
|
||||
self.current_template_id = template_id
|
||||
self._select_best_template_for_frame(self.current_frame)
|
||||
self.show_feedback_message(f"Template {template_id} selected")
|
||||
return
|
||||
if current_idx - 1 >= 0:
|
||||
template_id = template_ids[current_idx - 1]
|
||||
start_frame = self.templates[template_id]['start_frame']
|
||||
self.current_frame = start_frame
|
||||
self.current_template_id = template_id
|
||||
self._select_best_template_for_frame(self.current_frame)
|
||||
self.show_feedback_message(f"Template {template_id} (frame {start_frame})")
|
||||
return
|
||||
|
||||
self.show_feedback_message("No previous template found")
|
||||
|
||||
@@ -3323,6 +3329,32 @@ class VideoEditor:
|
||||
conf_text = f"{confidence:.2f}"
|
||||
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
|
||||
if 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
|
||||
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:
|
||||
# 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
|
||||
raw_x, raw_y = self._map_screen_to_rotated(screen_x, screen_y)
|
||||
|
||||
for template_id, template_data in self.templates.items():
|
||||
tx, ty, tw, th = template_data['region']
|
||||
# Check if click is within template region
|
||||
if (tx <= raw_x <= tx + tw and ty <= raw_y <= ty + th):
|
||||
self.remove_template(template_id)
|
||||
self.save_state()
|
||||
return
|
||||
# Only check templates that cover current frame
|
||||
if (template_data['start_frame'] <= self.current_frame <= template_data['end_frame']):
|
||||
tx, ty, tw, th = template_data['region']
|
||||
center_x = tx + tw // 2
|
||||
center_y = ty + th // 2
|
||||
|
||||
# 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)
|
||||
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}")
|
||||
self.show_feedback_message(f"Multi-scale template matching {'ON' if self.multi_scale_template_matching else 'OFF'}")
|
||||
self.save_state()
|
||||
elif key == ord(";"): # Semicolon - Navigate to next template
|
||||
self.navigate_to_next_template()
|
||||
elif key == ord(":"): # Colon - Navigate to previous template
|
||||
elif key == ord(";"): # Semicolon - 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"):
|
||||
# Marker looping only for videos
|
||||
if not self.is_image_mode:
|
||||
|
Reference in New Issue
Block a user