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(
marker,
display->SamplesFromRelativeX(event.GetPosition().x),
default_snap != event.ShiftDown(),
display->SamplesFromAbsoluteX(snap_range));
default_snap != event.ShiftDown() ? display->SamplesFromAbsoluteX(snap_range) : 0);
}
// 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();
if (!timing) return;
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
if (event.Moving())
@ -1144,8 +1144,8 @@ void AudioDisplay::OnMouseEvent(wxMouseEvent& event)
{
int64_t samplepos = SamplesFromRelativeX(mousepos.x);
AudioMarker *marker = event.LeftDown() ?
timing->OnLeftClick(samplepos, drag_sensitivity) :
timing->OnRightClick(samplepos, drag_sensitivity);
timing->OnLeftClick(samplepos, drag_sensitivity, snap_sensitivity) :
timing->OnRightClick(samplepos, drag_sensitivity, snap_sensitivity);
if (marker)
{

View file

@ -125,25 +125,26 @@ public:
/// @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 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
/// starts dragging the mouse after pressing down the button, the returned
/// 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
/// @param sample The audio sample index the user clicked
/// @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
/// starts dragging the mouse after pressing down the button, the returned
/// 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
/// @param marker The marker being dragged
/// @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
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
virtual ~AudioTimingController() { }

View file

@ -80,7 +80,7 @@ public:
int64_t GetPosition() const { return position; }
wxPen GetStyle() const { return style; }
FeetStyle GetFeet() const { return feet; }
bool CanSnap() const { return true; }
bool CanSnap() const { return false; }
public:
// Specific interface
@ -197,6 +197,11 @@ class AudioTimingControllerDialogue : public AudioTimingController, private Sele
/// @param sample New position of the marker
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
void OnActiveLineChanged(AssDialogue *new_line);
void OnSelectedSetChanged(const Selection &lines_added, const Selection &lines_removed);
@ -220,9 +225,9 @@ public:
void Commit();
void Revert();
bool IsNearbyMarker(int64_t sample, int sensitivity) const;
AudioMarker * OnLeftClick(int64_t sample, int sensitivity);
AudioMarker * OnRightClick(int64_t sample, int sensitivity);
void OnMarkerDrag(AudioMarker *marker, int64_t new_position, bool snap, int64_t snap_range);
AudioMarker * OnLeftClick(int64_t sample, int sensitivity, int64_t snap_range);
AudioMarker * OnRightClick(int64_t sample, int sensitivity, int64_t snap_range);
void OnMarkerDrag(AudioMarker *marker, int64_t new_position, int64_t snap_range);
public:
// 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]);
}
AudioMarker * AudioTimingControllerDialogue::OnLeftClick(int64_t sample, int sensitivity)
AudioMarker * AudioTimingControllerDialogue::OnLeftClick(int64_t sample, int sensitivity, int64_t snap_range)
{
assert(sensitivity >= 0);
@ -497,7 +502,7 @@ AudioMarker * AudioTimingControllerDialogue::OnLeftClick(int64_t sample, int sen
{
// Clicked near the left marker:
// Insta-move it and start dragging it
SetMarker(left, sample);
SetMarker(left, SnapPosition(sample, snap_range));
return left;
}
@ -511,42 +516,22 @@ AudioMarker * AudioTimingControllerDialogue::OnLeftClick(int64_t sample, int sen
// Clicked far from either marker:
// 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
SetMarker(left, sample);
SetMarker(left, SnapPosition(sample, snap_range));
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();
SetMarker(right, sample);
SetMarker(right, SnapPosition(sample, snap_range));
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]);
if (snap)
{
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);
SetMarker(static_cast<AudioMarkerDialogueTiming*>(marker), SnapPosition(new_position, snap_range));
}
void AudioTimingControllerDialogue::UpdateSelection()
@ -606,3 +591,28 @@ void AudioTimingControllerDialogue::RegenerateInactiveLines()
}
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 Revert();
bool IsNearbyMarker(int64_t sample, int sensitivity) const;
AudioMarker * OnLeftClick(int64_t sample, int sensitivity);
AudioMarker * OnRightClick(int64_t sample, int sensitivity) { return 0; }
void OnMarkerDrag(AudioMarker *marker, int64_t new_position, bool, int64_t);
AudioMarker * OnLeftClick(int64_t sample, int sensitivity, int64_t);
AudioMarker * OnRightClick(int64_t, int, int64_t) { return 0; }
void OnMarkerDrag(AudioMarker *marker, int64_t new_position, int64_t);
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;
}
AudioMarker *AudioTimingControllerKaraoke::OnLeftClick(int64_t sample, int sensitivity) {
AudioMarker *AudioTimingControllerKaraoke::OnLeftClick(int64_t sample, int sensitivity, int64_t) {
SampleRange range(sample - sensitivity, sample + sensitivity);
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;
}
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);
// No rearranging of syllables allowed
new_position = mid(