diff --git a/scripts/mw2html_audacity/mw2html.py b/scripts/mw2html_audacity/mw2html.py
index 5f877ec9f..4b2a618b0 100644
--- a/scripts/mw2html_audacity/mw2html.py
+++ b/scripts/mw2html_audacity/mw2html.py
@@ -528,6 +528,7 @@ def url_open(url):
L = urlparse.urlparse(url)
if L[1] != domain:
conn.close()
+ if L[1] == '': return(['',''])
print "connection to", domain, "closed."
conn = httplib.HTTPConnection(L[1])
domain = L[1]
diff --git a/src/AudacityApp.cpp b/src/AudacityApp.cpp
index 3d9499e01..ef50a76b3 100644
--- a/src/AudacityApp.cpp
+++ b/src/AudacityApp.cpp
@@ -113,8 +113,6 @@ It handles initialization and termination by subclassing wxApp.
#include "effects/ScoreAlignDialog.h"
#endif
-#include "tracks/ui/Scrubbing.h"
-
#if 0
#ifdef _DEBUG
#ifdef _MSC_VER
@@ -1530,11 +1528,7 @@ void AudacityApp::OnKeyDown(wxKeyEvent &event)
// Stop play, including scrub, but not record
auto project = ::GetActiveProject();
auto token = project->GetAudioIOToken();
- auto &scrubber = project->GetScrubber();
- if(scrubber.HasStartedScrubbing())
- // ESC out of scrubbing
- scrubber.StopScrubbing();
- else if(token > 0 &&
+ if(token > 0 &&
gAudioIO->IsAudioTokenActive(token) &&
gAudioIO->GetNumCaptureChannels() == 0)
// ESC out of other play (but not record)
diff --git a/src/Project.cpp b/src/Project.cpp
index 9492224e3..6cd3a2560 100644
--- a/src/Project.cpp
+++ b/src/Project.cpp
@@ -285,7 +285,8 @@ public:
{
}
- bool IsSupportedFormat(const wxDataFormat & format, Direction WXUNUSED(dir = Get)) const override
+ bool IsSupportedFormat(const wxDataFormat & format, Direction WXUNUSED(dir = Get)) const
+ // PRL: This function does NOT override any inherited virtual! What does it do?
{
if (format.GetType() == wxDF_FILENAME) {
return true;
diff --git a/src/commands/CommandFunctors.h b/src/commands/CommandFunctors.h
index 5df2b27a2..f6d6ec79d 100644
--- a/src/commands/CommandFunctors.h
+++ b/src/commands/CommandFunctors.h
@@ -29,62 +29,62 @@ using CommandFunctorPointer = std::shared_ptr ;
// Define functor subclasses that dispatch to the correct call sequence on
// member functions of AudacityProject (or other class!)
-template
-using audCommandFunction = void (THIS::*)();
+template
+using audCommandFunction = void (OBJ::*)();
-template
+template
class VoidFunctor final : public CommandFunctor
{
public:
- explicit VoidFunctor(THIS *This, audCommandFunction pfn)
+ explicit VoidFunctor(OBJ *This, audCommandFunction pfn)
: mThis{ This }, mCommandFunction{ pfn } {}
void operator () (int, const wxEvent *) override
{ (mThis->*mCommandFunction) (); }
private:
- THIS *const mThis;
- const audCommandFunction mCommandFunction;
+ OBJ *const mThis;
+ const audCommandFunction mCommandFunction;
};
-template
-using audCommandKeyFunction = void (THIS::*)(const wxEvent *);
+template
+using audCommandKeyFunction = void (OBJ::*)(const wxEvent *);
-template
+template
class KeyFunctor final : public CommandFunctor
{
public:
- explicit KeyFunctor(THIS *This, audCommandKeyFunction pfn)
+ explicit KeyFunctor(OBJ *This, audCommandKeyFunction pfn)
: mThis{ This }, mCommandKeyFunction{ pfn } {}
void operator () (int, const wxEvent *evt) override
{ (mThis->*mCommandKeyFunction) (evt); }
private:
- THIS *const mThis;
- const audCommandKeyFunction mCommandKeyFunction;
+ OBJ *const mThis;
+ const audCommandKeyFunction mCommandKeyFunction;
};
-template
-using audCommandListFunction = void (THIS::*)(int);
+template
+using audCommandListFunction = void (OBJ::*)(int);
-template
+template
class ListFunctor final : public CommandFunctor
{
public:
- explicit ListFunctor(THIS *This, audCommandListFunction pfn)
+ explicit ListFunctor(OBJ *This, audCommandListFunction pfn)
: mThis{ This }, mCommandListFunction{ pfn } {}
void operator () (int index, const wxEvent *) override
{ (mThis->*mCommandListFunction)(index); }
private:
- THIS *const mThis;
- const audCommandListFunction mCommandListFunction;
+ OBJ *const mThis;
+ const audCommandListFunction mCommandListFunction;
};
-template
-using audCommandPluginFunction = bool (THIS::*)(const PluginID &, int);
+template
+using audCommandPluginFunction = bool (OBJ::*)(const PluginID &, int);
-template
+template
class PluginFunctor final : public CommandFunctor
{
public:
- explicit PluginFunctor(THIS *This, const PluginID &id, audCommandPluginFunction pfn)
+ explicit PluginFunctor(OBJ *This, const PluginID &id, audCommandPluginFunction pfn)
: mPluginID{ id }, mThis{ This }, mCommandPluginFunction{ pfn } {}
void operator () (int, const wxEvent *) override
{ (mThis->*mCommandPluginFunction)
@@ -93,34 +93,34 @@ public:
); }
private:
const PluginID mPluginID;
- THIS *const mThis;
- const audCommandPluginFunction mCommandPluginFunction;
+ OBJ *const mThis;
+ const audCommandPluginFunction mCommandPluginFunction;
};
// Now define an overloaded factory function
-template
-inline CommandFunctorPointer MakeFunctor(THIS *This,
- audCommandFunction pfn)
-{ return CommandFunctorPointer{ safenew VoidFunctor{ This, pfn } }; }
+template
+inline CommandFunctorPointer MakeFunctor(OBJ *This,
+ audCommandFunction pfn)
+{ return CommandFunctorPointer{ safenew VoidFunctor{ This, pfn } }; }
-template
-inline CommandFunctorPointer MakeFunctor(THIS *This,
- audCommandKeyFunction pfn)
-{ return CommandFunctorPointer{ safenew KeyFunctor{ This, pfn } }; }
+template
+inline CommandFunctorPointer MakeFunctor(OBJ *This,
+ audCommandKeyFunction pfn)
+{ return CommandFunctorPointer{ safenew KeyFunctor{ This, pfn } }; }
-template
-inline CommandFunctorPointer MakeFunctor(THIS *This,
- audCommandListFunction pfn)
-{ return CommandFunctorPointer{ safenew ListFunctor{ This, pfn } }; }
+template
+inline CommandFunctorPointer MakeFunctor(OBJ *This,
+ audCommandListFunction pfn)
+{ return CommandFunctorPointer{ safenew ListFunctor{ This, pfn } }; }
-template
-inline CommandFunctorPointer MakeFunctor(THIS *This, const PluginID &id,
- audCommandPluginFunction pfn)
-{ return CommandFunctorPointer{ safenew PluginFunctor{ This, id, pfn } }; }
+template
+inline CommandFunctorPointer MakeFunctor(OBJ *This, const PluginID &id,
+ audCommandPluginFunction pfn)
+{ return CommandFunctorPointer{ safenew PluginFunctor{ This, id, pfn } }; }
// Now define the macro abbreviations that call the factory
-#define FNT(THIS, This, X) (MakeFunctor(This, X ))
-#define FNTS(THIS, This, X, S) (MakeFunctor(This, (S), X ))
+#define FNT(OBJ, This, X) (MakeFunctor(This, X ))
+#define FNTS(OBJ, This, X, S) (MakeFunctor(This, (S), X ))
#define FN(X) FNT(AudacityProject, this, & AudacityProject :: X)
#define FNS(X, S) FNTS(AudacityProject, this, & AudacityProject :: X, S)
diff --git a/src/effects/Effect.cpp b/src/effects/Effect.cpp
index 2a24f0696..45305a111 100644
--- a/src/effects/Effect.cpp
+++ b/src/effects/Effect.cpp
@@ -3245,6 +3245,8 @@ void EffectUIHost::OnApply(wxCommandEvent & evt)
if (IsModal())
{
+ mDismissed = true;
+
EndModal(true);
Close();
@@ -3265,7 +3267,7 @@ void EffectUIHost::OnApply(wxCommandEvent & evt)
void EffectUIHost::DoCancel()
{
- if (!mCancelled) {
+ if (!mDismissed) {
mEffect->mUIResultID = wxID_CANCEL;
if (IsModal())
@@ -3273,7 +3275,7 @@ void EffectUIHost::DoCancel()
else
Hide();
- mCancelled = true;
+ mDismissed = true;
}
}
diff --git a/src/effects/Effect.h b/src/effects/Effect.h
index 5ea0b5bc9..eb67f7ecf 100644
--- a/src/effects/Effect.h
+++ b/src/effects/Effect.h
@@ -659,7 +659,7 @@ private:
SelectedRegion mRegion;
double mPlayPos;
- bool mCancelled{};
+ bool mDismissed{};
DECLARE_EVENT_TABLE();
};
diff --git a/src/toolbars/ControlToolBar.cpp b/src/toolbars/ControlToolBar.cpp
index 18f43a995..bacaebfb0 100644
--- a/src/toolbars/ControlToolBar.cpp
+++ b/src/toolbars/ControlToolBar.cpp
@@ -773,6 +773,12 @@ void ControlToolBar::PlayDefault()
void ControlToolBar::StopPlaying(bool stopStream /* = true*/)
{
+ AudacityProject *project = GetActiveProject();
+
+ if(project)
+ // Let scrubbing code do some appearance change
+ project->GetScrubber().StopScrubbing();
+
if (!CanStopAudioStream())
return;
@@ -798,7 +804,6 @@ void ControlToolBar::StopPlaying(bool stopStream /* = true*/)
mBusyProject = NULL;
// So that we continue monitoring after playing or recording.
// also clean the MeterQueues
- AudacityProject *project = GetActiveProject();
if( project ) {
project->MayStartMonitoring();
diff --git a/src/toolbars/ToolBar.cpp b/src/toolbars/ToolBar.cpp
index 143b80761..cb003a489 100644
--- a/src/toolbars/ToolBar.cpp
+++ b/src/toolbars/ToolBar.cpp
@@ -67,7 +67,8 @@ public:
virtual ~ToolBarResizer();
// We don't need or want to accept focus.
- bool AcceptsFocus() const;
+ // PRL: except for ESC key now.
+ // bool AcceptsFocus() const;
private:
void OnErase(wxEraseEvent & event);
@@ -77,11 +78,14 @@ private:
void OnEnter(wxMouseEvent & event);
void OnLeave(wxMouseEvent & event);
void OnMotion(wxMouseEvent & event);
+ void ResizeBar(const wxSize &size);
void OnCaptureLost(wxMouseCaptureLostEvent & event);
+ void OnKeyDown(wxKeyEvent &event);
private:
ToolBar *mBar;
wxPoint mResizeStart;
+ wxSize mOrigSize;
DECLARE_EVENT_TABLE();
};
@@ -96,6 +100,7 @@ BEGIN_EVENT_TABLE( ToolBarResizer, wxWindow )
EVT_LEFT_UP( ToolBarResizer::OnLeftUp )
EVT_MOTION( ToolBarResizer::OnMotion )
EVT_MOUSE_CAPTURE_LOST( ToolBarResizer::OnCaptureLost )
+ EVT_KEY_DOWN( ToolBarResizer::OnKeyDown )
END_EVENT_TABLE();
ToolBarResizer::ToolBarResizer(ToolBar *bar)
@@ -109,10 +114,12 @@ ToolBarResizer::~ToolBarResizer()
{
}
+/*
bool ToolBarResizer::AcceptsFocus() const
{
return false;
}
+ */
//
// Handle background erasure
@@ -157,6 +164,8 @@ void ToolBarResizer::OnLeftDown( wxMouseEvent & event )
// Retrieve the mouse position
mResizeStart = ClientToScreen( event.GetPosition() );
+ mOrigSize = mBar->GetSize();
+
// We want all of the mouse events
CaptureMouse();
}
@@ -181,7 +190,7 @@ void ToolBarResizer::OnMotion( wxMouseEvent & event )
wxPoint raw_pos = event.GetPosition();
wxPoint pos = ClientToScreen( raw_pos );
- if( event.Dragging() )
+ if( HasCapture() && event.Dragging() )
{
wxRect r = mBar->GetRect();
wxSize msz = mBar->GetMinSize();
@@ -212,18 +221,22 @@ void ToolBarResizer::OnMotion( wxMouseEvent & event )
mResizeStart = pos;
}
- // Resize the bar
- mBar->SetSize( r.GetSize() );
-
- // Tell everyone we've changed sizes
- mBar->Updated();
-
- // Refresh our world
- mBar->GetParent()->Refresh();
- mBar->GetParent()->Update();
+ ResizeBar( r.GetSize() );
}
}
+void ToolBarResizer::ResizeBar(const wxSize &size)
+{
+ mBar->SetSize( size );
+
+ // Tell everyone we've changed sizes
+ mBar->Updated();
+
+ // Refresh our world
+ mBar->GetParent()->Refresh();
+ mBar->GetParent()->Update();
+}
+
void ToolBarResizer::OnCaptureLost( wxMouseCaptureLostEvent & WXUNUSED(event) )
{
if( HasCapture() )
@@ -232,6 +245,15 @@ void ToolBarResizer::OnCaptureLost( wxMouseCaptureLostEvent & WXUNUSED(event) )
}
}
+void ToolBarResizer::OnKeyDown(wxKeyEvent &event)
+{
+ event.Skip();
+ if (HasCapture() && WXK_ESCAPE == event.GetKeyCode()) {
+ ResizeBar( mOrigSize );
+ ReleaseMouse();
+ }
+}
+
////////////////////////////////////////////////////////////
/// Methods for ToolBar
////////////////////////////////////////////////////////////
diff --git a/src/toolbars/ToolDock.cpp b/src/toolbars/ToolDock.cpp
index b801122d7..5fd488d2a 100644
--- a/src/toolbars/ToolDock.cpp
+++ b/src/toolbars/ToolDock.cpp
@@ -452,6 +452,11 @@ void ToolDock::Expose( int type, bool show )
Updated();
}
+int ToolDock::Find(ToolBar *bar) const
+{
+ return mDockedBars.Index(bar);
+}
+
//
// Queues an EVT_TOOLBAR_UPDATED command event to notify any
// interested parties of an updated toolbar or dock layout
@@ -468,13 +473,16 @@ void ToolDock::Updated()
//
void ToolDock::OnGrabber( GrabberEvent & event )
{
- ToolBar *t = mBars[ event.GetId() ];
+ auto pos = event.GetPosition();
+ if (!event.IsEscaping()) {
+ ToolBar *t = mBars[ event.GetId() ];
- // Pass it on to the manager since it isn't in the handling hierarchy
- mManager->ProcessEvent( event );
+ // Pass it on to the manager since it isn't in the handling hierarchy
+ mManager->ProcessEvent( event );
- // We no longer have control
- mDockedBars.Remove( t );
+ // We no longer have control
+ mDockedBars.Remove( t );
+ }
}
//
diff --git a/src/toolbars/ToolDock.h b/src/toolbars/ToolDock.h
index 6816f8203..4d4619a23 100644
--- a/src/toolbars/ToolDock.h
+++ b/src/toolbars/ToolDock.h
@@ -57,6 +57,7 @@ class ToolDock final : public wxPanel
void LayoutToolBars();
void Expose( int type, bool show );
+ int Find(ToolBar *bar) const;
int GetOrder( ToolBar *bar );
int GetBarCount();
void Dock( ToolBar *bar, int ndx = -1 );
diff --git a/src/toolbars/ToolManager.cpp b/src/toolbars/ToolManager.cpp
index 56b837e3b..8cc49b7b2 100644
--- a/src/toolbars/ToolManager.cpp
+++ b/src/toolbars/ToolManager.cpp
@@ -234,10 +234,7 @@ class ToolFrame final : public wxFrame
rect.height = mMinSize.y;
}
- SetMinSize( rect.GetSize() );
- SetSize( rect.GetSize() );
- Layout();
- Refresh( false );
+ Resize( rect.GetSize() );
}
else if( HasCapture() && event.LeftUp() )
{
@@ -256,6 +253,8 @@ class ToolFrame final : public wxFrame
// Is left click within resize grabber?
if( r.Contains( pos ) && !event.Leaving() )
{
+ mOrigSize = GetSize();
+
SetCursor( wxCURSOR_SIZENWSE );
if( event.LeftDown() )
{
@@ -286,12 +285,30 @@ class ToolFrame final : public wxFrame
event.Veto();
}
- private:
+ void OnKeyDown( wxKeyEvent &event )
+ {
+ event.Skip();
+ if( HasCapture() && event.GetKeyCode() == WXK_ESCAPE ) {
+ Resize( mOrigSize );
+ ReleaseMouse();
+ }
+ }
+
+ void Resize( const wxSize &size )
+ {
+ SetMinSize( size );
+ SetSize( size );
+ Layout();
+ Refresh( false );
+ }
+
+private:
wxWindow *mParent;
ToolManager *mManager;
ToolBar *mBar;
wxSize mMinSize;
+ wxSize mOrigSize;
public:
@@ -308,6 +325,7 @@ BEGIN_EVENT_TABLE( ToolFrame, wxFrame )
EVT_MOUSE_CAPTURE_LOST( ToolFrame::OnCaptureLost )
EVT_CLOSE( ToolFrame::OnClose )
EVT_COMMAND( wxID_ANY, EVT_TOOLBAR_UPDATED, ToolFrame::OnToolBarUpdate )
+ EVT_KEY_DOWN( ToolFrame::OnKeyDown )
END_EVENT_TABLE()
IMPLEMENT_CLASS( ToolManager, wxEvtHandler );
@@ -988,15 +1006,6 @@ void ToolManager::OnMouse( wxMouseEvent & event )
// Button was released...finish the drag
if( !event.LeftIsDown() )
{
- // Release capture
- if( mParent->HasCapture() )
- {
- mParent->ReleaseMouse();
- }
-
- // Hide the indicator
- mIndicator->Hide();
-
// Transition the bar to a dock
if( mDragDock && !event.ShiftDown() )
{
@@ -1013,13 +1022,7 @@ void ToolManager::OnMouse( wxMouseEvent & event )
mDragBar->SetDocked( NULL, false );
}
- // Done dragging
- mDragWindow = NULL;
- mDragDock = NULL;
- mDragBar = NULL;
- mLastPos.x = mBarPos.x = -1;
- mLastPos.y = mBarPos.y = -1;
- mTimer.Stop();
+ DoneDragging();
}
else if( event.Dragging() && pos != mLastPos )
{
@@ -1221,17 +1224,29 @@ void ToolManager::OnGrabber( GrabberEvent & event )
// No need to propagate any further
event.Skip( false );
+ if(event.IsEscaping())
+ return HandleEscapeKey();
+
// Remember which bar we're dragging
mDragBar = mBars[ event.GetId() ];
+ // Remember state, in case of ESCape key later
+ if (mDragBar->IsDocked()) {
+ mPrevDock = dynamic_cast(mDragBar->GetParent());
+ wxASSERT(mPrevDock);
+ mPrevSlot = mPrevDock->Find(mDragBar);
+ }
+ else
+ mPrevPosition = mDragBar->GetParent()->GetPosition();
+
// Calculate the drag offset
wxPoint mp = event.GetPosition();
mDragOffset = mp -
mDragBar->GetParent()->ClientToScreen( mDragBar->GetPosition() ) +
- wxPoint( 1, 1 );
+ wxPoint( 1, 1 );
// Must set the bar afloat if it's currently docked
- if( mDragBar->IsDocked() )
+ if( mPrevDock )
{
#if defined(__WXMAC__)
// Disable window animation
@@ -1271,3 +1286,51 @@ void ToolManager::OnGrabber( GrabberEvent & event )
mLastState = wxGetKeyState( WXK_SHIFT );
mTimer.Start( 100 );
}
+
+
+void ToolManager::HandleEscapeKey()
+{
+ if (mDragBar) {
+ if(mPrevDock) {
+ // Sheriff John Stone,
+ // Why don't you leave me alone?
+ // Well, I feel so break up
+ // I want to go home.
+ mPrevDock->Dock( mDragBar, mPrevSlot );
+
+ // Done with the floater
+ mDragWindow->Destroy();
+ mDragBar->Refresh(false);
+ }
+ else {
+ // Floater remains, and returns to where it begain
+ auto parent = mDragBar->GetParent();
+ parent->SetPosition(mPrevPosition);
+ mDragBar->SetDocked(NULL, false);
+ }
+
+ DoneDragging();
+ }
+}
+
+void ToolManager::DoneDragging()
+{
+ // Done dragging
+ // Release capture
+ if( mParent->HasCapture() )
+ {
+ mParent->ReleaseMouse();
+ }
+
+ // Hide the indicator
+ mIndicator->Hide();
+
+ mDragWindow = NULL;
+ mDragDock = NULL;
+ mDragBar = NULL;
+ mPrevDock = NULL;
+ mPrevSlot = -1;
+ mLastPos.x = mBarPos.x = -1;
+ mLastPos.y = mBarPos.y = -1;
+ mTimer.Stop();
+}
diff --git a/src/toolbars/ToolManager.h b/src/toolbars/ToolManager.h
index 25e927a3f..111f8a04f 100644
--- a/src/toolbars/ToolManager.h
+++ b/src/toolbars/ToolManager.h
@@ -75,6 +75,8 @@ class ToolManager final : public wxEvtHandler
void OnMouse( wxMouseEvent & event );
void OnCaptureLost( wxMouseCaptureLostEvent & event );
void OnGrabber( GrabberEvent & event );
+ void HandleEscapeKey();
+ void DoneDragging();
void OnIndicatorCreate( wxWindowCreateEvent & event );
void OnIndicatorPaint( wxPaintEvent & event );
@@ -87,7 +89,7 @@ class ToolManager final : public wxEvtHandler
ToolFrame *mDragWindow;
ToolDock *mDragDock;
- ToolBar *mDragBar;
+ ToolBar *mDragBar {};
wxPoint mDragOffset;
int mDragBefore;
@@ -112,6 +114,10 @@ class ToolManager final : public wxEvtHandler
ToolBar *mBars[ ToolBarCount ];
+ wxPoint mPrevPosition {};
+ ToolDock *mPrevDock {};
+ int mPrevSlot {-1};
+
public:
DECLARE_CLASS( ToolManager );
diff --git a/src/tracks/ui/Scrubbing.cpp b/src/tracks/ui/Scrubbing.cpp
index 5610bc413..e3155a007 100644
--- a/src/tracks/ui/Scrubbing.cpp
+++ b/src/tracks/ui/Scrubbing.cpp
@@ -342,16 +342,12 @@ void Scrubber::StopScrubbing()
mScrubStartPosition = -1;
mSmoothScrollingScrub = false;
- const auto ctb = mProject->GetControlToolBar();
- if (IsScrubbing())
+ if (!IsScrubbing())
{
- if (gAudioIO->IsBusy()) {
- ctb->StopPlaying();
- }
- }
- else {
- // Didn't really play, but did change button apperance
+ // Marked scrub start, but
+ // didn't really play, but did change button apperance
+ const auto ctb = mProject->GetControlToolBar();
ctb->SetPlay(false, ControlToolBar::PlayAppearance::Straight);
}
}
@@ -596,9 +592,11 @@ void Scrubber::DoScrub(bool scroll, bool seek)
UncheckAllMenuItems();
CheckMenuItem();
}
- else
- // unchecks items
- StopScrubbing();
+ else {
+ // This will call back to Scrubber::StopScrubbing
+ const auto ctb = mProject->GetControlToolBar();
+ ctb->StopPlaying();
+ }
}
void Scrubber::OnScrub()
diff --git a/src/tracks/ui/Scrubbing.h b/src/tracks/ui/Scrubbing.h
index d4347c691..2ca11dcb3 100644
--- a/src/tracks/ui/Scrubbing.h
+++ b/src/tracks/ui/Scrubbing.h
@@ -37,6 +37,8 @@ public:
// Returns true iff the event should be considered consumed by this:
bool MaybeStartScrubbing(const wxMouseEvent &event);
void ContinueScrubbing();
+
+ // This is meant to be called only from ControlToolBar
void StopScrubbing();
wxCoord GetScrubStartPosition() const
diff --git a/src/widgets/Grabber.cpp b/src/widgets/Grabber.cpp
index b578b2a98..b0c760c46 100644
--- a/src/widgets/Grabber.cpp
+++ b/src/widgets/Grabber.cpp
@@ -44,6 +44,7 @@ BEGIN_EVENT_TABLE(Grabber, wxWindow)
EVT_LEAVE_WINDOW(Grabber::OnLeave)
EVT_LEFT_DOWN(Grabber::OnLeftDown)
EVT_PAINT(Grabber::OnPaint)
+ EVT_KEY_DOWN(Grabber::OnKeyDown)
END_EVENT_TABLE()
//
@@ -78,12 +79,12 @@ Grabber::~Grabber()
//
// Queue a drag event
//
-void Grabber::SendEvent(wxEventType type, const wxPoint & pos)
+void Grabber::SendEvent(wxEventType type, const wxPoint & pos, bool escaping)
{
wxWindow *parent = GetParent();
// Initialize event and convert mouse coordinates to screen space
- GrabberEvent e(type, GetId(), parent->ClientToScreen(pos));
+ GrabberEvent e(type, GetId(), parent->ClientToScreen(pos), escaping);
// Set the object of our desire
e.SetEventObject(parent);
@@ -190,7 +191,7 @@ void Grabber::OnLeftDown(wxMouseEvent & event)
PushButton(true);
// Notify parent
- SendEvent(EVT_GRABBER_CLICKED, event.GetPosition());
+ SendEvent(EVT_GRABBER_CLICKED, event.GetPosition(), false);
event.Skip();
}
@@ -227,3 +228,15 @@ void Grabber::OnPaint(wxPaintEvent & WXUNUSED(event))
// Redraw the grabber
DrawGrabber(dc);
}
+
+void Grabber::OnKeyDown(wxKeyEvent &event)
+{
+ event.Skip();
+
+ if(event.GetKeyCode() == WXK_ESCAPE) {
+ // We must not only skip this key event, but propagate it up the window
+ // hierarchy, so that ToolFrame detects it too.
+ event.ResumePropagation(wxEVENT_PROPAGATE_MAX);
+ SendEvent(EVT_GRABBER_CLICKED, wxPoint{ -1, -1 }, true);
+ }
+}
diff --git a/src/widgets/Grabber.h b/src/widgets/Grabber.h
index 28e1e8f75..e3b4d0417 100644
--- a/src/widgets/Grabber.h
+++ b/src/widgets/Grabber.h
@@ -45,17 +45,15 @@ class GrabberEvent final : public wxCommandEvent
GrabberEvent(wxEventType type = wxEVT_NULL,
wxWindowID winid = 0,
- const wxPoint& pt = wxDefaultPosition)
+ const wxPoint& pt = wxDefaultPosition,
+ bool escaping = false)
: wxCommandEvent(type, winid)
{
mPos = pt;
+ mEscaping = escaping;
}
- GrabberEvent(const GrabberEvent & event)
- : wxCommandEvent(event)
- {
- mPos = event.mPos;
- }
+ GrabberEvent(const GrabberEvent & event) = default;
// Position of event (in screen coordinates)
const wxPoint & GetPosition() const
@@ -68,6 +66,8 @@ class GrabberEvent final : public wxCommandEvent
mPos = pos;
}
+ bool IsEscaping() const { return mEscaping; }
+
// Clone is required by wxwidgets; implemented via copy constructor
wxEvent *Clone() const override
{
@@ -77,6 +77,7 @@ class GrabberEvent final : public wxCommandEvent
protected:
wxPoint mPos;
+ bool mEscaping {};
};
typedef void (wxEvtHandler::*GrabberEventFunction)(GrabberEvent &);
@@ -105,7 +106,8 @@ class Grabber final : public wxWindow
// not a need to dock/float a toolbar from the keyboard. If this
// changes, remove this and add the necessary keyboard movement
// handling.
- bool AcceptsFocus() const {return false;}
+ // PRL: Commented out so the ESC key can stop dragging.
+ // bool AcceptsFocus() const {return false;}
void PushButton(bool state);
@@ -115,11 +117,12 @@ class Grabber final : public wxWindow
void OnEnter(wxMouseEvent & event);
void OnLeave(wxMouseEvent & event);
void OnPaint(wxPaintEvent & event);
+ void OnKeyDown(wxKeyEvent & event);
private:
void DrawGrabber(wxDC & dc);
- void SendEvent(wxEventType type, const wxPoint & pos);
+ void SendEvent(wxEventType type, const wxPoint & pos, bool escaping);
bool mOver;
bool mPressed;