mirror of
https://github.com/cookiengineer/audacity
synced 2025-11-16 14:13:53 +01:00
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:
@@ -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);
|
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_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_DOWN(TrackPanel::OnKeyDown)
|
||||||
EVT_KEY_UP(TrackPanel::OnKeyUp)
|
|
||||||
EVT_CHAR(TrackPanel::OnChar)
|
|
||||||
EVT_PAINT(TrackPanel::OnPaint)
|
EVT_PAINT(TrackPanel::OnPaint)
|
||||||
EVT_SET_FOCUS(TrackPanel::OnSetFocus)
|
|
||||||
EVT_KILL_FOCUS(TrackPanel::OnKillFocus)
|
|
||||||
EVT_CONTEXT_MENU(TrackPanel::OnContextMenu)
|
EVT_CONTEXT_MENU(TrackPanel::OnContextMenu)
|
||||||
|
|
||||||
EVT_TIMER(wxID_ANY, TrackPanel::OnTimer)
|
EVT_TIMER(wxID_ANY, TrackPanel::OnTimer)
|
||||||
@@ -301,11 +307,11 @@ TrackPanel::TrackPanel(wxWindow * parent, wxWindowID id,
|
|||||||
ViewInfo * viewInfo,
|
ViewInfo * viewInfo,
|
||||||
TrackPanelListener * listener,
|
TrackPanelListener * listener,
|
||||||
AdornedRulerPanel * ruler)
|
AdornedRulerPanel * ruler)
|
||||||
: OverlayPanel(parent, id, pos, size, wxWANTS_CHARS | wxNO_BORDER),
|
: CellularPanel(parent, id, pos, size, viewInfo,
|
||||||
|
wxWANTS_CHARS | wxNO_BORDER),
|
||||||
mTrackInfo(this),
|
mTrackInfo(this),
|
||||||
mListener(listener),
|
mListener(listener),
|
||||||
mTracks(tracks),
|
mTracks(tracks),
|
||||||
mViewInfo(viewInfo),
|
|
||||||
mRuler(ruler),
|
mRuler(ruler),
|
||||||
mTrackArtist(nullptr),
|
mTrackArtist(nullptr),
|
||||||
mRefreshBacking(false),
|
mRefreshBacking(false),
|
||||||
@@ -614,7 +620,7 @@ void TrackPanel::MakeParentRedrawScrollbars()
|
|||||||
mListener->TP_RedrawScrollbars();
|
mListener->TP_RedrawScrollbars();
|
||||||
}
|
}
|
||||||
|
|
||||||
void TrackPanel::HandleInterruptedDrag()
|
void CellularPanel::HandleInterruptedDrag()
|
||||||
{
|
{
|
||||||
if (mUIHandle && mUIHandle->StopsOnKeystroke() ) {
|
if (mUIHandle && mUIHandle->StopsOnKeystroke() ) {
|
||||||
// The bogus id isn't used anywhere, but may help with debugging.
|
// The bogus id isn't used anywhere, but may help with debugging.
|
||||||
@@ -718,7 +724,7 @@ void TrackPanel::ProcessUIHandleResult
|
|||||||
panel->EnsureVisible(pClickedTrack);
|
panel->EnsureVisible(pClickedTrack);
|
||||||
}
|
}
|
||||||
|
|
||||||
void TrackPanel::Uncapture(wxMouseState *pState)
|
void CellularPanel::Uncapture(wxMouseState *pState)
|
||||||
{
|
{
|
||||||
auto state = ::wxGetMouseState();
|
auto state = ::wxGetMouseState();
|
||||||
if (!pState) {
|
if (!pState) {
|
||||||
@@ -732,7 +738,7 @@ void TrackPanel::Uncapture(wxMouseState *pState)
|
|||||||
HandleMotion( *pState );
|
HandleMotion( *pState );
|
||||||
}
|
}
|
||||||
|
|
||||||
bool TrackPanel::CancelDragging()
|
bool CellularPanel::CancelDragging()
|
||||||
{
|
{
|
||||||
if (mUIHandle) {
|
if (mUIHandle) {
|
||||||
// copy shared_ptr for safety, as in HandleClick
|
// copy shared_ptr for safety, as in HandleClick
|
||||||
@@ -752,7 +758,7 @@ bool TrackPanel::CancelDragging()
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool TrackPanel::HandleEscapeKey(bool down)
|
bool CellularPanel::HandleEscapeKey(bool down)
|
||||||
{
|
{
|
||||||
if (!down)
|
if (!down)
|
||||||
return false;
|
return false;
|
||||||
@@ -778,7 +784,7 @@ bool TrackPanel::HandleEscapeKey(bool down)
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
void TrackPanel::UpdateMouseState(const wxMouseState &state)
|
void CellularPanel::UpdateMouseState(const wxMouseState &state)
|
||||||
{
|
{
|
||||||
mLastMouseState = state;
|
mLastMouseState = state;
|
||||||
|
|
||||||
@@ -798,7 +804,7 @@ void TrackPanel::UpdateMouseState(const wxMouseState &state)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void TrackPanel::HandleModifierKey()
|
void CellularPanel::HandleModifierKey()
|
||||||
{
|
{
|
||||||
HandleCursorForPresentMouseState();
|
HandleCursorForPresentMouseState();
|
||||||
}
|
}
|
||||||
@@ -813,7 +819,7 @@ void TrackPanel::HandlePageDownKey()
|
|||||||
mListener->TP_ScrollWindow(GetScreenEndTime());
|
mListener->TP_ScrollWindow(GetScreenEndTime());
|
||||||
}
|
}
|
||||||
|
|
||||||
void TrackPanel::HandleCursorForPresentMouseState(bool doHit)
|
void CellularPanel::HandleCursorForPresentMouseState(bool doHit)
|
||||||
{
|
{
|
||||||
// Come here on modifier key or mouse button transitions,
|
// Come here on modifier key or mouse button transitions,
|
||||||
// or on starting or stopping of play or record,
|
// 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.
|
/// may cause the appropriate cursor and message to change.
|
||||||
/// As this procedure checks which region the mouse is over, it is
|
/// As this procedure checks which region the mouse is over, it is
|
||||||
/// appropriate to establish the message in the status bar.
|
/// 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 );
|
UpdateMouseState( inState );
|
||||||
|
|
||||||
@@ -853,7 +859,7 @@ void TrackPanel::HandleMotion( wxMouseState &inState, bool doHit )
|
|||||||
HandleMotion( tpmState, doHit );
|
HandleMotion( tpmState, doHit );
|
||||||
}
|
}
|
||||||
|
|
||||||
void TrackPanel::HandleMotion
|
void CellularPanel::HandleMotion
|
||||||
( const TrackPanelMouseState &tpmState, bool doHit )
|
( const TrackPanelMouseState &tpmState, bool doHit )
|
||||||
{
|
{
|
||||||
auto handle = mUIHandle;
|
auto handle = mUIHandle;
|
||||||
@@ -955,10 +961,7 @@ void TrackPanel::HandleMotion
|
|||||||
pCursor = &defaultCursor;
|
pCursor = &defaultCursor;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (HasEscape())
|
UpdateStatusMessage(status);
|
||||||
/* i18n-hint Esc is a key on the keyboard */
|
|
||||||
status += wxT(" "), status += _("(Esc to cancel)");
|
|
||||||
mListener->TP_DisplayStatusMessage(status);
|
|
||||||
|
|
||||||
#if wxUSE_TOOLTIPS
|
#if wxUSE_TOOLTIPS
|
||||||
if (tooltip != GetToolTipText()) {
|
if (tooltip != GetToolTipText()) {
|
||||||
@@ -975,7 +978,16 @@ void TrackPanel::HandleMotion
|
|||||||
newCell.get(), newCell.get(), refreshCode);
|
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?
|
// Is there a nontrivial TAB key rotation?
|
||||||
if ( mTargets.size() > 1 )
|
if ( mTargets.size() > 1 )
|
||||||
@@ -984,7 +996,7 @@ bool TrackPanel::HasRotation()
|
|||||||
return target && target->HasRotation();
|
return target && target->HasRotation();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool TrackPanel::HasEscape()
|
bool CellularPanel::HasEscape()
|
||||||
{
|
{
|
||||||
if (IsMouseCaptured())
|
if (IsMouseCaptured())
|
||||||
return true;
|
return true;
|
||||||
@@ -997,7 +1009,7 @@ bool TrackPanel::HasEscape()
|
|||||||
return mTargets.size() > 0;
|
return mTargets.size() > 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool TrackPanel::ChangeTarget(bool forward, bool cycle)
|
bool CellularPanel::ChangeTarget(bool forward, bool cycle)
|
||||||
{
|
{
|
||||||
auto size = mTargets.size();
|
auto size = mTargets.size();
|
||||||
|
|
||||||
@@ -1090,7 +1102,7 @@ void TrackPanel::MessageForScreenReader(const wxString& message)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Determines if a modal tool is active
|
/// Determines if a modal tool is active
|
||||||
bool TrackPanel::IsMouseCaptured()
|
bool CellularPanel::IsMouseCaptured()
|
||||||
{
|
{
|
||||||
return mUIHandle != NULL;
|
return mUIHandle != NULL;
|
||||||
}
|
}
|
||||||
@@ -1140,9 +1152,9 @@ void TrackPanel::OnTrackListResizing(wxCommandEvent & e)
|
|||||||
// Tracks have been removed from the list.
|
// Tracks have been removed from the list.
|
||||||
void TrackPanel::OnTrackListDeletion(wxCommandEvent & e)
|
void TrackPanel::OnTrackListDeletion(wxCommandEvent & e)
|
||||||
{
|
{
|
||||||
if (mUIHandle) {
|
|
||||||
// copy shared_ptr for safety, as in HandleClick
|
// copy shared_ptr for safety, as in HandleClick
|
||||||
auto handle = mUIHandle;
|
auto handle = Target();
|
||||||
|
if (handle) {
|
||||||
handle->OnProjectChange(GetProject());
|
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)
|
/// 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;
|
auto pCell = tpmEvent.pCell;
|
||||||
if (!pCell)
|
if (!pCell)
|
||||||
@@ -1395,7 +1407,7 @@ void TrackPanel::HandleWheelRotation( TrackPanelMouseEvent &tpmEvent )
|
|||||||
pCell.get(), pCell.get(), result);
|
pCell.get(), pCell.get(), result);
|
||||||
}
|
}
|
||||||
|
|
||||||
void TrackPanel::OnCaptureKey(wxCommandEvent & event)
|
void CellularPanel::OnCaptureKey(wxCommandEvent & event)
|
||||||
{
|
{
|
||||||
mEnableTab = false;
|
mEnableTab = false;
|
||||||
wxKeyEvent *kevent = static_cast<wxKeyEvent *>(event.GetEventObject());
|
wxKeyEvent *kevent = static_cast<wxKeyEvent *>(event.GetEventObject());
|
||||||
@@ -1403,19 +1415,17 @@ void TrackPanel::OnCaptureKey(wxCommandEvent & event)
|
|||||||
if ( WXK_ESCAPE != code )
|
if ( WXK_ESCAPE != code )
|
||||||
HandleInterruptedDrag();
|
HandleInterruptedDrag();
|
||||||
|
|
||||||
// TODO? Some notion of focused cell, more generally than focused tracks
|
// Give focused cell precedence
|
||||||
|
const auto t = GetFocusedCell();
|
||||||
// Give focused track precedence
|
|
||||||
Track * const t = GetFocusedTrack();
|
|
||||||
if (t) {
|
if (t) {
|
||||||
const unsigned refreshResult =
|
const unsigned refreshResult =
|
||||||
((TrackPanelCell*)t)->CaptureKey(*kevent, *mViewInfo, this);
|
t->CaptureKey(*kevent, *mViewInfo, this);
|
||||||
ProcessUIHandleResult(t, t, refreshResult);
|
ProcessUIHandleResult(t, t, refreshResult);
|
||||||
event.Skip(kevent->GetSkipped());
|
event.Skip(kevent->GetSkipped());
|
||||||
}
|
}
|
||||||
|
|
||||||
#if 0
|
#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()) &&
|
if ( !(t && !kevent->GetSkipped()) &&
|
||||||
WXK_TAB == code && HasRotation() ) {
|
WXK_TAB == code && HasRotation() ) {
|
||||||
// Override TAB navigation in wxWidgets, by not skipping
|
// Override TAB navigation in wxWidgets, by not skipping
|
||||||
@@ -1430,6 +1440,26 @@ void TrackPanel::OnCaptureKey(wxCommandEvent & event)
|
|||||||
}
|
}
|
||||||
|
|
||||||
void TrackPanel::OnKeyDown(wxKeyEvent & 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())
|
switch (event.GetKeyCode())
|
||||||
{
|
{
|
||||||
@@ -1450,16 +1480,6 @@ void TrackPanel::OnKeyDown(wxKeyEvent & event)
|
|||||||
HandleModifierKey();
|
HandleModifierKey();
|
||||||
break;
|
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
|
#if 0
|
||||||
case WXK_TAB:
|
case WXK_TAB:
|
||||||
if ( mEnableTab && HasRotation() ) {
|
if ( mEnableTab && HasRotation() ) {
|
||||||
@@ -1472,18 +1492,18 @@ void TrackPanel::OnKeyDown(wxKeyEvent & event)
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
Track *const t = GetFocusedTrack();
|
const auto t = GetFocusedCell();
|
||||||
|
|
||||||
if (t) {
|
if (t) {
|
||||||
const unsigned refreshResult =
|
const unsigned refreshResult =
|
||||||
((TrackPanelCell*)t)->KeyDown(event, *mViewInfo, this);
|
t->KeyDown(event, *mViewInfo, this);
|
||||||
ProcessUIHandleResult(t, t, refreshResult);
|
ProcessUIHandleResult(t, t, refreshResult);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
event.Skip();
|
event.Skip();
|
||||||
}
|
}
|
||||||
|
|
||||||
void TrackPanel::OnChar(wxKeyEvent & event)
|
void CellularPanel::OnChar(wxKeyEvent & event)
|
||||||
{
|
{
|
||||||
switch (event.GetKeyCode())
|
switch (event.GetKeyCode())
|
||||||
{
|
{
|
||||||
@@ -1496,17 +1516,17 @@ void TrackPanel::OnChar(wxKeyEvent & event)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
Track *const t = GetFocusedTrack();
|
const auto t = GetFocusedCell();
|
||||||
if (t) {
|
if (t) {
|
||||||
const unsigned refreshResult =
|
const unsigned refreshResult =
|
||||||
((TrackPanelCell*)t)->Char(event, *mViewInfo, this);
|
t->Char(event, *mViewInfo, this);
|
||||||
ProcessUIHandleResult(t, t, refreshResult);
|
ProcessUIHandleResult(t, t, refreshResult);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
event.Skip();
|
event.Skip();
|
||||||
}
|
}
|
||||||
|
|
||||||
void TrackPanel::OnKeyUp(wxKeyEvent & event)
|
void CellularPanel::OnKeyUp(wxKeyEvent & event)
|
||||||
{
|
{
|
||||||
bool didSomething = false;
|
bool didSomething = false;
|
||||||
switch (event.GetKeyCode())
|
switch (event.GetKeyCode())
|
||||||
@@ -1528,10 +1548,10 @@ void TrackPanel::OnKeyUp(wxKeyEvent & event)
|
|||||||
if (didSomething)
|
if (didSomething)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
Track * const t = GetFocusedTrack();
|
const auto t = GetFocusedCell();
|
||||||
if (t) {
|
if (t) {
|
||||||
const unsigned refreshResult =
|
const unsigned refreshResult =
|
||||||
((TrackPanelCell*)t)->KeyUp(event, *mViewInfo, this);
|
t->KeyUp(event, *mViewInfo, this);
|
||||||
ProcessUIHandleResult(t, t, refreshResult);
|
ProcessUIHandleResult(t, t, refreshResult);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -1540,7 +1560,7 @@ void TrackPanel::OnKeyUp(wxKeyEvent & event)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Should handle the case when the mouse capture is lost.
|
/// Should handle the case when the mouse capture is lost.
|
||||||
void TrackPanel::OnCaptureLost(wxMouseCaptureLostEvent & WXUNUSED(event))
|
void CellularPanel::OnCaptureLost(wxMouseCaptureLostEvent & WXUNUSED(event))
|
||||||
{
|
{
|
||||||
ClearTargets();
|
ClearTargets();
|
||||||
|
|
||||||
@@ -1554,10 +1574,37 @@ void TrackPanel::OnCaptureLost(wxMouseCaptureLostEvent & WXUNUSED(event))
|
|||||||
OnMouseEvent(e);
|
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
|
/// This handles just generic mouse events. Then, based
|
||||||
/// on our current state, we forward the mouse events to
|
/// on our current state, we forward the mouse events to
|
||||||
/// various interested parties.
|
/// various interested parties.
|
||||||
void TrackPanel::OnMouseEvent(wxMouseEvent & event)
|
void CellularPanel::OnMouseEvent(wxMouseEvent & event)
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
const auto foundCell = FindCell( event.m_x, event.m_y );
|
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
|
// If a mouse event originates from a keyboard context menu event then
|
||||||
// event.GetPosition() == wxDefaultPosition. wxContextMenu events are handled in
|
// 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
|
// Not ignoring them was causing bug 613: the mouse events were interpreted as clicking
|
||||||
// outside the tracks.
|
// outside the tracks.
|
||||||
if (event.GetPosition() == wxDefaultPosition && (event.RightDown() || event.RightUp())) {
|
if (event.GetPosition() == wxDefaultPosition && (event.RightDown() || event.RightUp())) {
|
||||||
@@ -1604,14 +1651,6 @@ try
|
|||||||
// parent window 'come alive' if it didn't have focus.
|
// parent window 'come alive' if it didn't have focus.
|
||||||
wxActivateEvent e;
|
wxActivateEvent e;
|
||||||
GetParent()->GetEventHandler()->ProcessEvent(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()) {
|
if (event.ButtonDown()) {
|
||||||
@@ -1692,17 +1731,8 @@ try
|
|||||||
CaptureMouse();
|
CaptureMouse();
|
||||||
}
|
}
|
||||||
|
|
||||||
//EnsureVisible should be called after the up-click.
|
if (event.ButtonUp())
|
||||||
if (event.ButtonUp()) {
|
|
||||||
Uncapture();
|
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( ... )
|
catch( ... )
|
||||||
{
|
{
|
||||||
@@ -1716,7 +1746,7 @@ catch( ... )
|
|||||||
throw;
|
throw;
|
||||||
}
|
}
|
||||||
|
|
||||||
void TrackPanel::HandleClick( const TrackPanelMouseEvent &tpmEvent )
|
void CellularPanel::HandleClick( const TrackPanelMouseEvent &tpmEvent )
|
||||||
{
|
{
|
||||||
auto pCell = tpmEvent.pCell;
|
auto pCell = tpmEvent.pCell;
|
||||||
|
|
||||||
@@ -1762,7 +1792,7 @@ void TrackPanel::HandleClick( const TrackPanelMouseEvent &tpmEvent )
|
|||||||
|
|
||||||
double TrackPanel::GetMostRecentXPos()
|
double TrackPanel::GetMostRecentXPos()
|
||||||
{
|
{
|
||||||
return mViewInfo->PositionToTime(mMouseMostRecentX, GetLabelWidth());
|
return mViewInfo->PositionToTime(MostRecentXCoord(), GetLabelWidth());
|
||||||
}
|
}
|
||||||
|
|
||||||
void TrackPanel::RefreshTrack(Track *trk, bool refreshbacking)
|
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
|
/// Determines which cell is under the mouse
|
||||||
/// @param mouseX - mouse X position.
|
/// @param mouseX - mouse X position.
|
||||||
/// @param mouseY - mouse Y 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 range = Cells();
|
||||||
auto &iter = range.first, &end = range.second;
|
auto &iter = range.first, &end = range.second;
|
||||||
@@ -2861,36 +2891,41 @@ void TrackPanel::DisplaySelection()
|
|||||||
mListener->TP_DisplaySelection();
|
mListener->TP_DisplaySelection();
|
||||||
}
|
}
|
||||||
|
|
||||||
Track *TrackPanel::GetFocusedTrack()
|
TrackPanelCell *TrackPanel::GetFocusedCell()
|
||||||
{
|
{
|
||||||
return mAx->GetFocus().get();
|
return mAx->GetFocus().get();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Track *TrackPanel::GetFocusedTrack()
|
||||||
|
{
|
||||||
|
return static_cast<Track*>( GetFocusedCell() );
|
||||||
|
}
|
||||||
|
|
||||||
|
void TrackPanel::SetFocusedCell()
|
||||||
|
{
|
||||||
|
SetFocusedTrack( GetFocusedTrack() );
|
||||||
|
}
|
||||||
|
|
||||||
void TrackPanel::SetFocusedTrack( Track *t )
|
void TrackPanel::SetFocusedTrack( Track *t )
|
||||||
{
|
{
|
||||||
// Make sure we always have the first linked track of a stereo track
|
// Make sure we always have the first linked track of a stereo track
|
||||||
if (t && !t->GetLinked() && t->GetLink())
|
if (t && !t->GetLinked() && t->GetLink())
|
||||||
t = (WaveTrack*)t->GetLink();
|
t = (WaveTrack*)t->GetLink();
|
||||||
|
|
||||||
if ( !mAx->SetFocus( Track::Pointer( t ) ) )
|
auto cell = mAx->SetFocus( Track::Pointer( t ) ).get();
|
||||||
return;
|
|
||||||
|
|
||||||
if (t && AudacityProject::GetKeyboardCaptureHandler())
|
if (cell) {
|
||||||
AudacityProject::ReleaseKeyboard(this);
|
|
||||||
|
|
||||||
if (t)
|
|
||||||
AudacityProject::CaptureKeyboard(this);
|
AudacityProject::CaptureKeyboard(this);
|
||||||
|
|
||||||
Refresh( false );
|
Refresh( false );
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void TrackPanel::OnSetFocus(wxFocusEvent & WXUNUSED(event))
|
void CellularPanel::OnSetFocus(wxFocusEvent & WXUNUSED(event))
|
||||||
{
|
{
|
||||||
SetFocusedTrack( GetFocusedTrack() );
|
SetFocusedCell();
|
||||||
Refresh( false );
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void TrackPanel::OnKillFocus(wxFocusEvent & WXUNUSED(event))
|
void CellularPanel::OnKillFocus(wxFocusEvent & WXUNUSED(event))
|
||||||
{
|
{
|
||||||
if (AudacityProject::HasKeyboardCapture(this))
|
if (AudacityProject::HasKeyboardCapture(this))
|
||||||
{
|
{
|
||||||
|
|||||||
197
src/TrackPanel.h
197
src/TrackPanel.h
@@ -242,9 +242,126 @@ private:
|
|||||||
const int DragThreshold = 3;// Anything over 3 pixels is a drag, else a click.
|
const int DragThreshold = 3;// Anything over 3 pixels is a drag, else a click.
|
||||||
|
|
||||||
|
|
||||||
class AUDACITY_DLL_API TrackPanel final : public OverlayPanel {
|
// 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:
|
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,
|
TrackPanel(wxWindow * parent,
|
||||||
wxWindowID id,
|
wxWindowID id,
|
||||||
const wxPoint & pos,
|
const wxPoint & pos,
|
||||||
@@ -263,14 +380,7 @@ class AUDACITY_DLL_API TrackPanel final : public OverlayPanel {
|
|||||||
|
|
||||||
void OnPaint(wxPaintEvent & event);
|
void OnPaint(wxPaintEvent & event);
|
||||||
void OnMouseEvent(wxMouseEvent & event);
|
void OnMouseEvent(wxMouseEvent & event);
|
||||||
void OnCaptureLost(wxMouseCaptureLostEvent & event);
|
|
||||||
void OnCaptureKey(wxCommandEvent & event);
|
|
||||||
void OnKeyDown(wxKeyEvent & 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);
|
void OnContextMenu(wxContextMenuEvent & event);
|
||||||
|
|
||||||
@@ -302,31 +412,24 @@ class AUDACITY_DLL_API TrackPanel final : public OverlayPanel {
|
|||||||
// void SetSelectionFormat(int iformat)
|
// void SetSelectionFormat(int iformat)
|
||||||
// void SetSnapTo(int snapto)
|
// 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 HandlePageUpKey();
|
||||||
void HandlePageDownKey();
|
void HandlePageDownKey();
|
||||||
AudacityProject * GetProject() const;
|
AudacityProject * GetProject() const override;
|
||||||
|
|
||||||
void ScrollIntoView(double pos);
|
void ScrollIntoView(double pos);
|
||||||
void ScrollIntoView(int x);
|
void ScrollIntoView(int x);
|
||||||
|
|
||||||
void OnTrackMenu(Track *t = NULL);
|
void OnTrackMenu(Track *t = NULL);
|
||||||
Track * GetFirstSelectedTrack();
|
Track * GetFirstSelectedTrack();
|
||||||
bool IsMouseCaptured();
|
|
||||||
|
|
||||||
void EnsureVisible(Track * t);
|
void EnsureVisible(Track * t);
|
||||||
void VerticalScroll( float fracPosition);
|
void VerticalScroll( float fracPosition);
|
||||||
|
|
||||||
|
TrackPanelCell *GetFocusedCell() override;
|
||||||
|
void SetFocusedCell() override;
|
||||||
Track *GetFocusedTrack();
|
Track *GetFocusedTrack();
|
||||||
void SetFocusedTrack(Track *t);
|
void SetFocusedTrack(Track *t);
|
||||||
|
|
||||||
void HandleCursorForPresentMouseState(bool doHit = true);
|
|
||||||
|
|
||||||
void UpdateVRulers();
|
void UpdateVRulers();
|
||||||
void UpdateVRuler(Track *t);
|
void UpdateVRuler(Track *t);
|
||||||
void UpdateTrackVRuler(const Track *t);
|
void UpdateTrackVRuler(const Track *t);
|
||||||
@@ -338,7 +441,6 @@ class AUDACITY_DLL_API TrackPanel final : public OverlayPanel {
|
|||||||
|
|
||||||
protected:
|
protected:
|
||||||
bool IsAudioActive();
|
bool IsAudioActive();
|
||||||
void HandleClick( const TrackPanelMouseEvent &tpmEvent );
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
size_t GetTrackCount() const;
|
size_t GetTrackCount() const;
|
||||||
@@ -351,9 +453,6 @@ public:
|
|||||||
void UpdateAccessibility();
|
void UpdateAccessibility();
|
||||||
void MessageForScreenReader(const wxString& message);
|
void MessageForScreenReader(const wxString& message);
|
||||||
|
|
||||||
// MM: Handle mouse wheel rotation
|
|
||||||
void HandleWheelRotation( TrackPanelMouseEvent &tpmEvent );
|
|
||||||
|
|
||||||
void MakeParentRedrawScrollbars();
|
void MakeParentRedrawScrollbars();
|
||||||
|
|
||||||
// If label, rectangle includes track control panel only.
|
// 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
|
// a crash, as it can take many seconds for large (eg. 10 track-hours) projects
|
||||||
|
|
||||||
// Find track info by coordinate
|
// Find track info by coordinate
|
||||||
struct FoundCell {
|
FoundCell FindCell(int mouseX, int mouseY) override;
|
||||||
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 );
|
|
||||||
|
|
||||||
int GetVRulerWidth() const;
|
int GetVRulerWidth() const;
|
||||||
int GetVRulerOffset() const { return mTrackInfo.GetTrackInfoWidth(); }
|
int GetVRulerOffset() const { return mTrackInfo.GetTrackInfoWidth(); }
|
||||||
@@ -447,7 +538,6 @@ protected:
|
|||||||
TrackPanelListener *mListener;
|
TrackPanelListener *mListener;
|
||||||
|
|
||||||
std::shared_ptr<TrackList> mTracks;
|
std::shared_ptr<TrackList> mTracks;
|
||||||
ViewInfo *mViewInfo;
|
|
||||||
|
|
||||||
AdornedRulerPanel *mRuler;
|
AdornedRulerPanel *mRuler;
|
||||||
|
|
||||||
@@ -481,11 +571,6 @@ protected:
|
|||||||
|
|
||||||
bool mRedrawAfterStop;
|
bool mRedrawAfterStop;
|
||||||
|
|
||||||
wxMouseState mLastMouseState;
|
|
||||||
|
|
||||||
int mMouseMostRecentX;
|
|
||||||
int mMouseMostRecentY;
|
|
||||||
|
|
||||||
friend class TrackPanelAx;
|
friend class TrackPanelAx;
|
||||||
|
|
||||||
#if wxUSE_ACCESSIBILITY
|
#if wxUSE_ACCESSIBILITY
|
||||||
@@ -510,48 +595,16 @@ protected:
|
|||||||
wxSize vrulerSize;
|
wxSize vrulerSize;
|
||||||
|
|
||||||
protected:
|
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;
|
std::shared_ptr<TrackPanelCell> mpBackground;
|
||||||
|
|
||||||
bool mEnableTab{};
|
|
||||||
|
|
||||||
DECLARE_EVENT_TABLE()
|
DECLARE_EVENT_TABLE()
|
||||||
|
|
||||||
void ProcessUIHandleResult
|
void ProcessUIHandleResult
|
||||||
(TrackPanelCell *pClickedCell, TrackPanelCell *pLatestCell,
|
(TrackPanelCell *pClickedCell, TrackPanelCell *pLatestCell,
|
||||||
unsigned refreshResult);
|
unsigned refreshResult) override;
|
||||||
|
|
||||||
|
void UpdateStatusMessage( const wxString &status ) override;
|
||||||
|
|
||||||
// friending GetInfoCommand allow automation to get sizes of the
|
// friending GetInfoCommand allow automation to get sizes of the
|
||||||
// tracks, track control panel and such.
|
// tracks, track control panel and such.
|
||||||
|
|||||||
Reference in New Issue
Block a user