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:
parent
db35301a00
commit
519a2020ff
@ -94,6 +94,10 @@ enum CommandFlag : unsigned long long
|
||||
CanStopAudioStreamFlag = 0x40000000,
|
||||
AudioStreamNotScrubbingFlag
|
||||
= 0x80000000ULL, // prl
|
||||
RulerHasFocus
|
||||
= 0x100000000ULL, // prl
|
||||
TrackPanelOrRulerHasFocus
|
||||
= 0x200000000ULL, // prl
|
||||
|
||||
NoFlagsSpecifed = ~0ULL
|
||||
};
|
||||
|
@ -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:
|
||||
|
@ -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;
|
||||
|
@ -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)
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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 */ )
|
||||
|
@ -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;
|
||||
|
Loading…
x
Reference in New Issue
Block a user