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:
127
croppa/main.py
127
croppa/main.py
@@ -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)
|
||||
|
||||
Reference in New Issue
Block a user