1
0
mirror of https://github.com/cookiengineer/audacity synced 2025-08-02 17:09:26 +02:00

Navigation to and from the ruler using up and down arrow keys...

... This affects those keys (and NUMPAD arrows), also (shift-)ctrl-f6,
ctrl-home, ctrl-end (which are command-left and right on mac)

Those should be tested to ensure correct restoration of the yellow rectangle,
appropriately in the tracks or the ruler.

This should also be tested with and without the Tracks preference for cyclic
movement of the focus.
This commit is contained in:
Paul Licameli 2016-05-06 16:40:39 -04:00
parent db35301a00
commit 519a2020ff
7 changed files with 183 additions and 135 deletions

View File

@ -94,6 +94,10 @@ enum CommandFlag : unsigned long long
CanStopAudioStreamFlag = 0x40000000,
AudioStreamNotScrubbingFlag
= 0x80000000ULL, // prl
RulerHasFocus
= 0x100000000ULL, // prl
TrackPanelOrRulerHasFocus
= 0x200000000ULL, // prl
NoFlagsSpecifed = ~0ULL
};

View File

@ -1128,8 +1128,8 @@ void AudacityProject::CreateMenusAndCommands()
c->AddCommand(wxT("SeekLeftLong"), _("Long seek left during playback"), FN(OnSeekLeftLong), wxT("Shift+Left\tallowDup"));
c->AddCommand(wxT("SeekRightLong"), _("Long Seek right during playback"), FN(OnSeekRightLong), wxT("Shift+Right\tallowDup"));
c->SetDefaultFlags(TracksExistFlag | TrackPanelHasFocus,
TracksExistFlag | TrackPanelHasFocus);
c->SetDefaultFlags(TrackPanelOrRulerHasFocus,
TrackPanelOrRulerHasFocus);
c->AddCommand(wxT("PrevTrack"), _("Move Focus to Previous Track"), FN(OnCursorUp), wxT("Up"));
c->AddCommand(wxT("NextTrack"), _("Move Focus to Next Track"), FN(OnCursorDown), wxT("Down"));
@ -1139,6 +1139,11 @@ void AudacityProject::CreateMenusAndCommands()
c->AddCommand(wxT("ShiftUp"), _("Move Focus to Previous and Select"), FN(OnShiftUp), wxT("Shift+Up"));
c->AddCommand(wxT("ShiftDown"), _("Move Focus to Next and Select"), FN(OnShiftDown), wxT("Shift+Down"));
c->SetDefaultFlags(TracksExistFlag | TrackPanelHasFocus,
TracksExistFlag | TrackPanelHasFocus);
c->AddCommand(wxT("Toggle"), _("Toggle Focused Track"), FN(OnToggle), wxT("Return"));
c->AddCommand(wxT("ToggleAlt"), _("Toggle Focused Track"), FN(OnToggle), wxT("NUMPAD_ENTER"));
@ -1619,6 +1624,9 @@ CommandFlag AudacityProject::GetFocusedFrame()
return TopDockHasFocus;
}
if (w == mRuler)
return RulerHasFocus;
if (w == mTrackPanel) {
return TrackPanelHasFocus;
}
@ -1726,6 +1734,8 @@ CommandFlag AudacityProject::GetUpdateFlags()
flags |= TextClipFlag;
flags |= GetFocusedFrame();
if (flags & (TrackPanelHasFocus | RulerHasFocus))
flags |= TrackPanelOrRulerHasFocus;
double start, end;
GetPlayRegion(&start, &end);
@ -2681,9 +2691,13 @@ void AudacityProject::NextFrame()
switch( GetFocusedFrame() )
{
case TopDockHasFocus:
mTrackPanel->SetFocus();
if(mTrackPanel->GetFocusedTrack())
mTrackPanel->SetFocus();
else
mRuler->SetFocus();
break;
case RulerHasFocus:
case TrackPanelHasFocus:
mToolManager->GetBotDock()->SetFocus();
break;
@ -2706,11 +2720,15 @@ void AudacityProject::PrevFrame()
break;
case TrackPanelHasFocus:
case RulerHasFocus:
mToolManager->GetTopDock()->SetFocus();
break;
case BotDockHasFocus:
mTrackPanel->SetFocus();
if(mTrackPanel->GetFocusedTrack())
mTrackPanel->SetFocus();
else
mRuler->SetFocus();
break;
default:

View File

@ -2161,9 +2161,11 @@ void AudacityProject::OnActivate(wxActivateEvent & event)
mLastFocusedWindow->SetFocus();
}
else {
if (mTrackPanel) {
if (mTrackPanel->GetFocusedTrack()) {
mTrackPanel->SetFocus();
}
else
mRuler->SetFocus();
}
// No longer need to remember the last focused window
mLastFocusedWindow = NULL;

View File

@ -7237,46 +7237,49 @@ void TrackPanel::UpdateVRulerSize()
/// TrackPanel::OnNextTrack.
void TrackPanel::OnPrevTrack( bool shift )
{
TrackListIterator iter( mTracks );
Track* t = GetFocusedTrack();
if( t == NULL ) // if there isn't one, focus on last
bool rulerFocus = mRuler->HasFocus();
bool stealFocus = (mCircularTrackNavigation && rulerFocus);
if(stealFocus) // if there isn't one, focus on last
{
t = iter.Last();
if(rulerFocus) {
this->SetFocus();
mRuler->Refresh();
}
TrackListIterator iter( mTracks );
auto t = iter.Last();
SetFocusedTrack( t );
EnsureVisible( t );
MakeParentModifyState(false);
return;
}
else if (rulerFocus) {
// JKC: wxBell() is probably for accessibility, so a blind
// user knows they were at the top track.
wxBell();
return;
}
Track* t = GetFocusedTrack();
Track* p = mTracks->GetPrev( t, true ); // Get previous track
if (!p) {
SetFocusedTrack(nullptr);
mRuler->SetFocus();
Refresh(false);
mRuler->Refresh();
return;
}
Track* p = NULL;
bool tSelected = false;
bool pSelected = false;
if( shift )
{
p = mTracks->GetPrev( t, true ); // Get previous track
if( p == NULL ) // On first track
{
// JKC: wxBell() is probably for accessibility, so a blind
// user knows they were at the top track.
wxBell();
if( mCircularTrackNavigation )
{
TrackListIterator iter( mTracks );
p = iter.Last();
}
else
{
EnsureVisible( t );
return;
}
}
tSelected = t->GetSelected();
if (p)
pSelected = p->GetSelected();
if( tSelected && pSelected )
{
mTracks->Select( t, false );
SetFocusedTrack( p ); // move focus to next track down
SetFocusedTrack( p ); // move focus to next track up
EnsureVisible( p );
MakeParentModifyState(false);
return;
@ -7284,7 +7287,7 @@ void TrackPanel::OnPrevTrack( bool shift )
if( tSelected && !pSelected )
{
mTracks->Select( p, true );
SetFocusedTrack( p ); // move focus to next track down
SetFocusedTrack( p ); // move focus to next track up
EnsureVisible( p );
MakeParentModifyState(false);
return;
@ -7292,7 +7295,7 @@ void TrackPanel::OnPrevTrack( bool shift )
if( !tSelected && pSelected )
{
mTracks->Select( p, false );
SetFocusedTrack( p ); // move focus to next track down
SetFocusedTrack( p ); // move focus to next track up
EnsureVisible( p );
MakeParentModifyState(false);
return;
@ -7300,7 +7303,7 @@ void TrackPanel::OnPrevTrack( bool shift )
if( !tSelected && !pSelected )
{
mTracks->Select( t, true );
SetFocusedTrack( p ); // move focus to next track down
SetFocusedTrack( p ); // move focus to next track up
EnsureVisible( p );
MakeParentModifyState(false);
return;
@ -7308,35 +7311,10 @@ void TrackPanel::OnPrevTrack( bool shift )
}
else
{
p = mTracks->GetPrev( t, true ); // Get next track
if( p == NULL ) // On last track so stay there?
{
wxBell();
if( mCircularTrackNavigation )
{
TrackListIterator iter( mTracks );
for( Track *d = iter.First(); d; d = iter.Next( true ) )
{
p = d;
}
SetFocusedTrack( p ); // Wrap to the first track
EnsureVisible( p );
MakeParentModifyState(false);
return;
}
else
{
EnsureVisible( t );
return;
}
}
else
{
SetFocusedTrack( p ); // move focus to next track down
EnsureVisible( p );
MakeParentModifyState(false);
return;
}
SetFocusedTrack( p ); // move focus to next track up
EnsureVisible( p );
MakeParentModifyState(false);
return;
}
}
@ -7345,37 +7323,46 @@ void TrackPanel::OnPrevTrack( bool shift )
/// block or not.
void TrackPanel::OnNextTrack( bool shift )
{
if(mRuler->HasFocus()) {
TrackListIterator iter(mTracks);
auto first = iter.First();
if(first != nullptr) {
// Steal focus
this->SetFocus();
SetFocusedTrack(first);
EnsureVisible(first);
MakeParentModifyState(false);
mRuler->Refresh();
}
return;
}
Track *t;
Track *n;
TrackListIterator iter( mTracks );
bool tSelected,nSelected;
bool tSelected, nSelected;
t = GetFocusedTrack(); // Get currently focused track
if( t == NULL ) // if there isn't one, focus on first
bool surrenderFocus =
t == nullptr ||
((n = mTracks->GetNext( t, true )) == nullptr &&
mCircularTrackNavigation);
if( surrenderFocus ) // if there is no next, give focus to the ruler
{
t = iter.First();
SetFocusedTrack( t );
EnsureVisible( t );
MakeParentModifyState(false);
SetFocusedTrack(nullptr);
mRuler->SetFocus();
mRuler->Refresh();
Refresh(false);
return;
}
if( shift )
{
n = mTracks->GetNext( t, true ); // Get next track
if( n == NULL ) // On last track so stay there
{
wxBell();
if( mCircularTrackNavigation )
{
TrackListIterator iter( mTracks );
n = iter.First();
}
else
{
EnsureVisible( t );
return;
}
EnsureVisible( t );
return;
}
tSelected = t->GetSelected();
nSelected = n->GetSelected();
@ -7414,24 +7401,11 @@ void TrackPanel::OnNextTrack( bool shift )
}
else
{
n = mTracks->GetNext( t, true ); // Get next track
if( n == NULL ) // On last track so stay there
{
wxBell();
if( mCircularTrackNavigation )
{
TrackListIterator iter( mTracks );
n = iter.First();
SetFocusedTrack( n ); // Wrap to the first track
EnsureVisible( n );
MakeParentModifyState(false);
return;
}
else
{
EnsureVisible( t );
return;
}
EnsureVisible( t );
return;
}
else
{
@ -7445,26 +7419,25 @@ void TrackPanel::OnNextTrack( bool shift )
void TrackPanel::OnFirstTrack()
{
Track *t = GetFocusedTrack();
if (!t)
return;
TrackListIterator iter(mTracks);
Track *f = iter.First();
if (t != f)
{
SetFocusedTrack(f);
MakeParentModifyState(false);
SetFocusedTrack(nullptr);
if (!mRuler->HasFocus()) {
mRuler->SetFocus();
mRuler->Refresh();
}
EnsureVisible(f);
}
void TrackPanel::OnLastTrack()
{
Track *t = GetFocusedTrack();
if (!t)
if (mTracks->empty()) {
OnFirstTrack();
return;
}
else if(mRuler->HasFocus()) {
this->SetFocus();
mRuler->Refresh();
}
Track *t = GetFocusedTrack();
TrackListIterator iter(mTracks);
Track *l = iter.Last();
if (t != l)

View File

@ -46,12 +46,7 @@ TrackPanelAx::~TrackPanelAx()
// Returns currently focused track or first one if none focused
Track *TrackPanelAx::GetFocus()
{
if( !mFocusedTrack )
{
SetFocus( NULL );
}
if( !TrackNum( mFocusedTrack ) )
if( mFocusedTrack && !TrackNum( mFocusedTrack ) )
{
mFocusedTrack = NULL;
}
@ -72,12 +67,6 @@ void TrackPanelAx::SetFocus( Track *track )
}
#endif
if( track == NULL )
{
TrackListIterator iter( mTrackPanel->mTracks );
track = iter.First();
}
mFocusedTrack = track;
#if wxUSE_ACCESSIBILITY
@ -106,13 +95,8 @@ void TrackPanelAx::SetFocus( Track *track )
// Returns TRUE if passed track has the focus
bool TrackPanelAx::IsFocused( Track *track )
{
if( !mFocusedTrack )
{
SetFocus( NULL );
}
if( ( track == mFocusedTrack ) ||
( track == mFocusedTrack->GetLink() ) )
( mFocusedTrack && track == mFocusedTrack->GetLink() ) )
{
return true;
}

View File

@ -1780,6 +1780,12 @@ BEGIN_EVENT_TABLE(AdornedRulerPanel, wxPanel)
// Scrub bar menu commands
EVT_MENU(OnShowHideScrubbingID, AdornedRulerPanel::OnToggleScrubbing)
// Key events, to navigate buttons
EVT_KEY_DOWN(AdornedRulerPanel::OnKeyDown)
EVT_SET_FOCUS(AdornedRulerPanel::OnSetFocus)
EVT_KILL_FOCUS(AdornedRulerPanel::OnKillFocus)
END_EVENT_TABLE()
AdornedRulerPanel::AdornedRulerPanel(AudacityProject* parent,
@ -2075,6 +2081,12 @@ enum : int {
TopMargin = 1,
BottomMargin = 2, // for bottom bevel and bottom line
LeftMargin = 1,
FocusBorder = 2,
FocusBorderLeft = FocusBorder,
FocusBorderTop = FocusBorder,
FocusBorderBottom = FocusBorder + 1, // count 1 for the black stroke
RightMargin = 1,
};
@ -2742,6 +2754,37 @@ void AdornedRulerPanel::OnToggleScrubbing(wxCommandEvent&)
PostSizeEventToParent();
}
void AdornedRulerPanel::OnKeyDown(wxKeyEvent &event)
{
switch (event.GetKeyCode())
{
case WXK_DOWN:
case WXK_NUMPAD_DOWN:
// Always takes our focus away, so redraw.
mProject->GetTrackPanel()->OnNextTrack();
break;
case WXK_UP:
case WXK_NUMPAD_UP:
mProject->GetTrackPanel()->OnPrevTrack();
break;
default:
break;
}
}
void AdornedRulerPanel::OnSetFocus(wxFocusEvent & WXUNUSED(event))
{
mProject->GetTrackPanel()->SetFocusedTrack(nullptr);
Refresh( false );
}
void AdornedRulerPanel::OnKillFocus(wxFocusEvent & WXUNUSED(event))
{
Refresh( false );
}
void AdornedRulerPanel::OnCaptureLost(wxMouseCaptureLostEvent & WXUNUSED(evt))
{
DrawQuickPlayIndicator(NULL);
@ -2957,8 +3000,11 @@ wxRect AdornedRulerPanel::GetButtonAreaRect(bool includeBorder) const
if(includeBorder)
x = 0, y = 0, bottomMargin = 0;
else
x = LeftMargin, y = TopMargin, bottomMargin = BottomMargin;
else {
x = std::max(LeftMargin, FocusBorderLeft);
y = std::max(TopMargin, FocusBorderTop);
bottomMargin = std::max(BottomMargin, FocusBorderBottom);
}
wxRect rect {
x, y,
@ -3262,16 +3308,35 @@ void AdornedRulerPanel::DoDrawBackground(wxDC * dc)
void AdornedRulerPanel::DoDrawEdge(wxDC *dc)
{
wxRect r = mOuter;
r.width -= RightMargin;
r.height -= BottomMargin;
AColor::BevelTrackInfo( *dc, true, r );
if (HasFocus()) {
dc->SetBrush(*wxTRANSPARENT_BRUSH);
wxRect rect{ mOuter };
--rect.height; // Leave room for the black stroke
AColor::TrackFocusPen(dc, 1);
dc->DrawRectangle(rect);
AColor::TrackFocusPen(dc, 0);
rect.Deflate(1, 1);
dc->DrawRectangle(rect);
static_assert(FocusBorder == 2, "Draws the wrong number of rectangles");
}
else {
wxRect r = mOuter;
r.width -= RightMargin;
r.height -= BottomMargin;
AColor::BevelTrackInfo( *dc, true, r );
}
// Black stroke at bottom
dc->SetPen( *wxBLACK_PEN );
dc->DrawLine( mOuter.x,
mOuter.y + mOuter.height - 1,
mOuter.x + mOuter.width,
mOuter.y + mOuter.height - 1 );
mOuter.y + mOuter.height - 1,
mOuter.x + mOuter.width,
mOuter.y + mOuter.height - 1 );
static_assert(FocusBorderBottom == 1 + FocusBorder, "Button area might be wrong");
}
void AdornedRulerPanel::DoDrawMarks(wxDC * dc, bool /*text */ )

View File

@ -291,8 +291,6 @@ public:
~AdornedRulerPanel();
bool AcceptsFocus() const override { return false; };
public:
static int GetRulerHeight();
static int GetRulerHeight(bool showScrubBar);
@ -471,6 +469,10 @@ private:
void OnToggleScrubbing(wxCommandEvent&);
void OnKeyDown(wxKeyEvent &event);
void OnSetFocus(wxFocusEvent &);
void OnKillFocus(wxFocusEvent &);
bool mPlayRegionDragsSelection;
bool mTimelineToolTip;
bool mQuickPlayEnabled;