mirror of
https://github.com/cookiengineer/audacity
synced 2025-05-01 16:19:43 +02:00
Addition, deletion, sort of Labels communicated by events...
... and LabelTrack listens to its own events, to update certain state. This is roundabout for now, but that state is view-related and will move into another class.
This commit is contained in:
parent
aa5f9550bd
commit
604fbd0a2c
@ -76,6 +76,10 @@ for drawing different aspects of the label and its text box.
|
||||
#include "widgets/AudacityMessageBox.h"
|
||||
#include "widgets/ErrorDialog.h"
|
||||
|
||||
wxDEFINE_EVENT(EVT_LABELTRACK_ADDITION, LabelTrackEvent);
|
||||
wxDEFINE_EVENT(EVT_LABELTRACK_DELETION, LabelTrackEvent);
|
||||
wxDEFINE_EVENT(EVT_LABELTRACK_PERMUTED, LabelTrackEvent);
|
||||
|
||||
enum
|
||||
{
|
||||
OnCutSelectedTextID = 1, // OSX doesn't like a 0 menu id
|
||||
@ -131,6 +135,10 @@ LabelTrack::LabelTrack(const std::shared_ptr<DirManager> &projDirManager):
|
||||
|
||||
// reset flags
|
||||
ResetFlags();
|
||||
|
||||
Bind( EVT_LABELTRACK_ADDITION, &LabelTrack::OnLabelAdded, this );
|
||||
Bind( EVT_LABELTRACK_DELETION, &LabelTrack::OnLabelDeleted, this );
|
||||
Bind( EVT_LABELTRACK_PERMUTED, &LabelTrack::OnLabelPermuted, this );
|
||||
}
|
||||
|
||||
LabelTrack::LabelTrack(const LabelTrack &orig) :
|
||||
@ -806,7 +814,7 @@ namespace {
|
||||
if (target) {
|
||||
auto handle = dynamic_cast<LabelGlyphHandle*>( target.get() );
|
||||
if (handle)
|
||||
return &handle->mHit;
|
||||
return &*handle->mpHit;
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
@ -1581,7 +1589,7 @@ bool LabelTrack::HandleGlyphDragRelease
|
||||
//the NEW size of the label.
|
||||
*newSel = mLabels[mSelIndex].selectedRegion;
|
||||
}
|
||||
SortLabels( &hit );
|
||||
SortLabels();
|
||||
}
|
||||
|
||||
return false;
|
||||
@ -2802,8 +2810,17 @@ int LabelTrackView::AddLabel(const SelectedRegion &selectedRegion,
|
||||
return pos;
|
||||
}
|
||||
|
||||
void LabelTrack::OnLabelAdded( const wxString &title, int pos )
|
||||
void LabelTrack::OnLabelAdded( LabelTrackEvent &e )
|
||||
{
|
||||
e.Skip();
|
||||
if ( e.mpTrack.lock().get() != this )
|
||||
return;
|
||||
|
||||
const auto &title = e.mTitle;
|
||||
const auto pos = e.mPresentPosition;
|
||||
|
||||
mInitialCursorPos = mCurrentCursorPos = title.length();
|
||||
|
||||
// restoreFocus is -2 e.g. from Nyquist label creation, when we should not
|
||||
// even lose the focus and open the label to edit in the first place.
|
||||
// -1 means we don't need to restore it to anywhere.
|
||||
@ -2824,8 +2841,6 @@ void LabelTrack::OnLabelAdded( const wxString &title, int pos )
|
||||
// If the label is added during actions like import, then the
|
||||
// mDrawCursor flag will be reset once the action is complete.
|
||||
mDrawCursor = true;
|
||||
|
||||
mInitialCursorPos = mCurrentCursorPos = title.length();
|
||||
}
|
||||
|
||||
|
||||
@ -2842,7 +2857,10 @@ int LabelTrack::AddLabel(const SelectedRegion &selectedRegion,
|
||||
|
||||
mLabels.insert(mLabels.begin() + pos, l);
|
||||
|
||||
OnLabelAdded( title, pos );
|
||||
// wxWidgets will own the event object
|
||||
QueueEvent( safenew LabelTrackEvent{
|
||||
EVT_LABELTRACK_ADDITION, SharedPointer<LabelTrack>(), title, -1, pos
|
||||
} );
|
||||
|
||||
return pos;
|
||||
}
|
||||
@ -2850,7 +2868,24 @@ int LabelTrack::AddLabel(const SelectedRegion &selectedRegion,
|
||||
void LabelTrack::DeleteLabel(int index)
|
||||
{
|
||||
wxASSERT((index < (int)mLabels.size()));
|
||||
mLabels.erase(mLabels.begin() + index);
|
||||
auto iter = mLabels.begin() + index;
|
||||
const auto title = iter->title;
|
||||
mLabels.erase(iter);
|
||||
|
||||
// wxWidgets will own the event object
|
||||
QueueEvent( safenew LabelTrackEvent{
|
||||
EVT_LABELTRACK_DELETION, SharedPointer<LabelTrack>(), title, index, -1
|
||||
} );
|
||||
}
|
||||
|
||||
void LabelTrack::OnLabelDeleted( LabelTrackEvent &e )
|
||||
{
|
||||
e.Skip();
|
||||
if ( e.mpTrack.lock().get() != this )
|
||||
return;
|
||||
|
||||
auto index = e.mFormerPosition;
|
||||
|
||||
// IF we've deleted the selected label
|
||||
// THEN set no label selected.
|
||||
if( mSelIndex== index )
|
||||
@ -2866,6 +2901,23 @@ void LabelTrack::DeleteLabel(int index)
|
||||
}
|
||||
}
|
||||
|
||||
void LabelTrack::OnLabelPermuted( LabelTrackEvent &e )
|
||||
{
|
||||
e.Skip();
|
||||
if ( e.mpTrack.lock().get() != this )
|
||||
return;
|
||||
|
||||
auto former = e.mFormerPosition;
|
||||
auto present = e.mPresentPosition;
|
||||
|
||||
if ( mSelIndex == former )
|
||||
mSelIndex = present;
|
||||
else if ( former < mSelIndex && mSelIndex <= present )
|
||||
-- mSelIndex;
|
||||
else if ( former > mSelIndex && mSelIndex >= present )
|
||||
++ mSelIndex;
|
||||
}
|
||||
|
||||
wxBitmap & LabelTrack::GetGlyph( int i)
|
||||
{
|
||||
return theTheme.Bitmap( i + bmpLabelGlyph0);
|
||||
@ -3013,7 +3065,7 @@ static bool IsGoodLabelEditKey(const wxKeyEvent & evt)
|
||||
/// This function is called often (whilst dragging a label)
|
||||
/// We expect them to be very nearly in order, so insertion
|
||||
/// sort (with a linear search) is a reasonable choice.
|
||||
void LabelTrack::SortLabels( LabelTrackHit *pHit )
|
||||
void LabelTrack::SortLabels()
|
||||
{
|
||||
const auto begin = mLabels.begin();
|
||||
const auto nn = (int)mLabels.size();
|
||||
@ -3039,20 +3091,12 @@ void LabelTrack::SortLabels( LabelTrackHit *pHit )
|
||||
begin + i + 1
|
||||
);
|
||||
|
||||
// Various indices need to be updated with the moved items...
|
||||
auto update = [=](int &index) {
|
||||
if( index <= i ) {
|
||||
if( index == i )
|
||||
index = j;
|
||||
else if( index >= j)
|
||||
++index;
|
||||
}
|
||||
};
|
||||
if ( pHit ) {
|
||||
update( pHit->mMouseOverLabelLeft );
|
||||
update( pHit->mMouseOverLabelRight );
|
||||
}
|
||||
update(mSelIndex);
|
||||
// Let listeners update their stored indices
|
||||
// wxWidgets will own the event object
|
||||
QueueEvent( safenew LabelTrackEvent{
|
||||
EVT_LABELTRACK_PERMUTED, SharedPointer<LabelTrack>(),
|
||||
mLabels[j].title, i, j
|
||||
} );
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -31,6 +31,7 @@ class DirManager;
|
||||
class TimeWarper;
|
||||
class ZoomInfo;
|
||||
|
||||
class LabelTrackEvent;
|
||||
|
||||
struct LabelTrackHit;
|
||||
struct TrackPanelDrawingContext;
|
||||
@ -102,7 +103,9 @@ const int NUM_GLYPH_CONFIGS = 3;
|
||||
const int NUM_GLYPH_HIGHLIGHTS = 4;
|
||||
const int MAX_NUM_ROWS =80;
|
||||
|
||||
class AUDACITY_DLL_API LabelTrack final : public Track
|
||||
class AUDACITY_DLL_API LabelTrack final
|
||||
: public Track
|
||||
, public wxEvtHandler
|
||||
{
|
||||
friend class LabelTrackView;
|
||||
friend class LabelStruct;
|
||||
@ -253,7 +256,8 @@ public:
|
||||
int FindPrevLabel(const SelectedRegion& currentSelection);
|
||||
|
||||
public:
|
||||
void SortLabels(LabelTrackHit *pHit = nullptr);
|
||||
void SortLabels();
|
||||
|
||||
private:
|
||||
TrackKind GetKind() const override { return TrackKind::Label; }
|
||||
|
||||
@ -296,6 +300,10 @@ private:
|
||||
void calculateFontHeight(wxDC & dc) const;
|
||||
void RemoveSelectedText();
|
||||
|
||||
void OnLabelAdded( LabelTrackEvent& );
|
||||
void OnLabelDeleted( LabelTrackEvent& );
|
||||
void OnLabelPermuted( LabelTrackEvent& );
|
||||
|
||||
static wxFont msFont;
|
||||
|
||||
protected:
|
||||
@ -303,4 +311,44 @@ protected:
|
||||
std::shared_ptr<TrackControls> DoGetControls() override;
|
||||
};
|
||||
|
||||
struct LabelTrackEvent : TrackListEvent
|
||||
{
|
||||
explicit
|
||||
LabelTrackEvent(
|
||||
wxEventType commandType, const std::shared_ptr<LabelTrack> &pTrack,
|
||||
const wxString &title,
|
||||
int formerPosition,
|
||||
int presentPosition
|
||||
)
|
||||
: TrackListEvent{ commandType, pTrack }
|
||||
, mTitle{ title }
|
||||
, mFormerPosition{ formerPosition }
|
||||
, mPresentPosition{ presentPosition }
|
||||
{}
|
||||
|
||||
LabelTrackEvent( const LabelTrackEvent& ) = default;
|
||||
wxEvent *Clone() const override {
|
||||
// wxWidgets will own the event object
|
||||
return safenew LabelTrackEvent(*this); }
|
||||
|
||||
wxString mTitle;
|
||||
|
||||
// invalid for addition event
|
||||
int mFormerPosition{ -1 };
|
||||
|
||||
// invalid for deletion event
|
||||
int mPresentPosition{ -1 };
|
||||
};
|
||||
|
||||
// Posted when a label is added.
|
||||
wxDECLARE_EXPORTED_EVENT(AUDACITY_DLL_API,
|
||||
EVT_LABELTRACK_ADDITION, LabelTrackEvent);
|
||||
|
||||
// Posted when a label is deleted.
|
||||
wxDECLARE_EXPORTED_EVENT(AUDACITY_DLL_API,
|
||||
EVT_LABELTRACK_DELETION, LabelTrackEvent);
|
||||
|
||||
// Posted when a label is repositioned in the sequence of labels.
|
||||
wxDECLARE_EXPORTED_EVENT(AUDACITY_DLL_API,
|
||||
EVT_LABELTRACK_PERMUTED, LabelTrackEvent);
|
||||
#endif
|
||||
|
@ -1081,7 +1081,9 @@ struct TrackListEvent : public wxCommandEvent
|
||||
|
||||
TrackListEvent( const TrackListEvent& ) = default;
|
||||
|
||||
wxEvent *Clone() const override { return new TrackListEvent(*this); }
|
||||
wxEvent *Clone() const override {
|
||||
// wxWidgets will own the event object
|
||||
return safenew TrackListEvent(*this); }
|
||||
|
||||
std::weak_ptr<Track> mpTrack;
|
||||
int mCode;
|
||||
|
@ -22,10 +22,46 @@ Paul Licameli split from TrackPanel.cpp
|
||||
#include <wx/cursor.h>
|
||||
#include <wx/translation.h>
|
||||
|
||||
LabelTrackHit::LabelTrackHit( const std::shared_ptr<LabelTrack> &pLT )
|
||||
: mpLT{ pLT }
|
||||
{
|
||||
pLT->Bind(
|
||||
EVT_LABELTRACK_PERMUTED, &LabelTrackHit::OnLabelPermuted, this );
|
||||
}
|
||||
|
||||
LabelTrackHit::~LabelTrackHit()
|
||||
{
|
||||
// Must do this because this sink isn't wxEvtHandler
|
||||
mpLT->Unbind(
|
||||
EVT_LABELTRACK_PERMUTED, &LabelTrackHit::OnLabelPermuted, this );
|
||||
}
|
||||
|
||||
void LabelTrackHit::OnLabelPermuted( LabelTrackEvent &e )
|
||||
{
|
||||
e.Skip();
|
||||
if ( e.mpTrack.lock() != mpLT )
|
||||
return;
|
||||
|
||||
auto former = e.mFormerPosition;
|
||||
auto present = e.mPresentPosition;
|
||||
|
||||
auto update = [=]( int &index ){
|
||||
if ( index == former )
|
||||
index = present;
|
||||
else if ( former < index && index <= present )
|
||||
-- index;
|
||||
else if ( former > index && index >= present )
|
||||
++ index;
|
||||
};
|
||||
|
||||
update( mMouseOverLabelLeft );
|
||||
update( mMouseOverLabelRight );
|
||||
}
|
||||
|
||||
LabelGlyphHandle::LabelGlyphHandle
|
||||
(const std::shared_ptr<LabelTrack> &pLT,
|
||||
const wxRect &rect, const LabelTrackHit &hit)
|
||||
: mHit{ hit }
|
||||
const wxRect &rect, const std::shared_ptr<LabelTrackHit> &pHit)
|
||||
: mpHit{ pHit }
|
||||
, mpLT{ pLT }
|
||||
, mRect{ rect }
|
||||
{
|
||||
@ -39,7 +75,7 @@ void LabelGlyphHandle::Enter(bool)
|
||||
UIHandle::Result LabelGlyphHandle::NeedChangeHighlight
|
||||
(const LabelGlyphHandle &oldState, const LabelGlyphHandle &newState)
|
||||
{
|
||||
if (oldState.mHit.mEdge != newState.mHit.mEdge)
|
||||
if (oldState.mpHit->mEdge != newState.mpHit->mEdge)
|
||||
// pointer moves between the circle and the chevron
|
||||
return RefreshCode::RefreshCell;
|
||||
return 0;
|
||||
@ -61,14 +97,18 @@ UIHandlePtr LabelGlyphHandle::HitTest
|
||||
const wxMouseState &state,
|
||||
const std::shared_ptr<LabelTrack> &pLT, const wxRect &rect)
|
||||
{
|
||||
LabelTrackHit hit{};
|
||||
pLT->OverGlyph(hit, state.m_x, state.m_y);
|
||||
// Allocate on heap because there are pointers to it when it is bound as
|
||||
// an event sink, therefore it's not copyable; make it shared so
|
||||
// LabelGlyphHandle can be copyable:
|
||||
auto pHit = std::make_shared<LabelTrackHit>( pLT );
|
||||
|
||||
pLT->OverGlyph(*pHit, state.m_x, state.m_y);
|
||||
|
||||
// IF edge!=0 THEN we've set the cursor and we're done.
|
||||
// signal this by setting the tip.
|
||||
if ( hit.mEdge & 3 )
|
||||
if ( pHit->mEdge & 3 )
|
||||
{
|
||||
auto result = std::make_shared<LabelGlyphHandle>( pLT, rect, hit );
|
||||
auto result = std::make_shared<LabelGlyphHandle>( pLT, rect, pHit );
|
||||
result = AssignUIHandlePtr(holder, result);
|
||||
return result;
|
||||
}
|
||||
@ -89,9 +129,9 @@ UIHandle::Result LabelGlyphHandle::Click
|
||||
|
||||
auto &viewInfo = ViewInfo::Get( *pProject );
|
||||
mpLT->HandleGlyphClick
|
||||
(mHit, event, mRect, viewInfo, &viewInfo.selectedRegion);
|
||||
(*mpHit, event, mRect, viewInfo, &viewInfo.selectedRegion);
|
||||
|
||||
if (! mHit.mIsAdjustingLabel )
|
||||
if (! mpHit->mIsAdjustingLabel )
|
||||
{
|
||||
// The positive hit test should have ensured otherwise
|
||||
//wxASSERT(false);
|
||||
@ -119,7 +159,7 @@ UIHandle::Result LabelGlyphHandle::Drag
|
||||
const wxMouseEvent &event = evt.event;
|
||||
auto &viewInfo = ViewInfo::Get( *pProject );
|
||||
mpLT->HandleGlyphDragRelease
|
||||
(mHit, event, mRect, viewInfo, &viewInfo.selectedRegion);
|
||||
(*mpHit, event, mRect, viewInfo, &viewInfo.selectedRegion);
|
||||
|
||||
// Refresh all so that the change of selection is redrawn in all tracks
|
||||
return result | RefreshCode::RefreshAll | RefreshCode::DrawOverlays;
|
||||
@ -128,7 +168,7 @@ UIHandle::Result LabelGlyphHandle::Drag
|
||||
HitTestPreview LabelGlyphHandle::Preview
|
||||
(const TrackPanelMouseState &, const AudacityProject *)
|
||||
{
|
||||
return HitPreview( (mHit.mEdge & 4 )!=0);
|
||||
return HitPreview( (mpHit->mEdge & 4 )!=0);
|
||||
}
|
||||
|
||||
UIHandle::Result LabelGlyphHandle::Release
|
||||
@ -140,7 +180,7 @@ UIHandle::Result LabelGlyphHandle::Release
|
||||
const wxMouseEvent &event = evt.event;
|
||||
auto &viewInfo = ViewInfo::Get( *pProject );
|
||||
if (mpLT->HandleGlyphDragRelease
|
||||
(mHit, event, mRect, viewInfo, &viewInfo.selectedRegion)) {
|
||||
(*mpHit, event, mRect, viewInfo, &viewInfo.selectedRegion)) {
|
||||
ProjectHistory::Get( *pProject ).PushState(_("Modified Label"),
|
||||
_("Label Edit"),
|
||||
UndoPush::CONSOLIDATE);
|
||||
|
@ -15,6 +15,7 @@ Paul Licameli split from TrackPanel.cpp
|
||||
|
||||
class wxMouseState;
|
||||
class LabelTrack;
|
||||
class LabelTrackEvent;
|
||||
|
||||
/// mEdge:
|
||||
/// 0 if not over a glyph,
|
||||
@ -26,12 +27,20 @@ class LabelTrack;
|
||||
/// mMouseLabelLeft - index of any left label hit
|
||||
/// mMouseLabelRight - index of any right label hit
|
||||
///
|
||||
struct LabelTrackHit {
|
||||
struct LabelTrackHit
|
||||
{
|
||||
LabelTrackHit( const std::shared_ptr<LabelTrack> &pLT );
|
||||
~LabelTrackHit();
|
||||
|
||||
int mEdge{};
|
||||
int mMouseOverLabelLeft{ -1 }; /// Keeps track of which left label the mouse is currently over.
|
||||
int mMouseOverLabelRight{ -1 }; /// Keeps track of which right label the mouse is currently over.
|
||||
bool mbIsMoving {};
|
||||
bool mIsAdjustingLabel {};
|
||||
|
||||
std::shared_ptr<LabelTrack> mpLT {};
|
||||
|
||||
void OnLabelPermuted( LabelTrackEvent &e );
|
||||
};
|
||||
|
||||
class LabelGlyphHandle final : public LabelDefaultClickHandle
|
||||
@ -41,7 +50,7 @@ class LabelGlyphHandle final : public LabelDefaultClickHandle
|
||||
public:
|
||||
explicit LabelGlyphHandle
|
||||
(const std::shared_ptr<LabelTrack> &pLT,
|
||||
const wxRect &rect, const LabelTrackHit &hit);
|
||||
const wxRect &rect, const std::shared_ptr<LabelTrackHit> &pHit);
|
||||
|
||||
LabelGlyphHandle &operator=(const LabelGlyphHandle&) = default;
|
||||
|
||||
@ -72,7 +81,7 @@ public:
|
||||
|
||||
bool StopsOnKeystroke() override { return true; }
|
||||
|
||||
LabelTrackHit mHit{};
|
||||
std::shared_ptr<LabelTrackHit> mpHit{};
|
||||
|
||||
static UIHandle::Result NeedChangeHighlight
|
||||
(const LabelGlyphHandle &oldState, const LabelGlyphHandle &newState);
|
||||
|
Loading…
x
Reference in New Issue
Block a user