1
0
mirror of https://github.com/cookiengineer/audacity synced 2025-05-03 17:19:43 +02:00

Bug2064: ESC key should abort drags in time ruler on Linux...

... Reimplement the ESC key handling in TrackPanel and time ruler on all
operating systems so that it does not rely on the focused window, but instead
uses the application-wide event filter.

This includes reversion of 9491605cfc8a7d60117365884fd494996b5ebbaf
This commit is contained in:
Paul Licameli 2019-02-10 10:31:10 -05:00
parent b47e2f91e2
commit 02db402b54
8 changed files with 75 additions and 57 deletions

View File

@ -2077,6 +2077,19 @@ void AdornedRulerPanel::GetMaxSize(wxCoord *width, wxCoord *height)
mRuler.GetMaxSize(width, height);
}
bool AdornedRulerPanel::s_AcceptsFocus{ false };
auto AdornedRulerPanel::TemporarilyAllowFocus() -> TempAllowFocus {
s_AcceptsFocus = true;
return TempAllowFocus{ &s_AcceptsFocus };
}
void AdornedRulerPanel::SetFocusFromKbd()
{
auto temp = TemporarilyAllowFocus();
SetFocus();
}
// Second-level subdivision includes quick-play region and maybe the scrub bar
// and also shaves little margins above and below
struct AdornedRulerPanel::Subgroup final : TrackPanelGroup {
@ -2150,11 +2163,6 @@ void AdornedRulerPanel::UpdateStatusMessage( const wxString &message )
GetProject()->TP_DisplayStatusMessage(message);
}
bool AdornedRulerPanel::TakesFocus() const
{
return false;
}
void AdornedRulerPanel::CreateOverlays()
{
if (!mOverlay) {

View File

@ -40,6 +40,10 @@ public:
~AdornedRulerPanel();
bool AcceptsFocus() const override { return s_AcceptsFocus; }
bool AcceptsFocusFromKeyboard() const override { return true; }
void SetFocusFromKbd() override;
public:
int GetRulerHeight() { return GetRulerHeight(mShowScrubbing); }
static int GetRulerHeight(bool showScrubBar);
@ -91,6 +95,14 @@ public:
void DoDrawIndicator(wxDC * dc, wxCoord xx, bool playing, int width, bool scrub, bool seek);
void UpdateButtonStates();
private:
static bool s_AcceptsFocus;
struct Resetter { void operator () (bool *p) const { if(p) *p = false; } };
using TempAllowFocus = std::unique_ptr<bool, Resetter>;
public:
static TempAllowFocus TemporarilyAllowFocus();
private:
void DoDrawPlayRegion(wxDC * dc);
@ -186,8 +198,6 @@ private:
void UpdateStatusMessage( const wxString & ) override;
bool TakesFocus() const override;
void CreateOverlays();
// Cooperating objects

View File

@ -37,6 +37,42 @@
#include "HitTestResult.h"
#include "RefreshCode.h"
// A singleton class that intercepts escape key presses when some cellular
// panel is dragging
struct CellularPanel::Filter : wxEventFilter
{
Filter()
{
wxEvtHandler::AddFilter( this );
}
~Filter()
{
wxEvtHandler::RemoveFilter( this );
}
static void Create()
{
static Filter instance;
}
int FilterEvent( wxEvent &event ) override
{
if ( spActivePanel &&
event.GetEventType() == wxEVT_KEY_DOWN &&
static_cast< wxKeyEvent& >( event ).GetKeyCode() == WXK_ESCAPE ) {
spActivePanel->HandleEscapeKey( true );
return Event_Processed;
}
else
return Event_Skip;
}
static wxWeakRef< CellularPanel > spActivePanel;
};
wxWeakRef< CellularPanel > CellularPanel::Filter::spActivePanel = nullptr;
struct CellularPanel::State
{
UIHandlePtr mUIHandle;
@ -76,6 +112,10 @@ CellularPanel::CellularPanel(
, mViewInfo( viewInfo )
, mState{ std::make_unique<State>() }
{
// Create the global event filter instance for CellularPanels only when the
// first CellularPanel is created, not sooner, so that the filter will be
// invoked before that for the application.
Filter::Create();
}
CellularPanel::~CellularPanel() = default;
@ -109,16 +149,8 @@ void CellularPanel::Uncapture(bool escaping, wxMouseState *pState)
ReleaseMouse();
HandleMotion( *pState );
if ( escaping
#ifndef __WXGTK__
// See other comment in HandleClick()
|| !TakesFocus()
#endif
) {
auto lender = GetProject()->mFocusLender.get();
if (lender)
lender->SetFocus();
}
if ( escaping || !AcceptsFocus() )
Filter::spActivePanel = nullptr;
}
bool CellularPanel::CancelDragging( bool escaping )
@ -523,6 +555,7 @@ void CellularPanel::OnKeyDown(wxKeyEvent & event)
switch (event.GetKeyCode())
{
case WXK_ESCAPE:
// This switch case is now redundant with the global filter
if(HandleEscapeKey(true))
// Don't skip the event, eat it so that
// AudacityApp does not also stop any playback.
@ -806,16 +839,9 @@ void CellularPanel::HandleClick( const TrackPanelMouseEvent &tpmEvent )
if (refreshResult & RefreshCode::Cancelled)
state.mUIHandle.reset(), handle.reset(), ClearTargets();
else {
if( !HasFocus()
#ifdef __WXGTK__
// Bug 2056 residual
// Don't take focus even temporarily in the time ruler, because
// the restoring of it doesn't work as expected for reasons not
// yet clear.
// The price we pay is that ESC can't abort drags in the time ruler
&& TakesFocus()
#endif
)
Filter::spActivePanel = this;
if( !HasFocus() && AcceptsFocus() )
SetFocusIgnoringChildren();
state.mpClickedCell = pCell;
@ -857,18 +883,11 @@ void CellularPanel::DoContextMenu( TrackPanelCell *pCell )
void CellularPanel::OnSetFocus(wxFocusEvent &event)
{
auto &ptr = GetProject()->mFocusLender;
if ( !ptr )
ptr = event.GetWindow();
SetFocusedCell();
}
void CellularPanel::OnKillFocus(wxFocusEvent & WXUNUSED(event))
{
// Forget any borrowing of focus
GetProject()->mFocusLender = NULL;
if (AudacityProject::HasKeyboardCapture(this))
{
AudacityProject::ReleaseKeyboard(this);

View File

@ -57,10 +57,6 @@ public:
virtual void UpdateStatusMessage( const wxString & ) = 0;
// Whether this panel keeps focus after a click and drag, or only borrows
// it.
virtual bool TakesFocus() const = 0;
public:
// Structure and functions for generalized visitation of the subdivision
struct Visitor {
@ -163,6 +159,8 @@ protected:
private:
struct State;
std::unique_ptr<State> mState;
struct Filter;
DECLARE_EVENT_TABLE()
};

View File

@ -5576,11 +5576,6 @@ void AudacityProject::PlaybackScroller::OnTimer(wxCommandEvent &event)
}
}
bool AudacityProject::IsFocused( const wxWindow *window ) const
{
return window == mFocusLender || window == wxWindow::FindFocus();
}
LyricsWindow* AudacityProject::GetLyricsWindow(bool create)
{
if (create && !mLyricsWindow)

View File

@ -830,12 +830,6 @@ public:
std::shared_ptr<BackgroundCell> GetBackgroundCell() const
{ return mBackgroundCell; }
wxWindowRef mFocusLender;
// Return true if the window is really focused, or if focus was borrowed
// from it
bool IsFocused( const wxWindow *window ) const;
DECLARE_EVENT_TABLE()
};

View File

@ -644,11 +644,6 @@ void TrackPanel::UpdateStatusMessage( const wxString &st )
mListener->TP_DisplayStatusMessage(status);
}
bool TrackPanel::TakesFocus() const
{
return true;
}
void TrackPanel::UpdateSelectionDisplay()
{
// Full refresh since the label area may need to indicate
@ -1188,7 +1183,8 @@ void TrackPanel::DrawEverythingElse(TrackPanelDrawingContext &context,
// if (GetFocusedTrack() != NULL) {
// the highlight was reportedly drawn even when something else
// was the focus and no highlight should be drawn. -RBD
if (GetFocusedTrack() != NULL && GetProject()->IsFocused( this )) {
if (GetFocusedTrack() != NULL &&
wxWindow::FindFocus() == this ) {
HighlightFocusedTrack(dc, focusRect);
}

View File

@ -492,8 +492,6 @@ protected:
void UpdateStatusMessage( const wxString &status ) override;
bool TakesFocus() const override;
// friending GetInfoCommand allow automation to get sizes of the
// tracks, track control panel and such.
friend class GetInfoCommand;