Enhance video editing controls: add Shift+scroll functionality to expand/contract crop uniformly and implement adjust_crop_size_uniform method

This commit is contained in:
2025-12-22 12:30:10 +01:00
parent 4b9e8ecf45
commit 5c44d147b0

View File

@@ -4025,7 +4025,7 @@ class VideoEditor:
# Force immediate display update to recalculate previous/next points and arrows # Force immediate display update to recalculate previous/next points and arrows
self.display_current_frame() self.display_current_frame()
# Handle scroll wheel: Ctrl+scroll -> zoom; plain scroll -> seek ±1 frame (independent of multiplier) # Handle scroll wheel: Ctrl+scroll -> zoom; Shift+scroll -> expand/contract crop; plain scroll -> seek ±1 frame
if event == cv2.EVENT_MOUSEWHEEL: if event == cv2.EVENT_MOUSEWHEEL:
if flags & cv2.EVENT_FLAG_CTRLKEY: if flags & cv2.EVENT_FLAG_CTRLKEY:
if flags > 0: # Scroll up -> zoom in if flags > 0: # Scroll up -> zoom in
@@ -4033,6 +4033,12 @@ class VideoEditor:
else: # Scroll down -> zoom out else: # Scroll down -> zoom out
self.zoom_factor = max(self.MIN_ZOOM, self.zoom_factor - self.ZOOM_INCREMENT) self.zoom_factor = max(self.MIN_ZOOM, self.zoom_factor - self.ZOOM_INCREMENT)
self.clear_transformation_cache() self.clear_transformation_cache()
elif flags & cv2.EVENT_FLAG_SHIFTKEY:
# Shift+scroll -> expand/contract crop uniformly
if flags > 0: # Scroll up -> expand
self.adjust_crop_size_uniform(expand=True)
else: # Scroll down -> contract
self.adjust_crop_size_uniform(expand=False)
else: else:
if not self.is_image_mode: if not self.is_image_mode:
direction = 1 if flags > 0 else -1 direction = 1 if flags > 0 else -1
@@ -4265,6 +4271,45 @@ class VideoEditor:
self.clear_transformation_cache() self.clear_transformation_cache()
self.save_state() # Save state when crop is adjusted self.save_state() # Save state when crop is adjusted
def adjust_crop_size_uniform(self, expand: bool, amount: int = None):
"""Expand or contract crop uniformly in all directions
expand=False: expand (like uppercase HJKL)
expand=True: contract (like lowercase hjkl)
"""
if amount is None:
amount = self.crop_size_step
if not self.crop_rect:
center_x = self.frame_width // 2
center_y = self.frame_height // 2
default_size = min(self.frame_width, self.frame_height) // 4
self.crop_rect = (
center_x - default_size // 2,
center_y - default_size // 2,
default_size,
default_size
)
return
x, y, w, h = self.crop_rect
if not expand: # expand=False means expand
# Expand uniformly from center
new_x = max(0, x - amount)
new_y = max(0, y - amount)
new_w = min(self.frame_width - new_x, w + (x - new_x) + amount)
new_h = min(self.frame_height - new_y, h + (y - new_y) + amount)
else: # expand=True means contract
# Contract uniformly toward center
contract_amount = min(amount, (w - 10) // 2, (h - 10) // 2)
new_x = x + contract_amount
new_y = y + contract_amount
new_w = max(10, w - contract_amount * 2)
new_h = max(10, h - contract_amount * 2)
self.crop_rect = (new_x, new_y, new_w, new_h)
self.clear_transformation_cache()
self.save_state()
def render_video(self, output_path: str): def render_video(self, output_path: str):
"""Render video or save image with current edits applied""" """Render video or save image with current edits applied"""
if self.is_image_mode: if self.is_image_mode: