diff --git a/release/scripts/presets/keyconfig/keymap_data/blender_default.py b/release/scripts/presets/keyconfig/keymap_data/blender_default.py index d08786e6ba8..1228c6e4298 100644 --- a/release/scripts/presets/keyconfig/keymap_data/blender_default.py +++ b/release/scripts/presets/keyconfig/keymap_data/blender_default.py @@ -960,7 +960,7 @@ def km_mask_editing(params): ("mask.select_more", {"type": 'NUMPAD_PLUS', "value": 'PRESS', "ctrl": True, "repeat": True}, None), ("mask.select_less", {"type": 'NUMPAD_MINUS', "value": 'PRESS', "ctrl": True, "repeat": True}, None), *_template_items_hide_reveal_actions("mask.hide_view_set", "mask.hide_view_clear"), - ("clip.select", {"type": params.select_mouse, "value": 'PRESS', "ctrl": True}, None), + # ("clip.select", {"type": params.select_mouse, "value": 'PRESS', "ctrl": True}, None), ("mask.cyclic_toggle", {"type": 'C', "value": 'PRESS', "alt": True}, None), ("mask.handle_type_set", {"type": 'V', "value": 'PRESS'}, None), ("mask.normals_make_consistent", @@ -3188,10 +3188,10 @@ def km_clip_editor(params): ("clip.frame_jump", {"type": 'RIGHT_ARROW', "value": 'PRESS', "shift": True, "alt": True, "repeat": True}, {"properties": [("position", 'PATHSTART')]}), ("clip.change_frame", {"type": 'LEFTMOUSE', "value": 'PRESS'}, None), - ("clip.select", {"type": params.select_mouse, "value": 'PRESS'}, - {"properties": [("deselect_all", not params.legacy)]}), - ("clip.select", {"type": params.select_mouse, "value": 'PRESS', "shift": True}, - {"properties": [("extend", True)]}), + # ("clip.select", {"type": params.select_mouse, "value": 'PRESS'}, + # {"properties": [("deselect_all", not params.legacy)]}), + # ("clip.select", {"type": params.select_mouse, "value": 'PRESS', "shift": True}, + # {"properties": [("extend", True)]}), *_template_items_select_actions(params, "clip.select_all"), ("clip.select_box", {"type": 'B', "value": 'PRESS'}, None), ("clip.select_circle", {"type": 'C', "value": 'PRESS'}, None), @@ -6623,6 +6623,8 @@ def _template_items_clip_tool_tweak_selection(params): ("deselect_all", True), ("activate_selected", params.select_mouse == 'LEFTMOUSE')]} ), + ("clip.select", {"type": params.select_mouse, "value": 'PRESS', "shift": True}, + {"properties": [("extend", True)]}), ] if params.select_mouse == 'RIGHTMOUSE': diff --git a/source/blender/editors/space_clip/tracking_select.c b/source/blender/editors/space_clip/tracking_select.c index b6d458a7780..cca09e7f049 100644 --- a/source/blender/editors/space_clip/tracking_select.c +++ b/source/blender/editors/space_clip/tracking_select.c @@ -11,6 +11,7 @@ #include "DNA_scene_types.h" #include "BLI_lasso_2d.h" +#include "BLI_listbase.h" #include "BLI_math.h" #include "BLI_rect.h" #include "BLI_utildefines.h" @@ -36,226 +37,432 @@ #include "clip_intern.h" /* own include */ #include "tracking_ops_intern.h" /* own include */ -static float dist_to_crns(const float co[2], const float pos[2], const float crns[4][2]); +/* -------------------------------------------------------------------- */ +/** \name Point track marker picking. + * \{ */ -/********************** mouse select operator *********************/ +typedef enum eTrackPickAreaDetail { + TRACK_PICK_AREA_DETAIL_NONE, + + /* Position of the marker (when area is TRACK_AREA_POINT). + * Position of the pattern corner when area is TRACK_AREA_PAT and corner != -1. */ + TRACK_PICK_AREA_DETAIL_POSITION, + + /* Size and offset of the search area. */ + TRACK_PICK_AREA_DETAIL_SIZE, + TRACK_PICK_AREA_DETAIL_OFFSET, + + /* "Widget" used to define pattern rotation and scale. */ + TRACK_PICK_AREA_DETAIL_TILT_SIZE, + + /* Edge of pattern or search area. */ + TRACK_PICK_AREA_DETAIL_EDGE, +} eTrackPickAreaDetail; + +typedef struct TrackPickResult { + MovieTrackingTrack *track; + MovieTrackingMarker *marker; -static int mouse_on_side( - const float co[2], float x1, float y1, float x2, float y2, float epsx, float epsy) + /* Picked area of the track. Is a single element from eTrackArea (no multiple choices are + * possible). */ + eTrackArea area; + eTrackPickAreaDetail area_detail; + + /* When a pattern corner is picked is 0-based index of the corner. + * Otherwise is -1. */ + int corner_index; + + /* Distance to the pick measured in squared pixels. */ + float distance_px_squared; +} TrackPickResult; + +BLI_INLINE TrackPickResult track_pick_result_make_null(void) { - if (x1 > x2) { - SWAP(float, x1, x2); - } + TrackPickResult result = {NULL}; + + result.area = TRACK_AREA_NONE; + result.area_detail = TRACK_PICK_AREA_DETAIL_NONE; + result.corner_index = -1; + result.distance_px_squared = FLT_MAX; + + return result; +} - if (y1 > y2) { - SWAP(float, y1, y2); +BLI_INLINE bool track_pick_result_can_slide(const TrackPickResult *pick_result) +{ + if (pick_result->marker == NULL) { + return false; } - return (co[0] >= x1 - epsx && co[0] <= x2 + epsx) && (co[1] >= y1 - epsy && co[1] <= y2 + epsy); + return pick_result->area_detail != TRACK_PICK_AREA_DETAIL_EDGE; } -static int mouse_on_rect(const float co[2], - const float pos[2], - const float min[2], - const float max[2], - float epsx, - float epsy) +static void slide_marker_tilt_slider_relative(const float pattern_corners[4][2], float r_slider[2]) { - return mouse_on_side( - co, pos[0] + min[0], pos[1] + min[1], pos[0] + max[0], pos[1] + min[1], epsx, epsy) || - mouse_on_side( - co, pos[0] + min[0], pos[1] + min[1], pos[0] + min[0], pos[1] + max[1], epsx, epsy) || - mouse_on_side( - co, pos[0] + min[0], pos[1] + max[1], pos[0] + max[0], pos[1] + max[1], epsx, epsy) || - mouse_on_side( - co, pos[0] + max[0], pos[1] + min[1], pos[0] + max[0], pos[1] + max[1], epsx, epsy); + add_v2_v2v2(r_slider, pattern_corners[1], pattern_corners[2]); } -static int mouse_on_crns( - const float co[2], const float pos[2], const float crns[4][2], float epsx, float epsy) +static void slide_marker_tilt_slider(const float marker_pos[2], + const float pattern_corners[4][2], + float r_slider[2]) { - float dist = dist_to_crns(co, pos, crns); + slide_marker_tilt_slider_relative(pattern_corners, r_slider); + add_v2_v2(r_slider, marker_pos); +} - return dist < max_ff(epsx, epsy); +static float mouse_to_slide_zone_distance_squared(const float co[2], + const float slide_zone[2], + int width, + int height) +{ + const float pixel_co[2] = {co[0] * width, co[1] * height}, + pixel_slide_zone[2] = {slide_zone[0] * width, slide_zone[1] * height}; + return square_f(pixel_co[0] - pixel_slide_zone[0]) + square_f(pixel_co[1] - pixel_slide_zone[1]); } -static int track_mouse_area(const bContext *C, const float co[2], MovieTrackingTrack *track) +static float mouse_to_search_corner_distance_squared( + const MovieTrackingMarker *marker, const float co[2], int corner, int width, int height) { - SpaceClip *sc = CTX_wm_space_clip(C); - int framenr = ED_space_clip_get_clip_frame_number(sc); - MovieTrackingMarker *marker = BKE_tracking_marker_get(track, framenr); - float pat_min[2], pat_max[2]; - float epsx, epsy; - int width, height; + float side_zone[2]; + if (corner == 0) { + side_zone[0] = marker->pos[0] + marker->search_max[0]; + side_zone[1] = marker->pos[1] + marker->search_min[1]; + } + else { + side_zone[0] = marker->pos[0] + marker->search_min[0]; + side_zone[1] = marker->pos[1] + marker->search_max[1]; + } + return mouse_to_slide_zone_distance_squared(co, side_zone, width, height); +} - ED_space_clip_get_size(sc, &width, &height); +static float mouse_to_closest_pattern_corner_distance_squared( + const MovieTrackingMarker *marker, const float co[2], int width, int height, int *r_corner) +{ + float min_distance_squared = FLT_MAX; + for (int i = 0; i < 4; i++) { + float corner_co[2]; + add_v2_v2v2(corner_co, marker->pattern_corners[i], marker->pos); + float distance_squared = mouse_to_slide_zone_distance_squared(co, corner_co, width, height); + if (distance_squared < min_distance_squared) { + min_distance_squared = distance_squared; + *r_corner = i; + } + } + return min_distance_squared; +} + +static float mouse_to_offset_distance_squared(const MovieTrackingTrack *track, + const MovieTrackingMarker *marker, + const float co[2], + int width, + int height) +{ + float pos[2]; + add_v2_v2v2(pos, marker->pos, track->offset); + return mouse_to_slide_zone_distance_squared(co, pos, width, height); +} - BKE_tracking_marker_pattern_minmax(marker, pat_min, pat_max); +static float mouse_to_tilt_distance_squared(const MovieTrackingMarker *marker, + const float co[2], + int width, + int height) +{ + float slider[2]; + slide_marker_tilt_slider(marker->pos, marker->pattern_corners, slider); + return mouse_to_slide_zone_distance_squared(co, slider, width, height); +} - epsx = min_ffff(pat_min[0] - marker->search_min[0], - marker->search_max[0] - pat_max[0], - fabsf(pat_min[0]), - fabsf(pat_max[0])) / - 2; - epsy = min_ffff(pat_min[1] - marker->search_min[1], - marker->search_max[1] - pat_max[1], - fabsf(pat_min[1]), - fabsf(pat_max[1])) / - 2; +static float mouse_to_closest_corners_edge_distance_squared(const float co[2], + const float corners_offset[2], + const float corners[4][2], + int width, + int height) +{ + const float co_px[2] = {co[0] * width, co[1] * height}; - epsx = max_ff(epsx, 2.0f / width); - epsy = max_ff(epsy, 2.0f / height); + float prev_corner_co_px[2]; + add_v2_v2v2(prev_corner_co_px, corners_offset, corners[3]); + prev_corner_co_px[0] *= width; + prev_corner_co_px[1] *= height; - if (sc->flag & SC_SHOW_MARKER_SEARCH) { - if (mouse_on_rect(co, marker->pos, marker->search_min, marker->search_max, epsx, epsy)) { - return TRACK_AREA_SEARCH; - } - } + float min_distance_squared = FLT_MAX; - if ((marker->flag & MARKER_DISABLED) == 0) { - if (sc->flag & SC_SHOW_MARKER_PATTERN) { - if (mouse_on_crns(co, marker->pos, marker->pattern_corners, epsx, epsy)) { - return TRACK_AREA_PAT; - } - } + for (int i = 0; i < 4; ++i) { + float corner_co_px[2]; + add_v2_v2v2(corner_co_px, corners_offset, corners[i]); + corner_co_px[0] *= width; + corner_co_px[1] *= height; - epsx = 12.0f / width; - epsy = 12.0f / height; + const float distance_squared = dist_squared_to_line_segment_v2( + co_px, corner_co_px, prev_corner_co_px); - if (fabsf(co[0] - marker->pos[0] - track->offset[0]) < epsx && - fabsf(co[1] - marker->pos[1] - track->offset[1]) <= epsy) { - return TRACK_AREA_POINT; + if (distance_squared < min_distance_squared) { + min_distance_squared = distance_squared; } + + copy_v2_v2(prev_corner_co_px, corner_co_px); } - return TRACK_AREA_NONE; + return min_distance_squared; } -static float dist_to_rect(const float co[2], - const float pos[2], - const float min[2], - const float max[2]) +static float mouse_to_closest_pattern_edge_distance_squared(const MovieTrackingMarker *marker, + const float co[2], + int width, + int height) { - float d1, d2, d3, d4; - const float p[2] = {co[0] - pos[0], co[1] - pos[1]}; - const float v1[2] = {min[0], min[1]}, v2[2] = {max[0], min[1]}; - const float v3[2] = {max[0], max[1]}, v4[2] = {min[0], max[1]}; + return mouse_to_closest_corners_edge_distance_squared( + co, marker->pos, marker->pattern_corners, width, height); +} - d1 = dist_squared_to_line_segment_v2(p, v1, v2); - d2 = dist_squared_to_line_segment_v2(p, v2, v3); - d3 = dist_squared_to_line_segment_v2(p, v3, v4); - d4 = dist_squared_to_line_segment_v2(p, v4, v1); +static float mouse_to_closest_search_edge_distance_squared(const MovieTrackingMarker *marker, + const float co[2], + int width, + int height) +{ + const float corners[4][2] = { + {marker->search_min[0], marker->search_min[1]}, + {marker->search_max[0], marker->search_min[1]}, + {marker->search_max[0], marker->search_max[1]}, + {marker->search_min[0], marker->search_max[1]}, + }; - return sqrtf(min_ffff(d1, d2, d3, d4)); + return mouse_to_closest_corners_edge_distance_squared(co, marker->pos, corners, width, height); } -/* Distance to quad defined by its corners, corners are relative to pos */ -static float dist_to_crns(const float co[2], const float pos[2], const float crns[4][2]) +static TrackPickResult tracking_pick_point_track(bContext *C, const float co[2]) { - float d1, d2, d3, d4; - const float p[2] = {co[0] - pos[0], co[1] - pos[1]}; - const float *v1 = crns[0], *v2 = crns[1]; - const float *v3 = crns[2], *v4 = crns[3]; + SpaceClip *space_clip = CTX_wm_space_clip(C); + + int width, height; + ED_space_clip_get_size(space_clip, &width, &height); + if (width == 0 || height == 0) { + return track_pick_result_make_null(); + } - d1 = dist_squared_to_line_segment_v2(p, v1, v2); - d2 = dist_squared_to_line_segment_v2(p, v2, v3); - d3 = dist_squared_to_line_segment_v2(p, v3, v4); - d4 = dist_squared_to_line_segment_v2(p, v4, v1); + MovieClip *clip = ED_space_clip_get_clip(space_clip); + ListBase *tracks_base = BKE_tracking_get_active_tracks(&clip->tracking); + const int framenr = ED_space_clip_get_clip_frame_number(space_clip); + + const float distance_tolerance_px_squared = (12.0f * 12.0f) / space_clip->zoom; + TrackPickResult pick_result = track_pick_result_make_null(); + + LISTBASE_FOREACH (MovieTrackingTrack *, track, tracks_base) { + const bool is_track_selected = TRACK_VIEW_SELECTED(space_clip, track); + + // XXX + // if (!TRACK_VIEW_SELECTED(space_clip, track) || (track->flag & TRACK_LOCKED)) { + // continue; + // } + + MovieTrackingMarker *marker = BKE_tracking_marker_get(track, framenr); + // XXX + // if (marker->flag & MARKER_DISABLED) { + // continue; + // } + + float distance_squared; + + /* Initialize the current pick with the offset point of the track. */ + TrackPickResult current_pick = track_pick_result_make_null(); + current_pick.track = track; + current_pick.marker = marker; + current_pick.area = TRACK_AREA_POINT; + current_pick.distance_px_squared = mouse_to_offset_distance_squared( + track, marker, co, width, height); + + /* If search area is visible, check how close to its sliding zones mouse is. */ + if (is_track_selected && (space_clip->flag & SC_SHOW_MARKER_SEARCH)) { + distance_squared = mouse_to_search_corner_distance_squared(marker, co, 1, width, height); + if (distance_squared < current_pick.distance_px_squared) { + current_pick.area = TRACK_AREA_SEARCH; + current_pick.area_detail = TRACK_PICK_AREA_DETAIL_OFFSET; + current_pick.distance_px_squared = distance_squared; + } - return sqrtf(min_ffff(d1, d2, d3, d4)); -} + distance_squared = mouse_to_search_corner_distance_squared(marker, co, 0, width, height); + if (distance_squared < current_pick.distance_px_squared) { + current_pick.area = TRACK_AREA_SEARCH; + current_pick.area_detail = TRACK_PICK_AREA_DETAIL_SIZE; + current_pick.distance_px_squared = distance_squared; + } + } -/* Same as above, but all the coordinates are absolute */ -static float dist_to_crns_abs(const float co[2], const float corners[4][2]) -{ - float d1, d2, d3, d4; - const float *v1 = corners[0], *v2 = corners[1]; - const float *v3 = corners[2], *v4 = corners[3]; + /* If pattern area is visible, check which corner is closest to the mouse. */ + if (space_clip->flag & SC_SHOW_MARKER_PATTERN) { + int current_corner = -1; + distance_squared = mouse_to_closest_pattern_corner_distance_squared( + marker, co, width, height, ¤t_corner); + if (distance_squared < current_pick.distance_px_squared) { + current_pick.area = TRACK_AREA_PAT; + current_pick.area_detail = TRACK_PICK_AREA_DETAIL_POSITION; + current_pick.corner_index = current_corner; + current_pick.distance_px_squared = distance_squared; + } - d1 = dist_squared_to_line_segment_v2(co, v1, v2); - d2 = dist_squared_to_line_segment_v2(co, v2, v3); - d3 = dist_squared_to_line_segment_v2(co, v3, v4); - d4 = dist_squared_to_line_segment_v2(co, v4, v1); + /* Here we also check whether the mouse is actually closer to the widget which controls scale + * and tilt. */ + // XXX: Support for Slide Marker. + if (false) { + distance_squared = mouse_to_tilt_distance_squared(marker, co, width, height); + if (distance_squared < current_pick.distance_px_squared) { + current_pick.area = TRACK_AREA_PAT; + current_pick.area_detail = TRACK_PICK_AREA_DETAIL_TILT_SIZE; + current_pick.distance_px_squared = distance_squared; + } + } + } - return sqrtf(min_ffff(d1, d2, d3, d4)); + /* Whenever a manipulation "widgets" are not within distance tolerance test the edges as well. + * This allows to pick tracks by clicking on the pattern/search areas edges but prefer to use + * more actionable "widget" for sliding. */ + if (current_pick.distance_px_squared > distance_tolerance_px_squared) { + if (is_track_selected && (space_clip->flag & SC_SHOW_MARKER_SEARCH)) { + distance_squared = mouse_to_closest_search_edge_distance_squared( + marker, co, width, height); + if (distance_squared < current_pick.distance_px_squared) { + current_pick.area = TRACK_AREA_SEARCH; + current_pick.area_detail = TRACK_PICK_AREA_DETAIL_EDGE; + current_pick.distance_px_squared = distance_squared; + } + } + + if (space_clip->flag & SC_SHOW_MARKER_PATTERN) { + distance_squared = mouse_to_closest_pattern_edge_distance_squared( + marker, co, width, height); + if (distance_squared < current_pick.distance_px_squared) { + current_pick.area = TRACK_AREA_PAT; + current_pick.area_detail = TRACK_PICK_AREA_DETAIL_EDGE; + current_pick.distance_px_squared = distance_squared; + } + } + } + + if (current_pick.distance_px_squared < pick_result.distance_px_squared) { + pick_result = current_pick; + } + } + + if (pick_result.distance_px_squared > distance_tolerance_px_squared) { + return track_pick_result_make_null(); + } + + return pick_result; } -static MovieTrackingTrack *find_nearest_track(SpaceClip *sc, - ListBase *tracksbase, - const float co[2], - float *r_distance) -{ - MovieTrackingTrack *track = NULL, *cur; - float mindist = 0.0f; - int framenr = ED_space_clip_get_clip_frame_number(sc); +/** \} */ - cur = tracksbase->first; - while (cur) { - MovieTrackingMarker *marker = BKE_tracking_marker_get(cur, framenr); +/* -------------------------------------------------------------------- */ +/** \name Plane track marker picking. + * \{ */ - if (((cur->flag & TRACK_HIDDEN) == 0) && MARKER_VISIBLE(sc, cur, marker)) { - float dist, d1, d2 = FLT_MAX, d3 = FLT_MAX; +typedef struct PlaneTrackPickResult { + MovieTrackingPlaneTrack *plane_track; + MovieTrackingPlaneMarker *plane_marker; - /* distance to marker point */ - d1 = sqrtf( - (co[0] - marker->pos[0] - cur->offset[0]) * (co[0] - marker->pos[0] - cur->offset[0]) + - (co[1] - marker->pos[1] - cur->offset[1]) * (co[1] - marker->pos[1] - cur->offset[1])); + /* When not equal to -1 denotes the index of the corner which was the closest to the requested + * coordinate. */ + int corner_index; - /* distance to pattern boundbox */ - if (sc->flag & SC_SHOW_MARKER_PATTERN) { - d2 = dist_to_crns(co, marker->pos, marker->pattern_corners); - } + /* Distance to the pick measured in squared pixels. */ + float distance_px_squared; +} PlaneTrackPickResult; - /* distance to search boundbox */ - if (sc->flag & SC_SHOW_MARKER_SEARCH && TRACK_VIEW_SELECTED(sc, cur)) { - d3 = dist_to_rect(co, marker->pos, marker->search_min, marker->search_max); - } +BLI_INLINE PlaneTrackPickResult plane_track_pick_result_make_null(void) +{ + PlaneTrackPickResult result = {NULL}; - /* choose minimal distance. useful for cases of overlapped markers. */ - dist = min_fff(d1, d2, d3); + result.corner_index = -1; + result.distance_px_squared = FLT_MAX; - if (track == NULL || dist < mindist) { - track = cur; - mindist = dist; - } - } + return result; +} - cur = cur->next; +BLI_INLINE bool plane_track_pick_result_can_slide(const PlaneTrackPickResult *pick_result) +{ + if (pick_result->plane_marker == NULL) { + return false; } - *r_distance = mindist; + return pick_result->corner_index != -1; +} - return track; +static float mouse_to_plane_slide_zone_distance_squared(const float co[2], + const float slide_zone[2], + int width, + int height) +{ + const float pixel_co[2] = {co[0] * width, co[1] * height}; + const float pixel_slide_zone[2] = {slide_zone[0] * width, slide_zone[1] * height}; + return square_f(pixel_co[0] - pixel_slide_zone[0]) + square_f(pixel_co[1] - pixel_slide_zone[1]); } -static MovieTrackingPlaneTrack *find_nearest_plane_track(SpaceClip *sc, - ListBase *plane_tracks_base, - const float co[2], - float *r_distance) +static PlaneTrackPickResult tracking_pick_plane_track(bContext *C, const float co[2]) { - MovieTrackingPlaneTrack *plane_track = NULL, *current_plane_track; - float min_distance = 0.0f; - int framenr = ED_space_clip_get_clip_frame_number(sc); + SpaceClip *space_clip = CTX_wm_space_clip(C); + + int width, height; + ED_space_clip_get_size(space_clip, &width, &height); + if (width == 0 || height == 0) { + return plane_track_pick_result_make_null(); + } + + MovieClip *clip = ED_space_clip_get_clip(space_clip); + ListBase *plane_tracks_base = BKE_tracking_get_active_plane_tracks(&clip->tracking); + const int framenr = ED_space_clip_get_clip_frame_number(space_clip); + + const float distance_tolerance_px_squared = (12.0f * 12.0f) / space_clip->zoom; + PlaneTrackPickResult pick_result = plane_track_pick_result_make_null(); + + for (MovieTrackingPlaneTrack *plane_track = plane_tracks_base->first; plane_track != NULL; + plane_track = plane_track->next) { + // XXX: + // if (!PLANE_TRACK_VIEW_SELECTED(plane_track)) { + // continue; + // } - for (current_plane_track = plane_tracks_base->first; current_plane_track; - current_plane_track = current_plane_track->next) { - MovieTrackingPlaneMarker *plane_marker = BKE_tracking_plane_marker_get(current_plane_track, - framenr); + MovieTrackingPlaneMarker *plane_marker = BKE_tracking_plane_marker_get(plane_track, framenr); - if ((current_plane_track->flag & TRACK_HIDDEN) == 0) { - float distance = dist_to_crns_abs(co, plane_marker->corners); - if (plane_track == NULL || distance < min_distance) { - plane_track = current_plane_track; - min_distance = distance; + PlaneTrackPickResult current_pick = plane_track_pick_result_make_null(); + current_pick.plane_track = plane_track; + current_pick.plane_marker = plane_marker; + + for (int i = 0; i < 4; i++) { + const float distance_squared = mouse_to_plane_slide_zone_distance_squared( + co, plane_marker->corners[i], width, height); + + if (distance_squared < current_pick.distance_px_squared) { + current_pick.corner_index = i; + current_pick.distance_px_squared = distance_squared; + } + } + + if (current_pick.distance_px_squared > distance_tolerance_px_squared) { + const float zero_offset[2] = {0.0f, 0.0f}; + const float distance_squared = mouse_to_closest_corners_edge_distance_squared( + co, zero_offset, plane_marker->corners, width, height); + if (distance_squared < current_pick.distance_px_squared) { + current_pick.corner_index = -1; + current_pick.distance_px_squared = distance_squared; } } + + if (current_pick.distance_px_squared < pick_result.distance_px_squared) { + pick_result = current_pick; + } } - *r_distance = min_distance; + if (pick_result.distance_px_squared > distance_tolerance_px_squared) { + return plane_track_pick_result_make_null(); + } - return plane_track; + return pick_result; } +/** \} */ + +/********************** mouse select operator *********************/ + void ed_tracking_deselect_all_tracks(ListBase *tracks_base) { MovieTrackingTrack *track; @@ -303,6 +510,7 @@ static int select_exec(bContext *C, wmOperator *op) * operator can be used immediately after. * This logic makes it convenient to slide markers when left mouse selection is used. Without it * selection will be lost which causes inconvenience for the VFX artist. */ + // XXX: Find a better way (maybe via track_pick_result_can_slide). Also, support plane tracks. const bool activate_selected = RNA_boolean_get(op->ptr, "activate_selected"); if (activate_selected) { MovieTrackingTrack *track = tracking_find_slidable_track_in_proximity(C, co); @@ -318,40 +526,20 @@ static int select_exec(bContext *C, wmOperator *op) } } - float distance_to_track, distance_to_plane_track; - - MovieTrackingTrack *track = find_nearest_track(sc, tracksbase, co, &distance_to_track); - MovieTrackingPlaneTrack *plane_track = find_nearest_plane_track( - sc, plane_tracks_base, co, &distance_to_plane_track); + const TrackPickResult track_pick = tracking_pick_point_track(C, co); + const PlaneTrackPickResult plane_track_pick = tracking_pick_plane_track(C, co); ClipViewLockState lock_state; ED_clip_view_lock_state_store(C, &lock_state); - /* Do not select beyond some reasonable distance, that is useless and - * prevents the 'deselect on nothing' behavior. */ - if (distance_to_track > 0.05f) { - track = NULL; - } - if (distance_to_plane_track > 0.05f) { - plane_track = NULL; - } - - /* Between track and plane we choose closest to the mouse for selection here. */ - if (track && plane_track) { - if (distance_to_track < distance_to_plane_track) { - plane_track = NULL; - } - else { - track = NULL; - } - } - - if (track) { + if (track_pick.track != NULL || + track_pick.distance_px_squared < plane_track_pick.distance_px_squared) { if (!extend) { ed_tracking_deselect_all_plane_tracks(plane_tracks_base); } - int area = track_mouse_area(C, co, track); + MovieTrackingTrack *track = track_pick.track; + int area = track_pick.area; if (!extend || !TRACK_VIEW_SELECTED(sc, track)) { area = TRACK_AREA_ALL; @@ -376,11 +564,13 @@ static int select_exec(bContext *C, wmOperator *op) clip->tracking.act_plane_track = NULL; } } - else if (plane_track) { + else if (plane_track_pick.plane_track != NULL) { if (!extend) { ed_tracking_deselect_all_tracks(tracksbase); } + MovieTrackingPlaneTrack *plane_track = plane_track_pick.plane_track; + if (PLANE_TRACK_VIEW_SELECTED(plane_track)) { if (extend) { plane_track->flag &= ~SELECT; @@ -407,6 +597,22 @@ static int select_exec(bContext *C, wmOperator *op) WM_event_add_notifier(C, NC_GEOM | ND_SELECT, NULL); DEG_id_tag_update(&clip->id, ID_RECALC_SELECT); + /* This is a bit implicit, but when the selection operator is used from a LMB Add Marker and + * tweak tool we do not want the pass-through here and only want selection to happen. This way + * the selection operator will not fall-through to Add Marker operator. */ + if (activate_selected) { + if (track_pick_result_can_slide(&track_pick) || + plane_track_pick_result_can_slide(&plane_track_pick)) { + return OPERATOR_FINISHED | OPERATOR_PASS_THROUGH; + } + + if (track_pick.track == NULL && plane_track_pick.plane_track == NULL) { + return OPERATOR_FINISHED | OPERATOR_PASS_THROUGH; + } + + return OPERATOR_FINISHED; + } + /* Pass-through + finished to allow tweak to transform. */ return OPERATOR_FINISHED | OPERATOR_PASS_THROUGH; }