Snap to markers in the audio display on click in addition to on drag

Originally committed to SVN as r6237.
This commit is contained in:
Thomas Goyne 2012-01-08 01:35:11 +00:00
parent 4dcb6240d4
commit c84275d6fa
4 changed files with 55 additions and 44 deletions

View file

@ -511,8 +511,7 @@ public:
timing_controller->OnMarkerDrag( timing_controller->OnMarkerDrag(
marker, marker,
display->SamplesFromRelativeX(event.GetPosition().x), display->SamplesFromRelativeX(event.GetPosition().x),
default_snap != event.ShiftDown(), default_snap != event.ShiftDown() ? display->SamplesFromAbsoluteX(snap_range) : 0);
display->SamplesFromAbsoluteX(snap_range));
} }
// We lose the marker drag if the button used to initiate it goes up // We lose the marker drag if the button used to initiate it goes up
@ -1128,6 +1127,7 @@ void AudioDisplay::OnMouseEvent(wxMouseEvent& event)
AudioTimingController *timing = controller->GetTimingController(); AudioTimingController *timing = controller->GetTimingController();
if (!timing) return; if (!timing) return;
int drag_sensitivity = pixel_samples * OPT_GET("Audio/Start Drag Sensitivity")->GetInt(); int drag_sensitivity = pixel_samples * OPT_GET("Audio/Start Drag Sensitivity")->GetInt();
int snap_sensitivity = OPT_GET("Audio/Snap/Enable")->GetBool() != event.ShiftDown() ? pixel_samples * OPT_GET("Audio/Snap/Distance")->GetInt() : 0;
// Not scrollbar, not timeline, no button action // Not scrollbar, not timeline, no button action
if (event.Moving()) if (event.Moving())
@ -1144,8 +1144,8 @@ void AudioDisplay::OnMouseEvent(wxMouseEvent& event)
{ {
int64_t samplepos = SamplesFromRelativeX(mousepos.x); int64_t samplepos = SamplesFromRelativeX(mousepos.x);
AudioMarker *marker = event.LeftDown() ? AudioMarker *marker = event.LeftDown() ?
timing->OnLeftClick(samplepos, drag_sensitivity) : timing->OnLeftClick(samplepos, drag_sensitivity, snap_sensitivity) :
timing->OnRightClick(samplepos, drag_sensitivity); timing->OnRightClick(samplepos, drag_sensitivity, snap_sensitivity);
if (marker) if (marker)
{ {

View file

@ -125,25 +125,26 @@ public:
/// @brief The user pressed the left button down at an empty place in the audio /// @brief The user pressed the left button down at an empty place in the audio
/// @param sample The audio sample index the user clicked /// @param sample The audio sample index the user clicked
/// @param sensitivity Distance in samples to consider existing markers /// @param sensitivity Distance in samples to consider existing markers
/// @param snap_range Maximum snapping range in samples
/// @return An audio marker or 0. If a marker is returned and the user /// @return An audio marker or 0. If a marker is returned and the user
/// starts dragging the mouse after pressing down the button, the returned /// starts dragging the mouse after pressing down the button, the returned
/// marker is being dragged. /// marker is being dragged.
virtual AudioMarker * OnLeftClick(int64_t sample, int sensitivity) = 0; virtual AudioMarker * OnLeftClick(int64_t sample, int sensitivity, int64_t snap_range) = 0;
/// @brief The user pressed the right button down at an empty place in the audio /// @brief The user pressed the right button down at an empty place in the audio
/// @param sample The audio sample index the user clicked /// @param sample The audio sample index the user clicked
/// @param sensitivity Distance in samples to consider existing markers /// @param sensitivity Distance in samples to consider existing markers
/// @param snap_range Maximum snapping range in samples
/// @return An audio marker or 0. If a marker is returned and the user /// @return An audio marker or 0. If a marker is returned and the user
/// starts dragging the mouse after pressing down the button, the returned /// starts dragging the mouse after pressing down the button, the returned
/// marker is being dragged. /// marker is being dragged.
virtual AudioMarker * OnRightClick(int64_t sample, int sensitivity) = 0; virtual AudioMarker * OnRightClick(int64_t sample, int sensitivity, int64_t snap_range) = 0;
/// @brief The user dragged a timing marker /// @brief The user dragged a timing marker
/// @param marker The marker being dragged /// @param marker The marker being dragged
/// @param new_position Sample position the marker was dragged to /// @param new_position Sample position the marker was dragged to
/// @param snap Enable snapping to other markers
/// @param snap_range Maximum snapping range in samples /// @param snap_range Maximum snapping range in samples
virtual void OnMarkerDrag(AudioMarker *marker, int64_t new_position, bool snap, int64_t snap_range) = 0; virtual void OnMarkerDrag(AudioMarker *marker, int64_t new_position, int64_t snap_range) = 0;
/// @brief Destructor /// @brief Destructor
virtual ~AudioTimingController() { } virtual ~AudioTimingController() { }

View file

@ -80,7 +80,7 @@ public:
int64_t GetPosition() const { return position; } int64_t GetPosition() const { return position; }
wxPen GetStyle() const { return style; } wxPen GetStyle() const { return style; }
FeetStyle GetFeet() const { return feet; } FeetStyle GetFeet() const { return feet; }
bool CanSnap() const { return true; } bool CanSnap() const { return false; }
public: public:
// Specific interface // Specific interface
@ -197,6 +197,11 @@ class AudioTimingControllerDialogue : public AudioTimingController, private Sele
/// @param sample New position of the marker /// @param sample New position of the marker
void SetMarker(AudioMarkerDialogueTiming *marker, int64_t sample); void SetMarker(AudioMarkerDialogueTiming *marker, int64_t sample);
/// Snap a position to a nearby marker, if any
/// @param position Position to snap
/// @param snap_range Maximum distance to snap in samples
int64_t SnapPosition(int64_t position, int64_t snap_range) const;
// SubtitleSelectionListener interface // SubtitleSelectionListener interface
void OnActiveLineChanged(AssDialogue *new_line); void OnActiveLineChanged(AssDialogue *new_line);
void OnSelectedSetChanged(const Selection &lines_added, const Selection &lines_removed); void OnSelectedSetChanged(const Selection &lines_added, const Selection &lines_removed);
@ -220,9 +225,9 @@ public:
void Commit(); void Commit();
void Revert(); void Revert();
bool IsNearbyMarker(int64_t sample, int sensitivity) const; bool IsNearbyMarker(int64_t sample, int sensitivity) const;
AudioMarker * OnLeftClick(int64_t sample, int sensitivity); AudioMarker * OnLeftClick(int64_t sample, int sensitivity, int64_t snap_range);
AudioMarker * OnRightClick(int64_t sample, int sensitivity); AudioMarker * OnRightClick(int64_t sample, int sensitivity, int64_t snap_range);
void OnMarkerDrag(AudioMarker *marker, int64_t new_position, bool snap, int64_t snap_range); void OnMarkerDrag(AudioMarker *marker, int64_t new_position, int64_t snap_range);
public: public:
// Specific interface // Specific interface
@ -481,7 +486,7 @@ bool AudioTimingControllerDialogue::IsNearbyMarker(int64_t sample, int sensitivi
return range.contains(active_markers[0]) || range.contains(active_markers[1]); return range.contains(active_markers[0]) || range.contains(active_markers[1]);
} }
AudioMarker * AudioTimingControllerDialogue::OnLeftClick(int64_t sample, int sensitivity) AudioMarker * AudioTimingControllerDialogue::OnLeftClick(int64_t sample, int sensitivity, int64_t snap_range)
{ {
assert(sensitivity >= 0); assert(sensitivity >= 0);
@ -497,7 +502,7 @@ AudioMarker * AudioTimingControllerDialogue::OnLeftClick(int64_t sample, int sen
{ {
// Clicked near the left marker: // Clicked near the left marker:
// Insta-move it and start dragging it // Insta-move it and start dragging it
SetMarker(left, sample); SetMarker(left, SnapPosition(sample, snap_range));
return left; return left;
} }
@ -511,42 +516,22 @@ AudioMarker * AudioTimingControllerDialogue::OnLeftClick(int64_t sample, int sen
// Clicked far from either marker: // Clicked far from either marker:
// Insta-set the left marker to the clicked position and return the right as the dragged one, // Insta-set the left marker to the clicked position and return the right as the dragged one,
// such that if the user does start dragging, he will create a new selection from scratch // such that if the user does start dragging, he will create a new selection from scratch
SetMarker(left, sample); SetMarker(left, SnapPosition(sample, snap_range));
return right; return right;
} }
AudioMarker * AudioTimingControllerDialogue::OnRightClick(int64_t sample, int sensitivity) AudioMarker * AudioTimingControllerDialogue::OnRightClick(int64_t sample, int sensitivity, int64_t snap_range)
{ {
AudioMarkerDialogueTiming *right = GetRightMarker(); AudioMarkerDialogueTiming *right = GetRightMarker();
SetMarker(right, sample); SetMarker(right, SnapPosition(sample, snap_range));
return right; return right;
} }
void AudioTimingControllerDialogue::OnMarkerDrag(AudioMarker *marker, int64_t new_position, bool snap, int64_t snap_range) void AudioTimingControllerDialogue::OnMarkerDrag(AudioMarker *marker, int64_t new_position, int64_t snap_range)
{ {
assert(marker == &active_markers[0] || marker == &active_markers[1]); assert(marker == &active_markers[0] || marker == &active_markers[1]);
if (snap) SetMarker(static_cast<AudioMarkerDialogueTiming*>(marker), SnapPosition(new_position, snap_range));
{
SampleRange snap_sample_range(new_position - snap_range, new_position + snap_range);
const AudioMarker *snap_marker = 0;
AudioMarkerVector potential_snaps;
GetMarkers(snap_sample_range, potential_snaps);
for (AudioMarkerVector::iterator mi = potential_snaps.begin(); mi != potential_snaps.end(); ++mi)
{
if (*mi != marker && (*mi)->CanSnap())
{
if (!snap_marker)
snap_marker = *mi;
else if (tabs((*mi)->GetPosition() - new_position) < tabs(snap_marker->GetPosition() - new_position))
snap_marker = *mi;
}
}
if (snap_marker)
new_position = snap_marker->GetPosition();
}
SetMarker(static_cast<AudioMarkerDialogueTiming*>(marker), new_position);
} }
void AudioTimingControllerDialogue::UpdateSelection() void AudioTimingControllerDialogue::UpdateSelection()
@ -606,3 +591,28 @@ void AudioTimingControllerDialogue::RegenerateInactiveLines()
} }
AnnounceUpdatedStyleRanges(); AnnounceUpdatedStyleRanges();
} }
int64_t AudioTimingControllerDialogue::SnapPosition(int64_t position, int64_t snap_range) const
{
if (snap_range <= 0)
return position;
SampleRange snap_sample_range(position - snap_range, position + snap_range);
const AudioMarker *snap_marker = 0;
AudioMarkerVector potential_snaps;
GetMarkers(snap_sample_range, potential_snaps);
for (AudioMarkerVector::iterator mi = potential_snaps.begin(); mi != potential_snaps.end(); ++mi)
{
if ((*mi)->CanSnap())
{
if (!snap_marker)
snap_marker = *mi;
else if (tabs((*mi)->GetPosition() - position) < tabs(snap_marker->GetPosition() - position))
snap_marker = *mi;
}
}
if (snap_marker)
return snap_marker->GetPosition();
return position;
}

View file

@ -130,9 +130,9 @@ public:
void Commit(); void Commit();
void Revert(); void Revert();
bool IsNearbyMarker(int64_t sample, int sensitivity) const; bool IsNearbyMarker(int64_t sample, int sensitivity) const;
AudioMarker * OnLeftClick(int64_t sample, int sensitivity); AudioMarker * OnLeftClick(int64_t sample, int sensitivity, int64_t);
AudioMarker * OnRightClick(int64_t sample, int sensitivity) { return 0; } AudioMarker * OnRightClick(int64_t, int, int64_t) { return 0; }
void OnMarkerDrag(AudioMarker *marker, int64_t new_position, bool, int64_t); void OnMarkerDrag(AudioMarker *marker, int64_t new_position, int64_t);
AudioTimingControllerKaraoke(agi::Context *c, AssKaraoke *kara, agi::signal::Connection& file_changed); AudioTimingControllerKaraoke(agi::Context *c, AssKaraoke *kara, agi::signal::Connection& file_changed);
}; };
@ -284,7 +284,7 @@ bool AudioTimingControllerKaraoke::IsNearbyMarker(int64_t sample, int sensitivit
return false; return false;
} }
AudioMarker *AudioTimingControllerKaraoke::OnLeftClick(int64_t sample, int sensitivity) { AudioMarker *AudioTimingControllerKaraoke::OnLeftClick(int64_t sample, int sensitivity, int64_t) {
SampleRange range(sample - sensitivity, sample + sensitivity); SampleRange range(sample - sensitivity, sample + sensitivity);
size_t syl = distance(markers.begin(), lower_bound(markers.begin(), markers.end(), sample)); size_t syl = distance(markers.begin(), lower_bound(markers.begin(), markers.end(), sample));
@ -301,7 +301,7 @@ AudioMarker *AudioTimingControllerKaraoke::OnLeftClick(int64_t sample, int sensi
return 0; return 0;
} }
void AudioTimingControllerKaraoke::OnMarkerDrag(AudioMarker *m, int64_t new_position, bool, int64_t) { void AudioTimingControllerKaraoke::OnMarkerDrag(AudioMarker *m, int64_t new_position, int64_t) {
KaraokeMarker *marker = static_cast<KaraokeMarker*>(m); KaraokeMarker *marker = static_cast<KaraokeMarker*>(m);
// No rearranging of syllables allowed // No rearranging of syllables allowed
new_position = mid( new_position = mid(