Compare commits

..

2 Commits

Author SHA1 Message Date
498a1911b1 Refactor constants to constants 2025-09-17 15:09:10 +02:00
d068da20f4 Remove some dead code 2025-09-17 15:08:42 +02:00

View File

@@ -509,6 +509,14 @@ class VideoEditor:
# Crop adjustment settings # Crop adjustment settings
CROP_SIZE_STEP = 15 # pixels to expand/contract crop CROP_SIZE_STEP = 15 # pixels to expand/contract crop
# Motion tracking settings
TRACKING_POINT_THRESHOLD = 10 # pixels for delete/snap radius
# Seek frame counts
SEEK_FRAMES_CTRL = 60 # Ctrl modifier: 60 frames
SEEK_FRAMES_SHIFT = 10 # Shift modifier: 10 frames
SEEK_FRAMES_DEFAULT = 1 # Default: 1 frame
def __init__(self, path: str): def __init__(self, path: str):
self.path = Path(path) self.path = Path(path)
@@ -996,11 +1004,11 @@ class VideoEditor:
): ):
"""Seek video with different frame counts based on modifiers and seek multiplier""" """Seek video with different frame counts based on modifiers and seek multiplier"""
if ctrl_pressed: if ctrl_pressed:
base_frames = 60 # Ctrl: 60 frames base_frames = self.SEEK_FRAMES_CTRL
elif shift_pressed: elif shift_pressed:
base_frames = 10 # Shift: 10 frames base_frames = self.SEEK_FRAMES_SHIFT
else: else:
base_frames = 1 # Default: 1 frame base_frames = self.SEEK_FRAMES_DEFAULT
# Apply seek multiplier to the base frame count # Apply seek multiplier to the base frame count
frames = direction * int(base_frames * self.seek_multiplier) frames = direction * int(base_frames * self.seek_multiplier)
@@ -1057,18 +1065,6 @@ class VideoEditor:
self.current_frame = max(0, min(frame_number, self.total_frames - 1)) self.current_frame = max(0, min(frame_number, self.total_frames - 1))
self.load_current_frame() self.load_current_frame()
def _get_sorted_markers(self):
"""Return sorted unique marker list [cut_start_frame, cut_end_frame] as ints within bounds."""
markers = []
for m in (self.cut_start_frame, self.cut_end_frame):
if isinstance(m, int):
markers.append(m)
if not markers:
return []
# Clamp and dedupe
clamped = set(max(0, min(m, self.total_frames - 1)) for m in markers)
return sorted(clamped)
def jump_to_previous_marker(self): def jump_to_previous_marker(self):
"""Jump to the previous tracking marker (frame with tracking points).""" """Jump to the previous tracking marker (frame with tracking points)."""
if self.is_image_mode: if self.is_image_mode:
@@ -1316,90 +1312,6 @@ class VideoEditor:
'available_h': available_height 'available_h': available_height
} }
def _map_original_to_screen(self, ox, oy):
"""Map a point in original frame coords to canvas screen coords."""
frame_number = getattr(self, 'current_frame', 0)
# Since crop is applied after rotation, mapping to rotated space uses only rotation
angle = self.rotation_angle
if angle == 90:
rx, ry = oy, self.frame_width - 1 - ox
elif angle == 180:
rx, ry = self.frame_width - 1 - ox, self.frame_height - 1 - oy
elif angle == 270:
rx, ry = self.frame_height - 1 - oy, ox
else:
rx, ry = ox, oy
# Now account for crop/zoom/offset using unified params
params = self._get_display_params()
rx -= params['eff_x']
ry -= params['eff_y']
zx = rx * self.zoom_factor
zy = ry * self.zoom_factor
inframe_x = zx - params['offx']
inframe_y = zy - params['offy']
sx = int(round(params['start_x'] + inframe_x * params['scale']))
sy = int(round(params['start_y'] + inframe_y * params['scale']))
return sx, sy
def _map_screen_to_original(self, sx, sy):
"""Map a point on canvas screen coords back to original frame coords."""
frame_number = getattr(self, 'current_frame', 0)
angle = self.rotation_angle
ch, cw = self.frame_height, self.frame_width
# Zoomed dimensions
if angle in (90, 270):
rotated_w, rotated_h = ch, cw
else:
rotated_w, rotated_h = cw, ch
new_w = int(rotated_w * self.zoom_factor)
new_h = int(rotated_h * self.zoom_factor)
# Whether apply_crop_zoom_and_rotation cropped due to zoom
cropped_due_to_zoom = (self.zoom_factor != 1.0) and (new_w > self.window_width or new_h > self.window_height)
# Visible dims before canvas scaling
visible_w = new_w if not cropped_due_to_zoom else min(new_w, self.window_width)
visible_h = new_h if not cropped_due_to_zoom else min(new_h, self.window_height)
# Canvas scale and placement
available_height = self.window_height - (0 if self.is_image_mode else self.TIMELINE_HEIGHT)
scale_raw = min(self.window_width / max(1, visible_w), available_height / max(1, visible_h))
scale_canvas = scale_raw if scale_raw < 1.0 else 1.0
final_w = int(visible_w * scale_canvas)
final_h = int(visible_h * scale_canvas)
start_x_canvas = (self.window_width - final_w) // 2
start_y_canvas = (available_height - final_h) // 2
# Back to processed (zoomed+cropped) space
zx = (sx - start_x_canvas) / max(1e-6, scale_canvas)
zy = (sy - start_y_canvas) / max(1e-6, scale_canvas)
# Add display offset in zoomed space (only if cropped_due_to_zoom)
if cropped_due_to_zoom:
offx_max = max(0, new_w - self.window_width)
offy_max = max(0, new_h - self.window_height)
offx = max(0, min(int(self.display_offset[0]), offx_max))
offy = max(0, min(int(self.display_offset[1]), offy_max))
else:
offx = 0
offy = 0
zx += offx
zy += offy
# Reverse zoom
rx = zx / max(1e-6, self.zoom_factor)
ry = zy / max(1e-6, self.zoom_factor)
# Reverse crop in rotated space to get rotated coordinates
cx, cy, cw, ch = self._get_effective_crop_rect_for_frame(frame_number)
rx = rx + cx
ry = ry + cy
# Reverse rotation to original frame coords
if angle == 90:
ox, oy = self.frame_width - 1 - ry, rx
elif angle == 180:
ox, oy = self.frame_width - 1 - rx, self.frame_height - 1 - ry
elif angle == 270:
ox, oy = ry, self.frame_height - 1 - rx
else:
ox, oy = rx, ry
ox = max(0, min(int(round(ox)), self.frame_width - 1))
oy = max(0, min(int(round(oy)), self.frame_height - 1))
return ox, oy
def _map_rotated_to_screen(self, rx, ry): def _map_rotated_to_screen(self, rx, ry):
"""Map a point in ROTATED frame coords to canvas screen coords (post-crop).""" """Map a point in ROTATED frame coords to canvas screen coords (post-crop)."""
# Subtract crop offset in rotated space (EFFECTIVE crop at current frame) # Subtract crop offset in rotated space (EFFECTIVE crop at current frame)
@@ -2225,7 +2137,7 @@ class VideoEditor:
if not self.is_image_mode: if not self.is_image_mode:
# Store tracking points in ROTATED frame coordinates (pre-crop) # Store tracking points in ROTATED frame coordinates (pre-crop)
rx, ry = self._map_screen_to_rotated(x, y) rx, ry = self._map_screen_to_rotated(x, y)
threshold = 50 threshold = self.TRACKING_POINT_THRESHOLD
removed = False removed = False
# First check for removal of existing points on current frame # First check for removal of existing points on current frame
@@ -2247,7 +2159,7 @@ class VideoEditor:
if not removed: if not removed:
snapped = False snapped = False
# Check all tracking points from all frames for snapping # Check all tracking points from all frames for snapping
for frame_num, points in self.tracking_points.items(): for _, points in self.tracking_points.items():
for (px, py) in points: for (px, py) in points:
sxp, syp = self._map_rotated_to_screen(px, py) sxp, syp = self._map_rotated_to_screen(px, py)
if (sxp - x) ** 2 + (syp - y) ** 2 <= threshold ** 2: if (sxp - x) ** 2 + (syp - y) ** 2 <= threshold ** 2: