Modify the TimingController interface to support dragging more than one marker at once. Updates #20.

Originally committed to SVN as r6460.
This commit is contained in:
Thomas Goyne 2012-02-10 00:04:13 +00:00
parent 51a3831794
commit 32c8cc0974
4 changed files with 48 additions and 42 deletions

View file

@ -464,7 +464,7 @@ public:
class AudioMarkerInteractionObject : public AudioDisplayInteractionObject { class AudioMarkerInteractionObject : public AudioDisplayInteractionObject {
// Object-pair being interacted with // Object-pair being interacted with
AudioMarker *marker; std::vector<AudioMarker*> markers;
AudioTimingController *timing_controller; AudioTimingController *timing_controller;
// Audio display drag is happening on // Audio display drag is happening on
AudioDisplay *display; AudioDisplay *display;
@ -478,8 +478,8 @@ class AudioMarkerInteractionObject : public AudioDisplayInteractionObject {
int snap_range; int snap_range;
public: public:
AudioMarkerInteractionObject(AudioMarker *marker, AudioTimingController *timing_controller, AudioDisplay *display, AudioController *controller, wxMouseButton button_used) AudioMarkerInteractionObject(std::vector<AudioMarker*> markers, AudioTimingController *timing_controller, AudioDisplay *display, AudioController *controller, wxMouseButton button_used)
: marker(marker) : markers(markers)
, timing_controller(timing_controller) , timing_controller(timing_controller)
, display(display) , display(display)
, controller(controller) , controller(controller)
@ -494,7 +494,7 @@ public:
if (event.Dragging()) if (event.Dragging())
{ {
timing_controller->OnMarkerDrag( timing_controller->OnMarkerDrag(
marker, markers,
display->TimeFromRelativeX(event.GetPosition().x), display->TimeFromRelativeX(event.GetPosition().x),
default_snap != event.ShiftDown() ? display->TimeFromAbsoluteX(snap_range) : 0); default_snap != event.ShiftDown() ? display->TimeFromAbsoluteX(snap_range) : 0);
} }
@ -1093,14 +1093,14 @@ void AudioDisplay::OnMouseEvent(wxMouseEvent& event)
if (event.LeftDown() || event.RightDown()) if (event.LeftDown() || event.RightDown())
{ {
int timepos = TimeFromRelativeX(mousepos.x); int timepos = TimeFromRelativeX(mousepos.x);
AudioMarker *marker = event.LeftDown() ? std::vector<AudioMarker*> markers = event.LeftDown() ?
timing->OnLeftClick(timepos, drag_sensitivity, snap_sensitivity) : timing->OnLeftClick(timepos, event.CmdDown(), drag_sensitivity, snap_sensitivity) :
timing->OnRightClick(timepos, drag_sensitivity, snap_sensitivity); timing->OnRightClick(timepos, event.CmdDown(), drag_sensitivity, snap_sensitivity);
if (marker) if (markers.size())
{ {
RemoveTrackCursor(); RemoveTrackCursor();
audio_marker.reset(new AudioMarkerInteractionObject(marker, timing, this, controller, (wxMouseButton)event.GetButton())); audio_marker.reset(new AudioMarkerInteractionObject(markers, timing, this, controller, (wxMouseButton)event.GetButton()));
SetDraggedObject(audio_marker.get()); SetDraggedObject(audio_marker.get());
return; return;
} }
@ -1173,6 +1173,8 @@ void AudioDisplay::OnAudioOpen(AudioProvider *provider)
connections.push_back(OPT_SUB("Colour/Audio Display/Spectrum", &AudioDisplay::ReloadRenderingSettings, this)); connections.push_back(OPT_SUB("Colour/Audio Display/Spectrum", &AudioDisplay::ReloadRenderingSettings, this));
connections.push_back(OPT_SUB("Colour/Audio Display/Waveform", &AudioDisplay::ReloadRenderingSettings, this)); connections.push_back(OPT_SUB("Colour/Audio Display/Waveform", &AudioDisplay::ReloadRenderingSettings, this));
connections.push_back(OPT_SUB("Audio/Renderer/Spectrum/Quality", &AudioDisplay::ReloadRenderingSettings, this)); connections.push_back(OPT_SUB("Audio/Renderer/Spectrum/Quality", &AudioDisplay::ReloadRenderingSettings, this));
OnTimingController();
} }
} }
else else

View file

@ -112,29 +112,30 @@ public:
/// controlling the mouse cursor. /// controlling the mouse cursor.
virtual bool IsNearbyMarker(int ms, int sensitivity) const = 0; virtual bool IsNearbyMarker(int ms, int sensitivity) const = 0;
/// @brief The user pressed the left button down at an empty place in the audio /// @brief The user pressed the left mouse button on the audio
/// @param ms The time in milliseconds the user clicked /// @param ms The time in milliseconds the user clicked
/// @param ctrl_down Is the user currently holding the ctrl key down?
/// @param sensitivity Distance in milliseconds to consider existing markers /// @param sensitivity Distance in milliseconds to consider existing markers
/// @param snap_range Maximum snapping range in milliseconds /// @param snap_range Maximum snapping range in milliseconds
/// @return An audio marker or 0. If a marker is returned and the user /// @return All audio markers at the clicked position which are eligible
/// starts dragging the mouse after pressing down the button, the returned /// to be dragged, if any.
/// marker is being dragged. virtual std::vector<AudioMarker*> OnLeftClick(int ms, bool ctrl_down, int sensitivity, int snap_range) = 0;
virtual AudioMarker * OnLeftClick(int ms, int sensitivity, int snap_range) = 0;
/// @brief The user pressed the right button down at an empty place in the audio /// @brief The user pressed the right mouse button on the audio
/// @param ms The time in milliseconds the user clicked /// @param ms The time in milliseconds the user clicked
/// @param ctrl_down Is the user currently holding the ctrl key down?
/// @param sensitivity Distance in milliseconds to consider existing markers /// @param sensitivity Distance in milliseconds to consider existing markers
/// @param snap_range Maximum snapping range in milliseconds /// @param snap_range Maximum snapping range in milliseconds
/// @return An audio marker or 0. If a marker is returned and the user /// @return All audio markers at the clicked position which are eligible
/// starts dragging the mouse after pressing down the button, the returned /// to be dragged, if any.
/// marker is being dragged. virtual std::vector<AudioMarker*> OnRightClick(int ms, bool ctrl_down, int sensitivity, int snap_range) = 0;
virtual AudioMarker * OnRightClick(int ms, int sensitivity, int snap_range) = 0;
/// @brief The user dragged a timing marker /// @brief The user dragged one or more timing markers
/// @param marker The marker being dragged /// @param marker The markers being dragged. This is guaranteed to be
/// a vector returned from OnLeftClick or OnRightClick.
/// @param new_position Time position the marker was dragged to /// @param new_position Time position the marker was dragged to
/// @param snap_range Maximum snapping range in milliseconds /// @param snap_range Maximum snapping range in milliseconds
virtual void OnMarkerDrag(AudioMarker *marker, int new_position, int snap_range) = 0; virtual void OnMarkerDrag(std::vector<AudioMarker*> const& marker, int new_position, int snap_range) = 0;
/// @brief Destructor /// @brief Destructor
virtual ~AudioTimingController() { } virtual ~AudioTimingController() { }

View file

@ -231,9 +231,9 @@ public:
void Commit(); void Commit();
void Revert(); void Revert();
bool IsNearbyMarker(int ms, int sensitivity) const; bool IsNearbyMarker(int ms, int sensitivity) const;
AudioMarker * OnLeftClick(int ms, int sensitivity, int snap_range); std::vector<AudioMarker*> OnLeftClick(int ms, bool ctrl_down, int sensitivity, int snap_range);
AudioMarker * OnRightClick(int ms, int sensitivity, int snap_range); std::vector<AudioMarker*> OnRightClick(int ms, bool, int sensitivity, int snap_range);
void OnMarkerDrag(AudioMarker *marker, int new_position, int snap_range); void OnMarkerDrag(std::vector<AudioMarker*> const& markers, int new_position, int snap_range);
public: public:
// Specific interface // Specific interface
@ -494,7 +494,7 @@ bool AudioTimingControllerDialogue::IsNearbyMarker(int ms, int sensitivity) cons
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(int ms, int sensitivity, int snap_range) std::vector<AudioMarker*> AudioTimingControllerDialogue::OnLeftClick(int ms, bool ctrl_down, int sensitivity, int snap_range)
{ {
assert(sensitivity >= 0); assert(sensitivity >= 0);
@ -511,32 +511,34 @@ AudioMarker * AudioTimingControllerDialogue::OnLeftClick(int ms, int sensitivity
// 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, SnapPosition(ms, snap_range)); SetMarker(left, SnapPosition(ms, snap_range));
return left; return std::vector<AudioMarker*>(1, left);
} }
if (dist_r < dist_l && dist_r <= sensitivity) if (dist_r < dist_l && dist_r <= sensitivity)
{ {
// Clicked near the right marker: // Clicked near the right marker:
// Only drag it. For insta-move, the user must right-click. // Only drag it. For insta-move, the user must right-click.
return right; return std::vector<AudioMarker*>(1, right);
} }
// 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, SnapPosition(ms, snap_range)); SetMarker(left, SnapPosition(ms, snap_range));
return right; return std::vector<AudioMarker*>(1, right);
} }
AudioMarker * AudioTimingControllerDialogue::OnRightClick(int ms, int sensitivity, int snap_range) std::vector<AudioMarker*> AudioTimingControllerDialogue::OnRightClick(int ms, bool, int sensitivity, int snap_range)
{ {
AudioMarkerDialogueTiming *right = GetRightMarker(); AudioMarkerDialogueTiming *right = GetRightMarker();
SetMarker(right, SnapPosition(ms, snap_range)); SetMarker(right, SnapPosition(ms, snap_range));
return right; return std::vector<AudioMarker*>(1, right);
} }
void AudioTimingControllerDialogue::OnMarkerDrag(AudioMarker *marker, int new_position, int snap_range) void AudioTimingControllerDialogue::OnMarkerDrag(std::vector<AudioMarker*> const& markers, int new_position, int snap_range)
{ {
assert(markers.size() == 1);
AudioMarker *marker = markers[0];
assert(marker == &active_markers[0] || marker == &active_markers[1]); assert(marker == &active_markers[0] || marker == &active_markers[1]);
SetMarker(static_cast<AudioMarkerDialogueTiming*>(marker), SnapPosition(new_position, snap_range)); SetMarker(static_cast<AudioMarkerDialogueTiming*>(marker), SnapPosition(new_position, snap_range));

View file

@ -129,9 +129,9 @@ public:
void Commit(); void Commit();
void Revert(); void Revert();
bool IsNearbyMarker(int ms, int sensitivity) const; bool IsNearbyMarker(int ms, int sensitivity) const;
AudioMarker * OnLeftClick(int ms, int sensitivity, int); std::vector<AudioMarker*> OnLeftClick(int ms, bool, int sensitivity, int);
AudioMarker * OnRightClick(int, int, int) { return 0; } std::vector<AudioMarker*> OnRightClick(int, bool, int, int) { return std::vector<AudioMarker*>(); }
void OnMarkerDrag(AudioMarker *marker, int new_position, int); void OnMarkerDrag(std::vector<AudioMarker*> const& marker, int new_position, int);
AudioTimingControllerKaraoke(agi::Context *c, AssKaraoke *kara, agi::signal::Connection& file_changed); AudioTimingControllerKaraoke(agi::Context *c, AssKaraoke *kara, agi::signal::Connection& file_changed);
}; };
@ -289,25 +289,26 @@ bool AudioTimingControllerKaraoke::IsNearbyMarker(int ms, int sensitivity) const
return false; return false;
} }
AudioMarker *AudioTimingControllerKaraoke::OnLeftClick(int ms, int sensitivity, int) { std::vector<AudioMarker*> AudioTimingControllerKaraoke::OnLeftClick(int ms, bool, int sensitivity, int) {
TimeRange range(ms - sensitivity, ms + sensitivity); TimeRange range(ms - sensitivity, ms + sensitivity);
size_t syl = distance(markers.begin(), lower_bound(markers.begin(), markers.end(), ms)); size_t syl = distance(markers.begin(), lower_bound(markers.begin(), markers.end(), ms));
if (syl < markers.size() && range.contains(markers[syl])) if (syl < markers.size() && range.contains(markers[syl]))
return &markers[syl]; return std::vector<AudioMarker*>(1, &markers[syl]);
if (syl > 0 && range.contains(markers[syl - 1])) if (syl > 0 && range.contains(markers[syl - 1]))
return &markers[syl - 1]; return std::vector<AudioMarker*>(1, &markers[syl - 1]);
cur_syl = syl; cur_syl = syl;
AnnounceUpdatedPrimaryRange(); AnnounceUpdatedPrimaryRange();
AnnounceUpdatedStyleRanges(); AnnounceUpdatedStyleRanges();
return 0; return std::vector<AudioMarker*>();
} }
void AudioTimingControllerKaraoke::OnMarkerDrag(AudioMarker *m, int new_position, int) { void AudioTimingControllerKaraoke::OnMarkerDrag(std::vector<AudioMarker*> const& m, int new_position, int) {
KaraokeMarker *marker = static_cast<KaraokeMarker*>(m); assert(m.size() == 1);
KaraokeMarker *marker = static_cast<KaraokeMarker*>(m[0]);
// No rearranging of syllables allowed // No rearranging of syllables allowed
new_position = mid( new_position = mid(
marker == &markers.front() ? start_marker.GetPosition() : (marker - 1)->GetPosition(), marker == &markers.front() ? start_marker.GetPosition() : (marker - 1)->GetPosition(),