Snap based on all markers being dragged rather than just the mouse position
This commit is contained in:
parent
9168484fc6
commit
c13b026598
1 changed files with 56 additions and 43 deletions
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue