1
0
mirror of https://github.com/cookiengineer/audacity synced 2025-08-01 00:19:27 +02:00

TrackPanel no longer implements track selection click or rearrange drag...

... also implement ESC key for the drag
This commit is contained in:
Paul Licameli 2015-08-09 13:48:27 -04:00 committed by Paul Licameli
parent 46b97084eb
commit 703abe87bc
9 changed files with 330 additions and 190 deletions

View File

@ -1233,6 +1233,7 @@
5E7396561DAFDA0000BA0A4D /* WaveTrackSliderHandles.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5E7396541DAFDA0000BA0A4D /* WaveTrackSliderHandles.cpp */; };
5E7396591DAFDA3600BA0A4D /* TrackButtonHandles.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5E7396571DAFDA3600BA0A4D /* TrackButtonHandles.cpp */; };
5E73965C1DAFDAA400BA0A4D /* BackgroundCell.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5E73965A1DAFDAA400BA0A4D /* BackgroundCell.cpp */; };
5E73965F1DAFDAEC00BA0A4D /* TrackSelectHandle.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5E73965D1DAFDAEC00BA0A4D /* TrackSelectHandle.cpp */; };
5E74D2E31CC4429700D88B0B /* EditCursorOverlay.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5E74D2DD1CC4429700D88B0B /* EditCursorOverlay.cpp */; };
5E74D2E41CC4429700D88B0B /* PlayIndicatorOverlay.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5E74D2DF1CC4429700D88B0B /* PlayIndicatorOverlay.cpp */; };
5E74D2E51CC4429700D88B0B /* Scrubbing.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5E74D2E11CC4429700D88B0B /* Scrubbing.cpp */; };
@ -3070,6 +3071,8 @@
5E7396581DAFDA3600BA0A4D /* TrackButtonHandles.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = TrackButtonHandles.h; sourceTree = "<group>"; };
5E73965A1DAFDAA400BA0A4D /* BackgroundCell.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = BackgroundCell.cpp; sourceTree = "<group>"; };
5E73965B1DAFDAA400BA0A4D /* BackgroundCell.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = BackgroundCell.h; sourceTree = "<group>"; };
5E73965D1DAFDAEC00BA0A4D /* TrackSelectHandle.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = TrackSelectHandle.cpp; sourceTree = "<group>"; };
5E73965E1DAFDAEC00BA0A4D /* TrackSelectHandle.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = TrackSelectHandle.h; sourceTree = "<group>"; };
5E74D2D91CC4427B00D88B0B /* TrackPanelCell.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = TrackPanelCell.h; sourceTree = "<group>"; };
5E74D2DA1CC4427B00D88B0B /* TrackPanelCellIterator.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = TrackPanelCellIterator.h; sourceTree = "<group>"; };
5E74D2DD1CC4429700D88B0B /* EditCursorOverlay.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = EditCursorOverlay.cpp; sourceTree = "<group>"; };
@ -5778,6 +5781,7 @@
5E7396421DAFD8C600BA0A4D /* TimeShiftHandle.cpp */,
5E7396571DAFDA3600BA0A4D /* TrackButtonHandles.cpp */,
5E1512681DB0010C00702E29 /* TrackControls.cpp */,
5E73965D1DAFDAEC00BA0A4D /* TrackSelectHandle.cpp */,
5E15126A1DB0010C00702E29 /* TrackUI.cpp */,
5E15126B1DB0010C00702E29 /* TrackVRulerControls.cpp */,
5E73963C1DAFD86000BA0A4D /* ZoomHandle.cpp */,
@ -5792,6 +5796,7 @@
5E7396431DAFD8C600BA0A4D /* TimeShiftHandle.h */,
5E7396581DAFDA3600BA0A4D /* TrackButtonHandles.h */,
5E1512691DB0010C00702E29 /* TrackControls.h */,
5E73965E1DAFDAEC00BA0A4D /* TrackSelectHandle.h */,
5E15126C1DB0010C00702E29 /* TrackVRulerControls.h */,
5E73963D1DAFD86000BA0A4D /* ZoomHandle.h */,
);
@ -7893,6 +7898,7 @@
2888495E131B6CF600B59735 /* km.po in Sources */,
2888495F131B6CF600B59735 /* ko.po in Sources */,
28884960131B6CF600B59735 /* lt.po in Sources */,
5E73965F1DAFDAEC00BA0A4D /* TrackSelectHandle.cpp in Sources */,
28884961131B6CF600B59735 /* mk.po in Sources */,
28884962131B6CF600B59735 /* my.po in Sources */,
28884963131B6CF600B59735 /* nb.po in Sources */,

View File

@ -601,6 +601,8 @@ audacity_SOURCES = \
tracks/ui/TrackButtonHandles.h \
tracks/ui/TrackControls.cpp \
tracks/ui/TrackControls.h \
tracks/ui/TrackSelectHandle.cpp \
tracks/ui/TrackSelectHandle.h \
tracks/ui/TrackUI.cpp \
tracks/ui/TrackVRulerControls.cpp \
tracks/ui/TrackVRulerControls.h \

View File

@ -195,6 +195,8 @@ is time to refresh some aspect of the screen.
//This loads the appropriate set of cursors, depending on platform.
#include "../images/Cursors.h"
#include "widgets/ASlider.h"
DEFINE_EVENT_TYPE(EVT_TRACK_PANEL_TIMER)
/*
@ -381,7 +383,6 @@ TrackPanel::TrackPanel(wxWindow * parent, wxWindowID id,
mArrowCursor = std::make_unique<wxCursor>(wxCURSOR_ARROW);
mResizeCursor = std::make_unique<wxCursor>(wxCURSOR_SIZENS);
mRearrangeCursor = std::make_unique<wxCursor>(wxCURSOR_HAND);
mAdjustLeftSelectionCursor = std::make_unique<wxCursor>(wxCURSOR_POINT_LEFT);
mAdjustRightSelectionCursor = std::make_unique<wxCursor>(wxCURSOR_POINT_RIGHT);
@ -873,7 +874,6 @@ void TrackPanel::HandleInterruptedDrag()
So this includes the cases:
IsAdjustingLabel,
IsRearranging,
IsStretching
*/
@ -1123,9 +1123,6 @@ bool TrackPanel::SetCursorByActivity( )
case IsSelecting:
SetCursor(*mSelectCursor);
return true;
case IsRearranging:
SetCursor( unsafe ? *mDisabledCursor : *mRearrangeCursor);
return true;
case IsAdjustingLabel:
case IsSelectingLabelText:
return true;
@ -1142,36 +1139,6 @@ bool TrackPanel::SetCursorByActivity( )
return false;
}
#if defined(__WXMAC__)
/* i18n-hint: Command names a modifier key on Macintosh keyboards */
#define CTRL_CLICK _("Command-Click")
#else
/* i18n-hint: Ctrl names a modifier key on Windows or Linux keyboards */
#define CTRL_CLICK _("Ctrl-Click")
#endif
/// When in the "label" (TrackInfo or vertical ruler), we can either vertical zoom or re-order tracks.
/// Dont't change cursor/tip to zoom if display is not waveform (either linear of dB) or Spectrum
void TrackPanel::SetCursorAndTipWhenInLabel( Track * ,
const wxMouseEvent &, wxString &tip )
{
if( GetTrackCount() > 1 ) {
// Set a status message if over TrackInfo.
//tip = _("Drag the track vertically to change the order of the tracks.");
// i18n-hint: %s is replaced by (translation of) 'Ctrl-Click' on windows, 'Command-Click' on Mac
tip = wxString::Format( _("%s to select or deselect track. Drag up or down to change track order."),
CTRL_CLICK );
SetCursor( *mArrowCursor );
}
else {
// Set a status message if over TrackInfo.
// i18n-hint: %s is replaced by (translation of) 'Ctrl-Click' on windows, 'Command-Click' on Mac
tip = wxString::Format( _("%s to select or deselect track."),
CTRL_CLICK );
SetCursor(*mArrowCursor);
}
}
/// When in the resize area we can adjust size or relative size.
void TrackPanel::SetCursorAndTipWhenInVResizeArea( bool bLinked, wxString &tip )
{
@ -1492,9 +1459,6 @@ void TrackPanel::HandleCursor(wxMouseEvent & event)
pCursor = hitTest.preview.cursor;
if (pCursor)
SetCursor(*pCursor);
else if (foundCell.type == CellType::Label ||
foundCell.type == CellType::VRuler)
SetCursorAndTipWhenInLabel(track, event, tip);
}
// Is it a label track?
@ -1671,11 +1635,12 @@ void TrackPanel::HandleSelect(wxMouseEvent & event)
}
// Counts tracks, counting stereo tracks as one track.
size_t TrackPanel::GetTrackCount(){
size_t TrackPanel::GetTrackCount() const
{
size_t count = 0;
TrackListIterator iter(GetTracks());
for (Track *t = iter.First(); t; t = iter.Next()) {
TrackListConstIterator iter(GetTracks());
for (auto t = iter.First(); t; t = iter.Next()) {
count += 1;
if( t->GetLinked() ){
t = iter.Next();
@ -1687,11 +1652,12 @@ size_t TrackPanel::GetTrackCount(){
}
// Counts selected tracks, counting stereo tracks as one track.
size_t TrackPanel::GetSelectedTrackCount(){
size_t TrackPanel::GetSelectedTrackCount() const
{
size_t count = 0;
TrackListIterator iter(GetTracks());
for (Track *t = iter.First(); t; t = iter.Next()) {
TrackListConstIterator iter(GetTracks());
for (auto t = iter.First(); t; t = iter.Next()) {
count += t->GetSelected() ? 1:0;
if( t->GetLinked() ){
t = iter.Next();
@ -3062,120 +3028,6 @@ bool TrackInfo::HideTopItem( const wxRect &rect, const wxRect &subRect,
return subRect.y + subRect.height - allowance >= rect.y + limit;
}
/// This handles when the user clicks on the "Label" area
/// of a track, ie the part with all the buttons and the drop
/// down menu, etc.
// That is, TrackInfo and vertical ruler rect.
void TrackPanel::HandleLabelClick(wxMouseEvent & event)
{
// AS: If not a click, ignore the mouse event.
if (!event.ButtonDown() && !event.ButtonDClick()) {
return;
}
// MIDI tracks use the right mouse button, but other tracks get confused
// if they see anything other than a left click.
bool isleft = event.Button(wxMOUSE_BTN_LEFT);
bool unsafe = IsUnsafe();
const auto foundCell = FindCell(event.m_x, event.m_y);
auto &t = foundCell.pTrack;
auto &rect = foundCell.rect;
if (!isleft) {
return;
}
// DM: If they weren't clicking on a particular part of a track label,
// deselect other tracks and select this one.
// JH: also, capture the current track for rearranging, so the user
// can drag the track up or down to swap it with others
if (!unsafe) {
mRearrangeCount = 0;
SetCapturedTrack(t, IsRearranging);
TrackPanel::CalculateRearrangingThresholds(event);
}
GetProject()->HandleListSelection(t, event.ShiftDown(), event.ControlDown(), !unsafe);
}
/// The user is dragging one of the tracks: change the track order
/// accordingly
void TrackPanel::HandleRearrange(wxMouseEvent & event)
{
// are we finishing the drag?
if (event.LeftUp()) {
if (mRearrangeCount != 0) {
wxString dir;
/* i18n-hint: a direction as in up or down.*/
dir = mRearrangeCount < 0 ? _("up") : _("down");
/* i18n-hint: will substitute name of track for first %s, "up" or "down" for the other.*/
MakeParentPushState(wxString::Format(_("Moved '%s' %s"),
mCapturedTrack->GetName().c_str(),
dir.c_str()),
_("Move Track"));
}
SetCapturedTrack(NULL);
SetCursor(*mArrowCursor);
return;
}
// probably harmless during play? However, we do disallow the click, so check this too.
bool unsafe = IsUnsafe();
if (unsafe)
return;
MixerBoard* pMixerBoard = this->GetMixerBoard(); // Update mixer board, too.
if (event.m_y < mMoveUpThreshold || event.m_y < 0) {
mTracks->MoveUp(mCapturedTrack);
--mRearrangeCount;
if (pMixerBoard)
if(auto pPlayable = dynamic_cast< const PlayableTrack* >( mCapturedTrack ))
pMixerBoard->MoveTrackCluster(pPlayable, true /* up */);
}
else if (event.m_y > mMoveDownThreshold || event.m_y > GetRect().GetHeight()) {
mTracks->MoveDown(mCapturedTrack);
++mRearrangeCount;
if (pMixerBoard)
if(auto pPlayable = dynamic_cast< const PlayableTrack* >( mCapturedTrack ))
pMixerBoard->MoveTrackCluster(pPlayable, false /* down */);
}
else
{
return;
}
// JH: if we moved up or down, recalculate the thresholds and make sure the
// track is fully on-screen.
TrackPanel::CalculateRearrangingThresholds(event);
EnsureVisible(mCapturedTrack);
}
/// Figure out how far the user must drag the mouse up or down
/// before the track will swap with the one above or below
void TrackPanel::CalculateRearrangingThresholds(wxMouseEvent & event)
{
wxASSERT(mCapturedTrack);
// JH: this will probably need to be tweaked a bit, I'm just
// not sure what formula will have the best feel for the
// user.
if (mTracks->CanMoveUp(mCapturedTrack))
mMoveUpThreshold =
event.m_y - mTracks->GetGroupHeight( mTracks->GetPrev(mCapturedTrack,true) );
else
mMoveUpThreshold = INT_MIN;
if (mTracks->CanMoveDown(mCapturedTrack))
mMoveDownThreshold =
event.m_y + mTracks->GetGroupHeight( mTracks->GetNext(mCapturedTrack,true) );
else
mMoveDownThreshold = INT_MAX;
}
/// ButtonDown means they just clicked and haven't released yet.
/// We use this opportunity to save which track they clicked on,
/// and the initial height of the track, so as they drag we can
@ -3811,9 +3663,6 @@ try
HandleResize(event);
HandleCursor(event);
break;
case IsRearranging:
HandleRearrange(event);
break;
case IsAdjustingLabel:
// Reach this case only when the captured track was label
HandleGlyphDragRelease(static_cast<LabelTrack *>(mCapturedTrack), event);
@ -4069,13 +3918,6 @@ void TrackPanel::HandleTrackSpecificMouseEvent(wxMouseEvent & event)
ProcessUIHandleResult(this, mRuler, pTrack, pTrack, refreshResult);
}
else {
if (foundCell.type == CellType::VRuler) {
}
else if (foundCell.type == CellType::Label)
HandleLabelClick(event);
}
HandleCursor(event);
return;
}

View File

@ -388,12 +388,14 @@ class AUDACITY_DLL_API TrackPanel final : public OverlayPanel {
#endif
// AS: Selection handling
size_t GetTrackCount();
size_t GetSelectedTrackCount();
virtual void HandleSelect(wxMouseEvent & event);
virtual void SelectionHandleDrag(wxMouseEvent &event, Track *pTrack);
public:
size_t GetTrackCount() const;
size_t GetSelectedTrackCount() const;
protected:
virtual void HandleSelect(wxMouseEvent & event);
virtual void SelectionHandleDrag(wxMouseEvent &event, Track *pTrack);
virtual void SelectionHandleClick(wxMouseEvent &event,
Track* pTrack, wxRect rect);
@ -424,9 +426,9 @@ protected:
virtual void SelectTracksByLabel( LabelTrack *t );
protected:
// AS: Cursor handling
virtual bool SetCursorByActivity( );
virtual void SetCursorAndTipWhenInLabel( Track * t, const wxMouseEvent &event, wxString &tip );
virtual void SetCursorAndTipWhenInVResizeArea( bool blinked, wxString &tip );
virtual void SetCursorAndTipWhenInLabelTrack( LabelTrack * pLT, const wxMouseEvent & event, wxString &tip );
virtual void SetCursorAndTipWhenSelectTool
@ -448,11 +450,6 @@ protected:
virtual void HandleResizeButtonUp(wxMouseEvent & event);
virtual void HandleResize(wxMouseEvent & event);
virtual void HandleLabelClick(wxMouseEvent & event);
virtual void HandleRearrange(wxMouseEvent & event);
virtual void CalculateRearrangingThresholds(wxMouseEvent & event);
public:
virtual void MakeParentRedrawScrollbars();
@ -487,7 +484,8 @@ protected:
// JKC Nov-2011: These four functions only used from within a dll such as mod-track-panel
// They work around some messy problems with constructors.
public:
TrackList * GetTracks(){ return mTracks.get(); }
const TrackList * GetTracks() const { return mTracks.get(); }
TrackList * GetTracks() { return mTracks.get(); }
ViewInfo * GetViewInfo(){ return mViewInfo;}
TrackPanelListener * GetListener(){ return mListener;}
AdornedRulerPanel * GetRuler(){ return mRuler;}
@ -697,7 +695,6 @@ public:
IsResizing,
IsResizingBetweenLinkedTracks,
IsResizingBelowLinkedTracks,
IsRearranging,
IsMuting,
IsSoloing,
IsMinimizing,
@ -709,17 +706,10 @@ protected:
virtual void SetCapturedTrack( Track * t, enum MouseCaptureEnum MouseCapture=IsUncaptured );
// JH: if the user is dragging a track, at what y
// coordinate should the dragging track move up or down?
int mMoveUpThreshold;
int mMoveDownThreshold;
int mRearrangeCount;
std::unique_ptr<wxCursor>
mArrowCursor, mSelectCursor,
mResizeCursor, mEnvelopeCursor, // doubles as the center frequency cursor
// for spectral selection
mRearrangeCursor,
mDisabledCursor, mAdjustLeftSelectionCursor, mAdjustRightSelectionCursor;
#ifdef EXPERIMENTAL_SPECTRAL_EDITING
std::unique_ptr<wxCursor>

View File

@ -11,6 +11,7 @@ Paul Licameli split from TrackPanel.cpp
#include "../../Audacity.h"
#include "TrackControls.h"
#include "TrackButtonHandles.h"
#include "TrackSelectHandle.h"
#include "../../HitTestResult.h"
#include "../../RefreshCode.h"
#include "../../MixerBoard.h"
@ -28,7 +29,7 @@ TrackControls::~TrackControls()
HitTestResult TrackControls::HitTest
(const TrackPanelMouseEvent &evt,
const AudacityProject *)
const AudacityProject *project)
{
const wxMouseEvent &event = evt.event;
const wxRect &rect = evt.rect;
@ -43,7 +44,8 @@ HitTestResult TrackControls::HitTest
if (NULL != (result = MinimizeButtonHandle::HitTest(event, rect)).handle)
return result;
return result;
return TrackSelectHandle::HitAnywhere
(project->GetTrackPanel()->GetTrackCount());
}
Track *TrackControls::FindTrack()

View File

@ -0,0 +1,227 @@
/**********************************************************************
Audacity: A Digital Audio Editor
TrackSelectHandle.cpp
Paul Licameli split from TrackPanel.cpp
**********************************************************************/
#include "../../Audacity.h"
#include "TrackSelectHandle.h"
#include "TrackControls.h"
#include "../../Experimental.h"
#include "../../HitTestResult.h"
#include "../../MixerBoard.h"
#include "../../Project.h"
#include "../../RefreshCode.h"
#include "../../TrackPanel.h"
#include "../../TrackPanelMouseEvent.h"
#include "../../WaveTrack.h"
#include "../../MemoryX.h"
#include <wx/cursor.h>
#include <wx/translation.h>
#include "../../../images/Cursors.h"
TrackSelectHandle::TrackSelectHandle()
{
}
TrackSelectHandle &TrackSelectHandle::Instance()
{
static TrackSelectHandle instance;
return instance;
}
#if defined(__WXMAC__)
/* i18n-hint: Command names a modifier key on Macintosh keyboards */
#define CTRL_CLICK _("Command-Click")
#else
/* i18n-hint: Ctrl names a modifier key on Windows or Linux keyboards */
#define CTRL_CLICK _("Ctrl-Click")
#endif
namespace {
wxString Message(unsigned trackCount) {
if (trackCount > 1)
// i18n-hint: %s is replaced by (translation of) 'Ctrl-Click' on windows, 'Command-Click' on Mac
return wxString::Format(
_("%s to select or deselect track. Drag up or down to change track order."),
CTRL_CLICK );
else
// i18n-hint: %s is replaced by (translation of) 'Ctrl-Click' on windows, 'Command-Click' on Mac
return wxString::Format(
_("%s to select or deselect track."),
CTRL_CLICK );
}
}
HitTestPreview TrackSelectHandle::HitPreview(unsigned trackCount)
{
static wxCursor arrowCursor{ wxCURSOR_ARROW };
return {
Message(trackCount),
&arrowCursor
};
}
HitTestResult TrackSelectHandle::HitAnywhere(unsigned trackCount)
{
return {
HitPreview(trackCount),
&Instance()
};
}
TrackSelectHandle::~TrackSelectHandle()
{
}
UIHandle::Result TrackSelectHandle::Click
(const TrackPanelMouseEvent &evt, AudacityProject *pProject)
{
using namespace RefreshCode;
Result result = RefreshNone;
const wxMouseEvent &event = evt.event;
// AS: If not a click, ignore the mouse event.
if (!event.ButtonDown() && !event.ButtonDClick())
return Cancelled;
if (!event.Button(wxMOUSE_BTN_LEFT))
return Cancelled;
TrackControls *const pControls = static_cast<TrackControls*>(evt.pCell);
Track *const pTrack = pControls->GetTrack();
TrackPanel *const trackPanel = pProject->GetTrackPanel();
const bool unsafe = pProject->IsAudioActive();
// DM: If they weren't clicking on a particular part of a track label,
// deselect other tracks and select this one.
// JH: also, capture the current track for rearranging, so the user
// can drag the track up or down to swap it with others
if (unsafe)
result |= Cancelled;
else {
mRearrangeCount = 0;
mpTrack = pTrack;
CalculateRearrangingThresholds(event);
}
pProject->HandleListSelection
(pTrack, event.ShiftDown(), event.ControlDown(), !unsafe);
return result;
}
UIHandle::Result TrackSelectHandle::Drag
(const TrackPanelMouseEvent &evt, AudacityProject *pProject)
{
using namespace RefreshCode;
Result result = RefreshNone;
const wxMouseEvent &event = evt.event;
TrackList *const tracks = pProject->GetTracks();
// probably harmless during play? However, we do disallow the click, so check this too.
bool unsafe = pProject->IsAudioActive();
if (unsafe)
return result;
MixerBoard* pMixerBoard = pProject->GetMixerBoard(); // Update mixer board, too.
if (event.m_y < mMoveUpThreshold || event.m_y < 0) {
tracks->MoveUp(mpTrack);
--mRearrangeCount;
if (pMixerBoard)
if(auto pPlayable = dynamic_cast< const PlayableTrack* >( mpTrack ))
pMixerBoard->MoveTrackCluster(pPlayable, true /* up */);
}
else if ( event.m_y > mMoveDownThreshold
|| event.m_y > evt.whole.GetHeight() ) {
tracks->MoveDown(mpTrack);
++mRearrangeCount;
if (pMixerBoard)
if(auto pPlayable = dynamic_cast< const PlayableTrack* >( mpTrack ))
pMixerBoard->MoveTrackCluster(pPlayable, false /* down */);
}
else
return result;
// JH: if we moved up or down, recalculate the thresholds and make sure the
// track is fully on-screen.
CalculateRearrangingThresholds(event);
result |= EnsureVisible;
return result;
}
HitTestPreview TrackSelectHandle::Preview
(const TrackPanelMouseEvent &, const AudacityProject *project)
{
// Note that this differs from HitPreview.
static auto disabledCursor =
::MakeCursor(wxCURSOR_NO_ENTRY, DisabledCursorXpm, 16, 16);
static wxCursor rearrangeCursor{ wxCURSOR_HAND };
const bool unsafe = GetActiveProject()->IsAudioActive();
return {
Message(project->GetTrackPanel()->GetTrackCount()),
(unsafe
? &*disabledCursor
: &rearrangeCursor)
};
}
UIHandle::Result TrackSelectHandle::Release
(const TrackPanelMouseEvent &, AudacityProject *, wxWindow *)
{
if (mRearrangeCount != 0) {
AudacityProject *const project = ::GetActiveProject();
wxString dir;
/* i18n-hint: a direction as in up or down.*/
dir = mRearrangeCount < 0 ? _("up") : _("down");
/* i18n-hint: will substitute name of track for first %s, "up" or "down" for the other.*/
project->PushState(wxString::Format(_("Moved '%s' %s"),
mpTrack->GetName().c_str(),
dir.c_str()),
_("Move Track"));
}
// No need to redraw, that was done when drag moved the track
return RefreshCode::RefreshNone;
}
UIHandle::Result TrackSelectHandle::Cancel(AudacityProject *pProject)
{
pProject->RollbackState();
return RefreshCode::RefreshAll;
}
/// Figure out how far the user must drag the mouse up or down
/// before the track will swap with the one above or below
void TrackSelectHandle::CalculateRearrangingThresholds(const wxMouseEvent & event)
{
// JH: this will probably need to be tweaked a bit, I'm just
// not sure what formula will have the best feel for the
// user.
AudacityProject *const project = ::GetActiveProject();
TrackList *const tracks = project->GetTracks();
if (tracks->CanMoveUp(mpTrack))
mMoveUpThreshold =
event.m_y - tracks->GetGroupHeight(tracks->GetPrev(mpTrack, true));
else
mMoveUpThreshold = INT_MIN;
if (tracks->CanMoveDown(mpTrack))
mMoveDownThreshold =
event.m_y + tracks->GetGroupHeight(tracks->GetNext(mpTrack, true));
else
mMoveDownThreshold = INT_MAX;
}

View File

@ -0,0 +1,63 @@
/**********************************************************************
Audacity: A Digital Audio Editor
TrackSelectHandle.h
Paul Licameli split from TrackPanel.cpp
**********************************************************************/
#ifndef __AUDACITY_TRACK_SELECT_HANDLE__
#define __AUDACITY_TRACK_SELECT_HANDLE__
#include "../../UIHandle.h"
class wxMouseEvent;
struct HitTestResult;
class Track;
class TrackSelectHandle final : public UIHandle
{
TrackSelectHandle();
TrackSelectHandle(const TrackSelectHandle&) = delete;
TrackSelectHandle &operator=(const TrackSelectHandle&) = delete;
static TrackSelectHandle& Instance();
static HitTestPreview HitPreview(unsigned trackCount);
public:
static HitTestResult HitAnywhere(unsigned trackCount);
virtual ~TrackSelectHandle();
Result Click
(const TrackPanelMouseEvent &event, AudacityProject *pProject) override;
Result Drag
(const TrackPanelMouseEvent &event, AudacityProject *pProject) override;
HitTestPreview Preview
(const TrackPanelMouseEvent &event, const AudacityProject *pProject)
override;
Result Release
(const TrackPanelMouseEvent &event, AudacityProject *pProject,
wxWindow *pParent) override;
Result Cancel(AudacityProject *) override;
bool StopsOnKeystroke() override { return true; }
private:
Track *mpTrack {};
// JH: if the user is dragging a track, at what y
// coordinate should the dragging track move up or down?
int mMoveUpThreshold {};
int mMoveDownThreshold {};
int mRearrangeCount {};
void CalculateRearrangingThresholds(const wxMouseEvent & event);
};
#endif

View File

@ -251,6 +251,7 @@
<ClCompile Include="..\..\..\src\tracks\ui\TimeShiftHandle.cpp" />
<ClCompile Include="..\..\..\src\tracks\ui\TrackButtonHandles.cpp" />
<ClCompile Include="..\..\..\src\tracks\ui\TrackControls.cpp" />
<ClCompile Include="..\..\..\src\tracks\ui\TrackSelectHandle.cpp" />
<ClCompile Include="..\..\..\src\tracks\ui\TrackUI.cpp" />
<ClCompile Include="..\..\..\src\tracks\ui\TrackVRulerControls.cpp" />
<ClCompile Include="..\..\..\src\tracks\ui\ZoomHandle.cpp" />
@ -522,6 +523,7 @@
<ClInclude Include="..\..\..\src\tracks\ui\TimeShiftHandle.h" />
<ClInclude Include="..\..\..\src\tracks\ui\TrackButtonHandles.h" />
<ClInclude Include="..\..\..\src\tracks\ui\TrackControls.h" />
<ClInclude Include="..\..\..\src\tracks\ui\TrackSelectHandle.h" />
<ClInclude Include="..\..\..\src\tracks\ui\ZoomHandle.h" />
<ClInclude Include="..\..\..\src\tracks\timetrack\ui\TimeTrackVRulerControls.h" />
<ClInclude Include="..\..\..\src\tracks\ui\TrackVRulerControls.h" />

View File

@ -1,4 +1,4 @@
<?xml version="1.0" encoding="utf-8"?>
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup>
<Filter Include="src">
@ -1025,6 +1025,9 @@
<ClCompile Include="..\..\..\src\tracks\ui\BackgroundCell.cpp">
<Filter>src\tracks\ui</Filter>
</ClCompile>
<ClCompile Include="..\..\..\src\tracks\ui\TrackSelectHandle.cpp">
<Filter>src\tracks\ui</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<ClInclude Include="..\..\..\src\AboutDialog.h">
@ -2041,6 +2044,9 @@
<ClInclude Include="..\..\..\src\tracks\ui\BackgroundCell.h">
<Filter>src\tracks\ui</Filter>
</ClInclude>
<ClInclude Include="..\..\..\src\tracks\ui\TrackSelectHandle.h">
<Filter>src\tracks\ui</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<Image Include="..\..\audacity.ico">