Refactor crop border dragging logic to improve user interaction

Enhance the crop border dragging functionality in the VideoEditor class by introducing logic to determine whether the drag starts inside or outside the crop area. Adjustments to crop dimensions are now based on the direction of movement and the position relative to the crop area, ensuring a more intuitive user experience. This update also includes the removal of the previous edge detection mechanism, streamlining the dragging process.
This commit is contained in:
2025-12-23 09:34:39 +01:00
parent 73e72bcb3b
commit bf32bb98ae

View File

@@ -154,9 +154,9 @@ class VideoEditor:
self.crop_preview_rect = None
self.crop_history = [] # For undo
self.crop_border_dragging = False
self.crop_border_drag_edge = None # 'left', 'right', 'top', 'bottom'
self.crop_border_drag_start_pos = None # (screen_x, screen_y) when drag started
self.crop_border_drag_start_rect = None # (x, y, w, h) in rotated coords when drag started
self.crop_border_drag_inside = None # True if drag started inside crop area, False if outside
# Zoom settings
self.zoom_factor = 1.0
@@ -3118,46 +3118,22 @@ class VideoEditor:
# Handle crop border dragging (only when Shift and Ctrl are NOT pressed)
if not (flags & cv2.EVENT_FLAG_SHIFTKEY) and not (flags & cv2.EVENT_FLAG_CTRLKEY) and self.crop_rect:
border_threshold = self.CROP_BORDER_DETECTION_MAX_DISTANCE
# Get effective crop in rotated coords and map to screen
eff_x, eff_y, eff_w, eff_h = self._get_effective_crop_rect_for_frame(getattr(self, 'current_frame', 0))
sx1, sy1 = self._map_rotated_to_screen(eff_x, eff_y)
sx2, sy2 = self._map_rotated_to_screen(eff_x + eff_w, eff_y + eff_h)
# Detect which border is closest to cursor
def detect_border():
# Calculate distances to each border
dist_left = abs(x - sx1) if sy1 <= y <= sy2 else float('inf')
dist_right = abs(x - sx2) if sy1 <= y <= sy2 else float('inf')
dist_top = abs(y - sy1) if sx1 <= x <= sx2 else float('inf')
dist_bottom = abs(y - sy2) if sx1 <= x <= sx2 else float('inf')
# Find closest border
distances = {
'left': dist_left,
'right': dist_right,
'top': dist_top,
'bottom': dist_bottom
}
closest_edge = min(distances, key=distances.get)
closest_dist = distances[closest_edge]
# Only return if within threshold
if closest_dist < border_threshold:
return closest_edge
return None
# Check if cursor is inside crop area
inside_crop = sx1 <= x <= sx2 and sy1 <= y <= sy2
if event == cv2.EVENT_LBUTTONDOWN:
edge = detect_border()
if edge:
self.crop_border_dragging = True
self.crop_border_drag_edge = edge
self.crop_border_drag_start_pos = (x, y)
self.crop_border_drag_start_rect = (eff_x, eff_y, eff_w, eff_h)
# Start dragging - record position and whether we're inside/outside
self.crop_border_dragging = True
self.crop_border_drag_start_pos = (x, y)
self.crop_border_drag_start_rect = (eff_x, eff_y, eff_w, eff_h)
self.crop_border_drag_inside = inside_crop
elif event == cv2.EVENT_MOUSEMOVE and self.crop_border_dragging:
if self.crop_border_drag_edge and self.crop_border_drag_start_pos and self.crop_border_drag_start_rect:
if self.crop_border_drag_start_pos and self.crop_border_drag_start_rect and self.crop_border_drag_inside is not None:
# Convert mouse movement from screen to rotated coords
start_sx, start_sy = self.crop_border_drag_start_pos
start_rx, start_ry = self._map_screen_to_rotated(start_sx, start_sy)
@@ -3166,7 +3142,11 @@ class VideoEditor:
dx_r = curr_rx - start_rx
dy_r = curr_ry - start_ry
# Adjust the appropriate border
# Determine primary direction (horizontal vs vertical)
abs_dx = abs(dx_r)
abs_dy = abs(dy_r)
# Adjust the appropriate border based on direction and inside/outside
new_x, new_y, new_w, new_h = self.crop_border_drag_start_rect
# Get rotated frame dimensions
@@ -3175,26 +3155,63 @@ class VideoEditor:
else:
rot_w, rot_h = self.frame_width, self.frame_height
if self.crop_border_drag_edge == 'left':
new_x = max(0, new_x + dx_r)
new_w = new_w - dx_r
if new_w < 10:
new_w = 10
new_x = self.crop_border_drag_start_rect[0] + self.crop_border_drag_start_rect[2] - 10
elif self.crop_border_drag_edge == 'right':
new_w = max(10, new_w + dx_r)
if new_x + new_w > rot_w:
new_w = rot_w - new_x
elif self.crop_border_drag_edge == 'top':
new_y = max(0, new_y + dy_r)
new_h = new_h - dy_r
if new_h < 10:
new_h = 10
new_y = self.crop_border_drag_start_rect[1] + self.crop_border_drag_start_rect[3] - 10
elif self.crop_border_drag_edge == 'bottom':
new_h = max(10, new_h + dy_r)
if new_y + new_h > rot_h:
new_h = rot_h - new_y
# Determine which border to adjust based on movement direction
if abs_dx > abs_dy:
# Horizontal movement
if self.crop_border_drag_inside:
# Inside crop: drag left -> adjust left border, drag right -> adjust right border
if dx_r < 0:
# Dragging left -> move left border left (expand left)
new_x = max(0, new_x + dx_r)
new_w = new_w - dx_r
if new_w < self.CROP_MIN_SIZE:
new_w = self.CROP_MIN_SIZE
new_x = self.crop_border_drag_start_rect[0] + self.crop_border_drag_start_rect[2] - self.CROP_MIN_SIZE
else:
# Dragging right -> move right border right (expand right)
new_w = max(self.CROP_MIN_SIZE, new_w + dx_r)
if new_x + new_w > rot_w:
new_w = rot_w - new_x
else:
# Outside crop: drag left -> adjust right border left (contract), drag right -> adjust right border right (expand)
if dx_r < 0:
# Dragging left -> move right border left (contract right)
new_w = max(self.CROP_MIN_SIZE, new_w + dx_r)
if new_w < self.CROP_MIN_SIZE:
new_w = self.CROP_MIN_SIZE
else:
# Dragging right -> move right border right (expand right)
new_w = max(self.CROP_MIN_SIZE, new_w + dx_r)
if new_x + new_w > rot_w:
new_w = rot_w - new_x
else:
# Vertical movement
if self.crop_border_drag_inside:
# Inside crop: drag up -> adjust top border, drag down -> adjust bottom border
if dy_r < 0:
# Dragging up -> move top border up (expand up)
new_y = max(0, new_y + dy_r)
new_h = new_h - dy_r
if new_h < self.CROP_MIN_SIZE:
new_h = self.CROP_MIN_SIZE
new_y = self.crop_border_drag_start_rect[1] + self.crop_border_drag_start_rect[3] - self.CROP_MIN_SIZE
else:
# Dragging down -> move bottom border down (expand down)
new_h = max(self.CROP_MIN_SIZE, new_h + dy_r)
if new_y + new_h > rot_h:
new_h = rot_h - new_y
else:
# Outside crop: drag up -> adjust bottom border up (contract), drag down -> adjust bottom border down (expand)
if dy_r < 0:
# Dragging up -> move bottom border up (contract bottom)
new_h = max(self.CROP_MIN_SIZE, new_h + dy_r)
if new_h < self.CROP_MIN_SIZE:
new_h = self.CROP_MIN_SIZE
else:
# Dragging down -> move bottom border down (expand down)
new_h = max(self.CROP_MIN_SIZE, new_h + dy_r)
if new_y + new_h > rot_h:
new_h = rot_h - new_y
# Convert back from rotated to original frame coords
self._set_crop_from_rotated_rect((new_x, new_y, new_w, new_h))
@@ -3202,9 +3219,9 @@ class VideoEditor:
self.display_current_frame()
elif event == cv2.EVENT_LBUTTONUP and self.crop_border_dragging:
self.crop_border_dragging = False
self.crop_border_drag_edge = None
self.crop_border_drag_start_pos = None
self.crop_border_drag_start_rect = None
self.crop_border_drag_inside = None
self.save_state()
# Handle crop selection (Shift + click and drag)