Snap based on all markers being dragged rather than just the mouse position

This commit is contained in:
Thomas Goyne 2014-05-14 11:52:41 -07:00
parent 9168484fc6
commit c13b026598

View file

@ -49,6 +49,7 @@
#include <cstdint> #include <cstdint>
#include <wx/pen.h> #include <wx/pen.h>
namespace {
class TimeableLine; class TimeableLine;
/// @class DialogueTimingMarker /// @class DialogueTimingMarker
@ -366,13 +367,13 @@ class AudioTimingControllerDialogue final : public AudioTimingController {
/// @brief Set the position of markers and announce the change to the world /// @brief Set the position of markers and announce the change to the world
/// @param upd_markers Markers to move /// @param upd_markers Markers to move
/// @param ms New position of the markers /// @param ms New position of the markers
void SetMarkers(std::vector<AudioMarker*> const& upd_markers, int ms); void SetMarkers(std::vector<AudioMarker*> const& upd_markers, int ms, int snap_range);
/// Snap a position to a nearby marker, if any /// Try to snap all of the active markers to any inactive markers
/// @param position Position to snap
/// @param snap_range Maximum distance to snap in milliseconds /// @param snap_range Maximum distance to snap in milliseconds
/// @param exclude Markers which should be excluded from the potential snaps /// @param active Markers which should be snapped
int SnapPosition(int position, int snap_range, std::vector<AudioMarker*> const& exclude) const; /// @return The distance the markers were shifted by
int SnapMarkers(int snap_range, std::vector<AudioMarker*> const& markers) const;
/// Commit all pending changes to the file /// Commit all pending changes to the file
/// @param user_triggered Is this a user-initiated commit or an autocommit /// @param user_triggered Is this a user-initiated commit or an autocommit
@ -413,11 +414,6 @@ public:
AudioTimingControllerDialogue(agi::Context *c); AudioTimingControllerDialogue(agi::Context *c);
}; };
std::unique_ptr<AudioTimingController> CreateDialogueTimingController(agi::Context *c)
{
return agi::make_unique<AudioTimingControllerDialogue>(c);
}
AudioTimingControllerDialogue::AudioTimingControllerDialogue(agi::Context *c) AudioTimingControllerDialogue::AudioTimingControllerDialogue(agi::Context *c)
: active_line(AudioStyle_Primary, &style_left, &style_right) : active_line(AudioStyle_Primary, &style_left, &style_right)
, keyframes_provider(c, "Audio/Display/Draw/Keyframes in Dialogue Mode") , keyframes_provider(c, "Audio/Display/Draw/Keyframes in Dialogue Mode")
@ -586,25 +582,25 @@ void AudioTimingControllerDialogue::Revert()
void AudioTimingControllerDialogue::AddLeadIn() void AudioTimingControllerDialogue::AddLeadIn()
{ {
DialogueTimingMarker *m = active_line.GetLeftMarker(); DialogueTimingMarker *m = active_line.GetLeftMarker();
SetMarkers({ m }, *m - OPT_GET("Audio/Lead/IN")->GetInt()); SetMarkers({ m }, *m - OPT_GET("Audio/Lead/IN")->GetInt(), 0);
} }
void AudioTimingControllerDialogue::AddLeadOut() void AudioTimingControllerDialogue::AddLeadOut()
{ {
DialogueTimingMarker *m = active_line.GetRightMarker(); DialogueTimingMarker *m = active_line.GetRightMarker();
SetMarkers({ m }, *m + OPT_GET("Audio/Lead/OUT")->GetInt()); SetMarkers({ m }, *m + OPT_GET("Audio/Lead/OUT")->GetInt(), 0);
} }
void AudioTimingControllerDialogue::ModifyLength(int delta, bool) { void AudioTimingControllerDialogue::ModifyLength(int delta, bool) {
DialogueTimingMarker *m = active_line.GetRightMarker(); DialogueTimingMarker *m = active_line.GetRightMarker();
SetMarkers({ m }, SetMarkers({ m },
std::max<int>(*m + delta * 10, *active_line.GetLeftMarker())); std::max<int>(*m + delta * 10, *active_line.GetLeftMarker()), 0);
} }
void AudioTimingControllerDialogue::ModifyStart(int delta) { void AudioTimingControllerDialogue::ModifyStart(int delta) {
DialogueTimingMarker *m = active_line.GetLeftMarker(); DialogueTimingMarker *m = active_line.GetLeftMarker();
SetMarkers({ m }, SetMarkers({ m },
std::min<int>(*m + delta * 10, *active_line.GetRightMarker())); std::min<int>(*m + delta * 10, *active_line.GetRightMarker()), 0);
} }
bool AudioTimingControllerDialogue::IsNearbyMarker(int ms, int sensitivity, bool alt_down) const bool AudioTimingControllerDialogue::IsNearbyMarker(int ms, int sensitivity, bool alt_down) const
@ -645,7 +641,7 @@ std::vector<AudioMarker*> AudioTimingControllerDialogue::OnLeftClick(int ms, boo
std::vector<AudioMarker*> jump = GetLeftMarkers(); std::vector<AudioMarker*> jump = GetLeftMarkers();
ret = drag_timing->GetBool() ? GetRightMarkers() : jump; ret = drag_timing->GetBool() ? GetRightMarkers() : jump;
// Get ret before setting as setting may swap left/right // Get ret before setting as setting may swap left/right
SetMarkers(jump, SnapPosition(ms, snap_range, jump)); SetMarkers(jump, ms, snap_range);
return ret; return ret;
} }
@ -665,7 +661,7 @@ std::vector<AudioMarker*> AudioTimingControllerDialogue::OnLeftClick(int ms, boo
// Left-click within drag range should still move the left marker to the // Left-click within drag range should still move the left marker to the
// clicked position, but not the right marker // clicked position, but not the right marker
if (clicked == left) if (clicked == left)
SetMarkers(ret, SnapPosition(ms, snap_range, ret)); SetMarkers(ret, ms, snap_range);
return ret; return ret;
} }
@ -674,13 +670,13 @@ std::vector<AudioMarker*> AudioTimingControllerDialogue::OnRightClick(int ms, bo
{ {
clicked_ms = -1; clicked_ms = -1;
std::vector<AudioMarker*> ret = GetRightMarkers(); std::vector<AudioMarker*> ret = GetRightMarkers();
SetMarkers(ret, SnapPosition(ms, snap_range, ret)); SetMarkers(ret, ms, snap_range);
return ret; return ret;
} }
void AudioTimingControllerDialogue::OnMarkerDrag(std::vector<AudioMarker*> const& markers, int new_position, int snap_range) void AudioTimingControllerDialogue::OnMarkerDrag(std::vector<AudioMarker*> const& markers, int new_position, int snap_range)
{ {
SetMarkers(markers, SnapPosition(new_position, snap_range, markers)); SetMarkers(markers, new_position, snap_range);
} }
void AudioTimingControllerDialogue::UpdateSelection() void AudioTimingControllerDialogue::UpdateSelection()
@ -689,16 +685,12 @@ void AudioTimingControllerDialogue::UpdateSelection()
AnnounceUpdatedStyleRanges(); AnnounceUpdatedStyleRanges();
} }
void AudioTimingControllerDialogue::SetMarkers(std::vector<AudioMarker*> const& upd_markers, int ms) void AudioTimingControllerDialogue::SetMarkers(std::vector<AudioMarker*> const& upd_markers, int ms, int snap_range)
{ {
if (upd_markers.empty()) return; if (upd_markers.empty()) return;
int shift = 0; int shift = clicked_ms >= 0 ? ms - clicked_ms : 0;
if (clicked_ms >= 0) if (shift) clicked_ms = ms;
{
shift = ms - clicked_ms;
clicked_ms = ms;
}
// Since we're moving markers, the sorted list of markers will need to be // Since we're moving markers, the sorted list of markers will need to be
// resorted. To avoid resorting the entire thing, find the subrange that // resorted. To avoid resorting the entire thing, find the subrange that
@ -729,6 +721,10 @@ void AudioTimingControllerDialogue::SetMarkers(std::vector<AudioMarker*> const&
modified_lines.insert(marker->GetLine()); modified_lines.insert(marker->GetLine());
} }
int snap = SnapMarkers(snap_range, upd_markers);
if (clicked_ms >= 0)
clicked_ms += snap;
// Resort the range // Resort the range
sort(begin, end, marker_ptr_cmp()); sort(begin, end, marker_ptr_cmp());
@ -864,30 +860,47 @@ std::vector<AudioMarker*> AudioTimingControllerDialogue::GetRightMarkers()
return ret; return ret;
} }
int AudioTimingControllerDialogue::SnapPosition(int position, int snap_range, std::vector<AudioMarker*> const& exclude) const int AudioTimingControllerDialogue::SnapMarkers(int snap_range, std::vector<AudioMarker*> const& active) const
{ {
if (position < 0) if (snap_range <= 0) return 0;
position = 0;
if (snap_range <= 0)
return position;
TimeRange snap_time_range(position - snap_range, position + snap_range);
const AudioMarker *snap_marker = nullptr;
AudioMarkerVector potential_snaps; AudioMarkerVector potential_snaps;
GetMarkers(snap_time_range, potential_snaps); int snap_distance = 0;
for (auto marker : potential_snaps) bool has_snapped = false;
int prev = -1;
for (const auto active_marker : active)
{ {
if (marker->CanSnap() && boost::find(exclude, marker) == exclude.end()) auto pos = active_marker->GetPosition();
if (pos == prev) continue;
potential_snaps.clear();
GetMarkers(TimeRange(pos - snap_range, pos + snap_range), potential_snaps);
for (auto marker : potential_snaps)
{ {
if (!snap_marker) if (!marker->CanSnap() || boost::find(active, marker) != end(active)) continue;
snap_marker = marker;
else if (tabs(marker->GetPosition() - position) < tabs(snap_marker->GetPosition() - position)) auto dist = marker->GetPosition() - pos;
snap_marker = marker; if (!has_snapped)
snap_distance = dist;
else if (tabs(dist) < tabs(snap_distance))
snap_distance = dist;
if (snap_distance == 0)
return 0;
has_snapped = true;
} }
} }
if (snap_marker) if (!has_snapped || tabs(snap_distance) > snap_range)
return snap_marker->GetPosition(); return 0;
return position;
for (auto m : active)
static_cast<DialogueTimingMarker *>(m)->SetPosition(m->GetPosition() + snap_distance);
return snap_distance;
}
} // namespace {
std::unique_ptr<AudioTimingController> CreateDialogueTimingController(agi::Context *c)
{
return agi::make_unique<AudioTimingControllerDialogue>(c);
} }