Split base class CellularPanel out of TrackPanel...

... To be reused with the Ruler too.

The new base class does all the handling of hit tests on cells and managing
of UIHandles, and keyboard events and focus.

It has no knowledge of tracks -- that all resides in overriding functions in
TrackPanel.

Still to do, of course, is reorganizing drawing with callbacks to the cell
objects.
This commit is contained in:
Paul Licameli 2018-06-24 23:17:36 -04:00
parent d76777bef7
commit 062066eb79
2 changed files with 254 additions and 166 deletions

View File

@ -254,16 +254,22 @@ template < class A, class B, class DIST > bool within(A a, B b, DIST d)
return (a > b - d) && (a < b + d);
}
BEGIN_EVENT_TABLE(TrackPanel, OverlayPanel)
BEGIN_EVENT_TABLE(CellularPanel, OverlayPanel)
EVT_MOUSE_EVENTS(CellularPanel::OnMouseEvent)
EVT_MOUSE_CAPTURE_LOST(CellularPanel::OnCaptureLost)
EVT_COMMAND(wxID_ANY, EVT_CAPTURE_KEY, CellularPanel::OnCaptureKey)
EVT_KEY_DOWN(CellularPanel::OnKeyDown)
EVT_KEY_UP(CellularPanel::OnKeyUp)
EVT_CHAR(CellularPanel::OnChar)
EVT_SET_FOCUS(CellularPanel::OnSetFocus)
EVT_KILL_FOCUS(CellularPanel::OnKillFocus)
END_EVENT_TABLE()
BEGIN_EVENT_TABLE(TrackPanel, CellularPanel)
EVT_MOUSE_EVENTS(TrackPanel::OnMouseEvent)
EVT_MOUSE_CAPTURE_LOST(TrackPanel::OnCaptureLost)
EVT_COMMAND(wxID_ANY, EVT_CAPTURE_KEY, TrackPanel::OnCaptureKey)
EVT_KEY_DOWN(TrackPanel::OnKeyDown)
EVT_KEY_UP(TrackPanel::OnKeyUp)
EVT_CHAR(TrackPanel::OnChar)
EVT_PAINT(TrackPanel::OnPaint)
EVT_SET_FOCUS(TrackPanel::OnSetFocus)
EVT_KILL_FOCUS(TrackPanel::OnKillFocus)
EVT_CONTEXT_MENU(TrackPanel::OnContextMenu)
EVT_TIMER(wxID_ANY, TrackPanel::OnTimer)
@ -301,11 +307,11 @@ TrackPanel::TrackPanel(wxWindow * parent, wxWindowID id,
ViewInfo * viewInfo,
TrackPanelListener * listener,
AdornedRulerPanel * ruler)
: OverlayPanel(parent, id, pos, size, wxWANTS_CHARS | wxNO_BORDER),
: CellularPanel(parent, id, pos, size, viewInfo,
wxWANTS_CHARS | wxNO_BORDER),
mTrackInfo(this),
mListener(listener),
mTracks(tracks),
mViewInfo(viewInfo),
mRuler(ruler),
mTrackArtist(nullptr),
mRefreshBacking(false),
@ -614,7 +620,7 @@ void TrackPanel::MakeParentRedrawScrollbars()
mListener->TP_RedrawScrollbars();
}
void TrackPanel::HandleInterruptedDrag()
void CellularPanel::HandleInterruptedDrag()
{
if (mUIHandle && mUIHandle->StopsOnKeystroke() ) {
// The bogus id isn't used anywhere, but may help with debugging.
@ -718,7 +724,7 @@ void TrackPanel::ProcessUIHandleResult
panel->EnsureVisible(pClickedTrack);
}
void TrackPanel::Uncapture(wxMouseState *pState)
void CellularPanel::Uncapture(wxMouseState *pState)
{
auto state = ::wxGetMouseState();
if (!pState) {
@ -732,7 +738,7 @@ void TrackPanel::Uncapture(wxMouseState *pState)
HandleMotion( *pState );
}
bool TrackPanel::CancelDragging()
bool CellularPanel::CancelDragging()
{
if (mUIHandle) {
// copy shared_ptr for safety, as in HandleClick
@ -752,7 +758,7 @@ bool TrackPanel::CancelDragging()
return false;
}
bool TrackPanel::HandleEscapeKey(bool down)
bool CellularPanel::HandleEscapeKey(bool down)
{
if (!down)
return false;
@ -778,7 +784,7 @@ bool TrackPanel::HandleEscapeKey(bool down)
return false;
}
void TrackPanel::UpdateMouseState(const wxMouseState &state)
void CellularPanel::UpdateMouseState(const wxMouseState &state)
{
mLastMouseState = state;
@ -798,7 +804,7 @@ void TrackPanel::UpdateMouseState(const wxMouseState &state)
}
}
void TrackPanel::HandleModifierKey()
void CellularPanel::HandleModifierKey()
{
HandleCursorForPresentMouseState();
}
@ -813,7 +819,7 @@ void TrackPanel::HandlePageDownKey()
mListener->TP_ScrollWindow(GetScreenEndTime());
}
void TrackPanel::HandleCursorForPresentMouseState(bool doHit)
void CellularPanel::HandleCursorForPresentMouseState(bool doHit)
{
// Come here on modifier key or mouse button transitions,
// or on starting or stopping of play or record,
@ -842,7 +848,7 @@ bool TrackPanel::IsAudioActive()
/// may cause the appropriate cursor and message to change.
/// As this procedure checks which region the mouse is over, it is
/// appropriate to establish the message in the status bar.
void TrackPanel::HandleMotion( wxMouseState &inState, bool doHit )
void CellularPanel::HandleMotion( wxMouseState &inState, bool doHit )
{
UpdateMouseState( inState );
@ -853,7 +859,7 @@ void TrackPanel::HandleMotion( wxMouseState &inState, bool doHit )
HandleMotion( tpmState, doHit );
}
void TrackPanel::HandleMotion
void CellularPanel::HandleMotion
( const TrackPanelMouseState &tpmState, bool doHit )
{
auto handle = mUIHandle;
@ -955,11 +961,8 @@ void TrackPanel::HandleMotion
pCursor = &defaultCursor;
}
if (HasEscape())
/* i18n-hint Esc is a key on the keyboard */
status += wxT(" "), status += _("(Esc to cancel)");
mListener->TP_DisplayStatusMessage(status);
UpdateStatusMessage(status);
#if wxUSE_TOOLTIPS
if (tooltip != GetToolTipText()) {
// Unset first, by analogy with AButton
@ -975,7 +978,16 @@ void TrackPanel::HandleMotion
newCell.get(), newCell.get(), refreshCode);
}
bool TrackPanel::HasRotation()
void TrackPanel::UpdateStatusMessage( const wxString &st )
{
auto status = st;
if (HasEscape())
/* i18n-hint Esc is a key on the keyboard */
status += wxT(" "), status += _("(Esc to cancel)");
mListener->TP_DisplayStatusMessage(status);
}
bool CellularPanel::HasRotation()
{
// Is there a nontrivial TAB key rotation?
if ( mTargets.size() > 1 )
@ -984,7 +996,7 @@ bool TrackPanel::HasRotation()
return target && target->HasRotation();
}
bool TrackPanel::HasEscape()
bool CellularPanel::HasEscape()
{
if (IsMouseCaptured())
return true;
@ -997,7 +1009,7 @@ bool TrackPanel::HasEscape()
return mTargets.size() > 0;
}
bool TrackPanel::ChangeTarget(bool forward, bool cycle)
bool CellularPanel::ChangeTarget(bool forward, bool cycle)
{
auto size = mTargets.size();
@ -1090,7 +1102,7 @@ void TrackPanel::MessageForScreenReader(const wxString& message)
}
/// Determines if a modal tool is active
bool TrackPanel::IsMouseCaptured()
bool CellularPanel::IsMouseCaptured()
{
return mUIHandle != NULL;
}
@ -1140,9 +1152,9 @@ void TrackPanel::OnTrackListResizing(wxCommandEvent & e)
// Tracks have been removed from the list.
void TrackPanel::OnTrackListDeletion(wxCommandEvent & e)
{
if (mUIHandle) {
// copy shared_ptr for safety, as in HandleClick
auto handle = mUIHandle;
// copy shared_ptr for safety, as in HandleClick
auto handle = Target();
if (handle) {
handle->OnProjectChange(GetProject());
}
@ -1349,7 +1361,7 @@ bool TrackInfo::HideTopItem( const wxRect &rect, const wxRect &subRect,
}
/// Handle mouse wheel rotation (for zoom in/out, vertical and horizontal scrolling)
void TrackPanel::HandleWheelRotation( TrackPanelMouseEvent &tpmEvent )
void CellularPanel::HandleWheelRotation( TrackPanelMouseEvent &tpmEvent )
{
auto pCell = tpmEvent.pCell;
if (!pCell)
@ -1395,7 +1407,7 @@ void TrackPanel::HandleWheelRotation( TrackPanelMouseEvent &tpmEvent )
pCell.get(), pCell.get(), result);
}
void TrackPanel::OnCaptureKey(wxCommandEvent & event)
void CellularPanel::OnCaptureKey(wxCommandEvent & event)
{
mEnableTab = false;
wxKeyEvent *kevent = static_cast<wxKeyEvent *>(event.GetEventObject());
@ -1403,19 +1415,17 @@ void TrackPanel::OnCaptureKey(wxCommandEvent & event)
if ( WXK_ESCAPE != code )
HandleInterruptedDrag();
// TODO? Some notion of focused cell, more generally than focused tracks
// Give focused track precedence
Track * const t = GetFocusedTrack();
// Give focused cell precedence
const auto t = GetFocusedCell();
if (t) {
const unsigned refreshResult =
((TrackPanelCell*)t)->CaptureKey(*kevent, *mViewInfo, this);
t->CaptureKey(*kevent, *mViewInfo, this);
ProcessUIHandleResult(t, t, refreshResult);
event.Skip(kevent->GetSkipped());
}
#if 0
// Special TAB key handling, but only if the track didn't capture it
// Special TAB key handling, but only if the cell didn't capture it
if ( !(t && !kevent->GetSkipped()) &&
WXK_TAB == code && HasRotation() ) {
// Override TAB navigation in wxWidgets, by not skipping
@ -1430,6 +1440,26 @@ void TrackPanel::OnCaptureKey(wxCommandEvent & event)
}
void TrackPanel::OnKeyDown(wxKeyEvent & event)
{
switch (event.GetKeyCode())
{
// Allow PageUp and PageDown keys to
//scroll the Track Panel left and right
case WXK_PAGEUP:
HandlePageUpKey();
return;
case WXK_PAGEDOWN:
HandlePageDownKey();
return;
default:
// fall through to base class handler
event.Skip();
}
}
void CellularPanel::OnKeyDown(wxKeyEvent & event)
{
switch (event.GetKeyCode())
{
@ -1450,16 +1480,6 @@ void TrackPanel::OnKeyDown(wxKeyEvent & event)
HandleModifierKey();
break;
// Allow PageUp and PageDown keys to
//scroll the Track Panel left and right
case WXK_PAGEUP:
HandlePageUpKey();
return;
case WXK_PAGEDOWN:
HandlePageDownKey();
return;
#if 0
case WXK_TAB:
if ( mEnableTab && HasRotation() ) {
@ -1472,18 +1492,18 @@ void TrackPanel::OnKeyDown(wxKeyEvent & event)
#endif
}
Track *const t = GetFocusedTrack();
const auto t = GetFocusedCell();
if (t) {
const unsigned refreshResult =
((TrackPanelCell*)t)->KeyDown(event, *mViewInfo, this);
t->KeyDown(event, *mViewInfo, this);
ProcessUIHandleResult(t, t, refreshResult);
}
else
event.Skip();
}
void TrackPanel::OnChar(wxKeyEvent & event)
void CellularPanel::OnChar(wxKeyEvent & event)
{
switch (event.GetKeyCode())
{
@ -1496,17 +1516,17 @@ void TrackPanel::OnChar(wxKeyEvent & event)
return;
}
Track *const t = GetFocusedTrack();
const auto t = GetFocusedCell();
if (t) {
const unsigned refreshResult =
((TrackPanelCell*)t)->Char(event, *mViewInfo, this);
t->Char(event, *mViewInfo, this);
ProcessUIHandleResult(t, t, refreshResult);
}
else
event.Skip();
}
void TrackPanel::OnKeyUp(wxKeyEvent & event)
void CellularPanel::OnKeyUp(wxKeyEvent & event)
{
bool didSomething = false;
switch (event.GetKeyCode())
@ -1528,10 +1548,10 @@ void TrackPanel::OnKeyUp(wxKeyEvent & event)
if (didSomething)
return;
Track * const t = GetFocusedTrack();
const auto t = GetFocusedCell();
if (t) {
const unsigned refreshResult =
((TrackPanelCell*)t)->KeyUp(event, *mViewInfo, this);
t->KeyUp(event, *mViewInfo, this);
ProcessUIHandleResult(t, t, refreshResult);
return;
}
@ -1540,7 +1560,7 @@ void TrackPanel::OnKeyUp(wxKeyEvent & event)
}
/// Should handle the case when the mouse capture is lost.
void TrackPanel::OnCaptureLost(wxMouseCaptureLostEvent & WXUNUSED(event))
void CellularPanel::OnCaptureLost(wxMouseCaptureLostEvent & WXUNUSED(event))
{
ClearTargets();
@ -1554,10 +1574,37 @@ void TrackPanel::OnCaptureLost(wxMouseCaptureLostEvent & WXUNUSED(event))
OnMouseEvent(e);
}
void TrackPanel::OnMouseEvent(wxMouseEvent & event)
{
if (event.LeftDown()) {
// wxTimers seem to be a little unreliable, so this
// "primes" it to make sure it keeps going for a while...
// When this timer fires, we call TrackPanel::OnTimer and
// possibly update the screen for offscreen scrolling.
mTimer.Stop();
mTimer.Start(kTimerInterval, FALSE);
}
if (event.ButtonUp()) {
//EnsureVisible should be called after processing the up-click.
this->CallAfter( [this, event]{
const auto foundCell = FindCell(event.m_x, event.m_y);
const auto t = FindTrack( foundCell.pCell.get() );
if ( t )
EnsureVisible(t.get());
} );
}
// Must also fall through to base class handler
event.Skip();
}
/// This handles just generic mouse events. Then, based
/// on our current state, we forward the mouse events to
/// various interested parties.
void TrackPanel::OnMouseEvent(wxMouseEvent & event)
void CellularPanel::OnMouseEvent(wxMouseEvent & event)
try
{
const auto foundCell = FindCell( event.m_x, event.m_y );
@ -1578,7 +1625,7 @@ try
// If a mouse event originates from a keyboard context menu event then
// event.GetPosition() == wxDefaultPosition. wxContextMenu events are handled in
// TrackPanel::OnContextMenu(), and therefore associated mouse events are ignored here.
// CellularPanel::OnContextMenu(), and therefore associated mouse events are ignored here.
// Not ignoring them was causing bug 613: the mouse events were interpreted as clicking
// outside the tracks.
if (event.GetPosition() == wxDefaultPosition && (event.RightDown() || event.RightUp())) {
@ -1604,14 +1651,6 @@ try
// parent window 'come alive' if it didn't have focus.
wxActivateEvent e;
GetParent()->GetEventHandler()->ProcessEvent(e);
// wxTimers seem to be a little unreliable, so this
// "primes" it to make sure it keeps going for a while...
// When this timer fires, we call TrackPanel::OnTimer and
// possibly update the screen for offscreen scrolling.
mTimer.Stop();
mTimer.Start(kTimerInterval, FALSE);
}
if (event.ButtonDown()) {
@ -1692,17 +1731,8 @@ try
CaptureMouse();
}
//EnsureVisible should be called after the up-click.
if (event.ButtonUp()) {
if (event.ButtonUp())
Uncapture();
wxRect rect;
const auto foundCell = FindCell(event.m_x, event.m_y);
const auto t = FindTrack( foundCell.pCell.get() );
if ( t )
EnsureVisible(t.get());
}
}
catch( ... )
{
@ -1716,7 +1746,7 @@ catch( ... )
throw;
}
void TrackPanel::HandleClick( const TrackPanelMouseEvent &tpmEvent )
void CellularPanel::HandleClick( const TrackPanelMouseEvent &tpmEvent )
{
auto pCell = tpmEvent.pCell;
@ -1762,7 +1792,7 @@ void TrackPanel::HandleClick( const TrackPanelMouseEvent &tpmEvent )
double TrackPanel::GetMostRecentXPos()
{
return mViewInfo->PositionToTime(mMouseMostRecentX, GetLabelWidth());
return mViewInfo->PositionToTime(MostRecentXCoord(), GetLabelWidth());
}
void TrackPanel::RefreshTrack(Track *trk, bool refreshbacking)
@ -2779,7 +2809,7 @@ void TrackPanel::DrawShadow(Track * /* t */ , wxDC * dc, const wxRect & rect)
/// Determines which cell is under the mouse
/// @param mouseX - mouse X position.
/// @param mouseY - mouse Y position.
TrackPanel::FoundCell TrackPanel::FindCell(int mouseX, int mouseY)
auto TrackPanel::FindCell(int mouseX, int mouseY) -> FoundCell
{
auto range = Cells();
auto &iter = range.first, &end = range.second;
@ -2861,36 +2891,41 @@ void TrackPanel::DisplaySelection()
mListener->TP_DisplaySelection();
}
Track *TrackPanel::GetFocusedTrack()
TrackPanelCell *TrackPanel::GetFocusedCell()
{
return mAx->GetFocus().get();
}
Track *TrackPanel::GetFocusedTrack()
{
return static_cast<Track*>( GetFocusedCell() );
}
void TrackPanel::SetFocusedCell()
{
SetFocusedTrack( GetFocusedTrack() );
}
void TrackPanel::SetFocusedTrack( Track *t )
{
// Make sure we always have the first linked track of a stereo track
if (t && !t->GetLinked() && t->GetLink())
t = (WaveTrack*)t->GetLink();
if ( !mAx->SetFocus( Track::Pointer( t ) ) )
return;
auto cell = mAx->SetFocus( Track::Pointer( t ) ).get();
if (t && AudacityProject::GetKeyboardCaptureHandler())
AudacityProject::ReleaseKeyboard(this);
if (t)
if (cell) {
AudacityProject::CaptureKeyboard(this);
Refresh( false );
Refresh( false );
}
}
void TrackPanel::OnSetFocus(wxFocusEvent & WXUNUSED(event))
void CellularPanel::OnSetFocus(wxFocusEvent & WXUNUSED(event))
{
SetFocusedTrack( GetFocusedTrack() );
Refresh( false );
SetFocusedCell();
}
void TrackPanel::OnKillFocus(wxFocusEvent & WXUNUSED(event))
void CellularPanel::OnKillFocus(wxFocusEvent & WXUNUSED(event))
{
if (AudacityProject::HasKeyboardCapture(this))
{

View File

@ -242,9 +242,126 @@ private:
const int DragThreshold = 3;// Anything over 3 pixels is a drag, else a click.
class AUDACITY_DLL_API TrackPanel final : public OverlayPanel {
public:
// This class manages a panel divided into a number of sub-rectangles called
// cells, that each implement hit tests returning click-drag-release handler
// objects, and other services.
// It has no dependency on the Track class.
class AUDACITY_DLL_API CellularPanel : public OverlayPanel {
public:
CellularPanel(wxWindow * parent, wxWindowID id,
const wxPoint & pos,
const wxSize & size,
ViewInfo *viewInfo,
// default as for wxPanel:
long style = wxTAB_TRAVERSAL | wxNO_BORDER)
: OverlayPanel(parent, id, pos, size, style)
, mViewInfo( viewInfo )
{}
// Overridables:
virtual AudacityProject *GetProject() const = 0;
// Find track info by coordinate
struct FoundCell {
std::shared_ptr<TrackPanelCell> pCell;
wxRect rect;
};
virtual FoundCell FindCell(int mouseX, int mouseY) = 0;
virtual TrackPanelCell *GetFocusedCell() = 0;
virtual void SetFocusedCell() = 0;
virtual void ProcessUIHandleResult
(TrackPanelCell *pClickedCell, TrackPanelCell *pLatestCell,
unsigned refreshResult) = 0;
virtual void UpdateStatusMessage( const wxString & ) = 0;
public:
UIHandlePtr Target()
{
if (mTargets.size())
return mTargets[mTarget];
else
return {};
}
bool IsMouseCaptured();
wxCoord MostRecentXCoord() const { return mMouseMostRecentX; }
void HandleCursorForPresentMouseState(bool doHit = true);
protected:
bool HasEscape();
bool CancelDragging();
void ClearTargets()
{
// Forget the rotation of hit test candidates when the mouse moves from
// cell to cell or outside of the panel entirely.
mLastCell.reset();
mTargets.clear();
mTarget = 0;
mMouseOverUpdateFlags = 0;
}
private:
bool HasRotation();
bool ChangeTarget(bool forward, bool cycle);
void OnMouseEvent(wxMouseEvent & event);
void OnCaptureLost(wxMouseCaptureLostEvent & event);
void OnCaptureKey(wxCommandEvent & event);
void OnKeyDown(wxKeyEvent & event);
void OnChar(wxKeyEvent & event);
void OnKeyUp(wxKeyEvent & event);
void OnSetFocus(wxFocusEvent & event);
void OnKillFocus(wxFocusEvent & event);
void HandleInterruptedDrag();
void Uncapture( wxMouseState *pState = nullptr );
bool HandleEscapeKey(bool down);
void UpdateMouseState(const wxMouseState &state);
void HandleModifierKey();
void HandleClick( const TrackPanelMouseEvent &tpmEvent );
void HandleWheelRotation( TrackPanelMouseEvent &tpmEvent );
void HandleMotion( wxMouseState &state, bool doHit = true );
void HandleMotion
( const TrackPanelMouseState &tpmState, bool doHit = true );
protected:
ViewInfo *mViewInfo;
private:
UIHandlePtr mUIHandle;
std::weak_ptr<TrackPanelCell> mLastCell;
std::vector<UIHandlePtr> mTargets;
size_t mTarget {};
unsigned mMouseOverUpdateFlags{};
protected:
// To do: make a drawing method and make this private
wxMouseState mLastMouseState;
private:
int mMouseMostRecentX;
int mMouseMostRecentY;
std::weak_ptr<TrackPanelCell> mpClickedCell;
bool mEnableTab{};
DECLARE_EVENT_TABLE()
};
class AUDACITY_DLL_API TrackPanel final : public CellularPanel {
public:
TrackPanel(wxWindow * parent,
wxWindowID id,
const wxPoint & pos,
@ -263,14 +380,7 @@ class AUDACITY_DLL_API TrackPanel final : public OverlayPanel {
void OnPaint(wxPaintEvent & event);
void OnMouseEvent(wxMouseEvent & event);
void OnCaptureLost(wxMouseCaptureLostEvent & event);
void OnCaptureKey(wxCommandEvent & event);
void OnKeyDown(wxKeyEvent & event);
void OnChar(wxKeyEvent & event);
void OnKeyUp(wxKeyEvent & event);
void OnSetFocus(wxFocusEvent & event);
void OnKillFocus(wxFocusEvent & event);
void OnContextMenu(wxContextMenuEvent & event);
@ -302,31 +412,24 @@ class AUDACITY_DLL_API TrackPanel final : public OverlayPanel {
// void SetSelectionFormat(int iformat)
// void SetSnapTo(int snapto)
void HandleInterruptedDrag();
void Uncapture( wxMouseState *pState = nullptr );
bool CancelDragging();
bool HandleEscapeKey(bool down);
void UpdateMouseState(const wxMouseState &state);
void HandleModifierKey();
void HandlePageUpKey();
void HandlePageDownKey();
AudacityProject * GetProject() const;
AudacityProject * GetProject() const override;
void ScrollIntoView(double pos);
void ScrollIntoView(int x);
void OnTrackMenu(Track *t = NULL);
Track * GetFirstSelectedTrack();
bool IsMouseCaptured();
void EnsureVisible(Track * t);
void VerticalScroll( float fracPosition);
TrackPanelCell *GetFocusedCell() override;
void SetFocusedCell() override;
Track *GetFocusedTrack();
void SetFocusedTrack(Track *t);
void HandleCursorForPresentMouseState(bool doHit = true);
void UpdateVRulers();
void UpdateVRuler(Track *t);
void UpdateTrackVRuler(const Track *t);
@ -338,7 +441,6 @@ class AUDACITY_DLL_API TrackPanel final : public OverlayPanel {
protected:
bool IsAudioActive();
void HandleClick( const TrackPanelMouseEvent &tpmEvent );
public:
size_t GetTrackCount() const;
@ -351,9 +453,6 @@ public:
void UpdateAccessibility();
void MessageForScreenReader(const wxString& message);
// MM: Handle mouse wheel rotation
void HandleWheelRotation( TrackPanelMouseEvent &tpmEvent );
void MakeParentRedrawScrollbars();
// If label, rectangle includes track control panel only.
@ -366,15 +465,7 @@ protected:
// a crash, as it can take many seconds for large (eg. 10 track-hours) projects
// Find track info by coordinate
struct FoundCell {
std::shared_ptr<TrackPanelCell> pCell;
wxRect rect;
};
FoundCell FindCell(int mouseX, int mouseY);
void HandleMotion( wxMouseState &state, bool doHit = true );
void HandleMotion
( const TrackPanelMouseState &tpmState, bool doHit = true );
FoundCell FindCell(int mouseX, int mouseY) override;
int GetVRulerWidth() const;
int GetVRulerOffset() const { return mTrackInfo.GetTrackInfoWidth(); }
@ -447,7 +538,6 @@ protected:
TrackPanelListener *mListener;
std::shared_ptr<TrackList> mTracks;
ViewInfo *mViewInfo;
AdornedRulerPanel *mRuler;
@ -481,11 +571,6 @@ protected:
bool mRedrawAfterStop;
wxMouseState mLastMouseState;
int mMouseMostRecentX;
int mMouseMostRecentY;
friend class TrackPanelAx;
#if wxUSE_ACCESSIBILITY
@ -510,48 +595,16 @@ protected:
wxSize vrulerSize;
protected:
std::weak_ptr<TrackPanelCell> mLastCell;
std::vector<UIHandlePtr> mTargets;
size_t mTarget {};
unsigned mMouseOverUpdateFlags{};
public:
UIHandlePtr Target()
{
if (mTargets.size())
return mTargets[mTarget];
else
return {};
}
protected:
void ClearTargets()
{
// Forget the rotation of hit test candidates when the mouse moves from
// cell to cell or outside of the TrackPanel entirely.
mLastCell.reset();
mTargets.clear();
mTarget = 0;
mMouseOverUpdateFlags = 0;
}
bool HasRotation();
bool HasEscape();
bool ChangeTarget(bool forward, bool cycle);
std::weak_ptr<TrackPanelCell> mpClickedCell;
UIHandlePtr mUIHandle;
std::shared_ptr<TrackPanelCell> mpBackground;
bool mEnableTab{};
DECLARE_EVENT_TABLE()
void ProcessUIHandleResult
(TrackPanelCell *pClickedCell, TrackPanelCell *pLatestCell,
unsigned refreshResult);
unsigned refreshResult) override;
void UpdateStatusMessage( const wxString &status ) override;
// friending GetInfoCommand allow automation to get sizes of the
// tracks, track control panel and such.