Try another way of fixing accelerators stealing text control arrow keys (#1263).
authorCarl Hetherington <cth@carlh.net>
Wed, 23 May 2018 22:51:09 +0000 (23:51 +0100)
committerCarl Hetherington <cth@carlh.net>
Thu, 24 May 2018 22:33:08 +0000 (23:33 +0100)
src/tools/dcpomatic.cc
src/wx/dcp_panel.cc
src/wx/focus_manager.cc [new file with mode: 0644]
src/wx/focus_manager.h [new file with mode: 0644]
src/wx/wscript

index 33e90aef35260306b29562ea2e625e7ed9c58fed..4f034b2b5a3d013c699b01f560cb26ee0c2cefb6 100644 (file)
@@ -44,6 +44,7 @@
 #include "wx/nag_dialog.h"
 #include "wx/export_dialog.h"
 #include "wx/paste_dialog.h"
+#include "wx/focus_manager.h"
 #include "lib/film.h"
 #include "lib/config.h"
 #include "lib/util.h"
@@ -331,6 +332,15 @@ public:
 
                overall_panel->SetSizer (main_sizer);
 
+               UpdateChecker::instance()->StateChanged.connect (boost::bind (&DOMFrame::update_checker_state_changed, this));
+
+               FocusManager::instance()->SetFocus.connect (boost::bind (&DOMFrame::remove_accelerators, this));
+               FocusManager::instance()->KillFocus.connect (boost::bind (&DOMFrame::add_accelerators, this));
+               add_accelerators ();
+       }
+
+       void add_accelerators ()
+       {
 #ifdef __WXOSX__
                int accelerators = 7;
 #else
@@ -348,15 +358,18 @@ public:
 #endif
                Bind (wxEVT_MENU, boost::bind (&ContentPanel::add_file_clicked, _film_editor->content_panel()), ID_add_file);
                Bind (wxEVT_MENU, boost::bind (&DOMFrame::remove_clicked, this, _1), ID_remove);
-               Bind (wxEVT_MENU, boost::bind (&DOMFrame::start_stop_pressed, this, _1), ID_start_stop);
+               Bind (wxEVT_MENU, boost::bind (&DOMFrame::start_stop_pressed, this), ID_start_stop);
                Bind (wxEVT_MENU, boost::bind (&DOMFrame::timeline_pressed, this), ID_timeline);
-               Bind (wxEVT_MENU, boost::bind (&DOMFrame::back_frame, this, _1), ID_back_frame);
-               Bind (wxEVT_MENU, boost::bind (&DOMFrame::forward_frame, this, _1), ID_forward_frame);
+               Bind (wxEVT_MENU, boost::bind (&DOMFrame::back_frame, this), ID_back_frame);
+               Bind (wxEVT_MENU, boost::bind (&DOMFrame::forward_frame, this), ID_forward_frame);
                wxAcceleratorTable accel_table (accelerators, accel);
                SetAcceleratorTable (accel_table);
                delete[] accel;
+       }
 
-               UpdateChecker::instance()->StateChanged.connect (boost::bind (&DOMFrame::update_checker_state_changed, this));
+       void remove_accelerators ()
+       {
+               SetAcceleratorTable (wxAcceleratorTable ());
        }
 
        void remove_clicked (wxCommandEvent& ev)
@@ -1213,26 +1226,8 @@ private:
                _update_news_requested = false;
        }
 
-       /** Skip the given event if we're focussed in a TextCtrl, so that hotkeys don't
-        *  steal from text controls.
-        */
-       bool maybe_pass (wxCommandEvent& ev)
+       void start_stop_pressed ()
        {
-               wxWindow* f = wxWindow::FindFocus();
-               if (!f || !dynamic_cast<wxTextCtrl*>(f)) {
-                       return false;
-               }
-
-               ev.Skip();
-               return true;
-       }
-
-       void start_stop_pressed (wxCommandEvent& ev)
-       {
-               if (maybe_pass(ev)) {
-                       return;
-               }
-
                if (_film_viewer->playing()) {
                        _film_viewer->stop();
                } else {
@@ -1245,21 +1240,13 @@ private:
                _film_editor->content_panel()->timeline_clicked ();
        }
 
-       void back_frame (wxCommandEvent& ev)
+       void back_frame ()
        {
-               if (maybe_pass(ev)) {
-                       return;
-               }
-
                _film_viewer->back_frame ();
        }
 
-       void forward_frame (wxCommandEvent& ev)
+       void forward_frame ()
        {
-               if (maybe_pass(ev)) {
-                       return;
-               }
-
                _film_viewer->forward_frame ();
        }
 
index 397a29d4819f7cd4b64067d47be24570873a4481..f2783af6b94d0bc49db4edd8655aa577c0bb6056 100644 (file)
@@ -23,6 +23,7 @@
 #include "key_dialog.h"
 #include "isdcf_metadata_dialog.h"
 #include "audio_dialog.h"
+#include "focus_manager.h"
 #include "lib/ratio.h"
 #include "lib/config.h"
 #include "lib/dcp_content_type.h"
@@ -74,6 +75,8 @@ DCPPanel::DCPPanel (wxNotebook* n, boost::shared_ptr<Film> film)
        grid->Add (_name, wxGBPosition(r, 1), wxDefaultSpan, wxEXPAND | wxLEFT | wxRIGHT);
        ++r;
 
+       FocusManager::instance()->add(_name);
+
        int flags = wxALIGN_CENTER_VERTICAL;
 #ifdef __WXOSX__
        flags |= wxALIGN_RIGHT;
diff --git a/src/wx/focus_manager.cc b/src/wx/focus_manager.cc
new file mode 100644 (file)
index 0000000..f4f23cb
--- /dev/null
@@ -0,0 +1,55 @@
+/*
+    Copyright (C) 2018 Carl Hetherington <cth@carlh.net>
+
+    This file is part of DCP-o-matic.
+
+    DCP-o-matic is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    DCP-o-matic is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with DCP-o-matic.  If not, see <http://www.gnu.org/licenses/>.
+
+*/
+
+#include "focus_manager.h"
+#include <wx/textctrl.h>
+
+FocusManager* FocusManager::_instance;
+
+FocusManager *
+FocusManager::instance()
+{
+       if (!_instance) {
+               _instance = new FocusManager();
+       }
+
+       return _instance;
+}
+
+void
+FocusManager::set_focus (wxFocusEvent& ev)
+{
+       SetFocus();
+       ev.Skip();
+}
+
+void
+FocusManager::kill_focus (wxFocusEvent& ev)
+{
+       KillFocus();
+       ev.Skip();
+}
+
+void
+FocusManager::add(wxTextCtrl* c)
+{
+       c->Bind(wxEVT_SET_FOCUS, boost::bind(&FocusManager::set_focus, this, _1));
+       c->Bind(wxEVT_KILL_FOCUS, boost::bind(&FocusManager::kill_focus, this, _1));
+}
diff --git a/src/wx/focus_manager.h b/src/wx/focus_manager.h
new file mode 100644 (file)
index 0000000..3c91c22
--- /dev/null
@@ -0,0 +1,51 @@
+/*
+    Copyright (C) 2018 Carl Hetherington <cth@carlh.net>
+
+    This file is part of DCP-o-matic.
+
+    DCP-o-matic is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    DCP-o-matic is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with DCP-o-matic.  If not, see <http://www.gnu.org/licenses/>.
+
+*/
+
+#include <boost/signals2.hpp>
+
+class wxTextCtrl;
+class wxFocusEvent;
+
+/** @class FocusManager class
+ *  @brief A central point for notifications about when wxTextCtrls get focus in the main window.
+ *
+ *  This allows us to turn off accelerators for the duration of the focus so that they don't steal
+ *  keypresses.  It's a hack but the only way I could make it work on all platforms (looking for
+ *  the focussed thing and doing ev.Skip() if it's a wxTextCtrl did not work for me on Windows:
+ *  ev.Skip() did not cause the event to be delivered).
+ */
+class FocusManager
+{
+public:
+       /** emitted when any add()ed TextCtrl gets focus */
+       boost::signals2::signal<void ()> SetFocus;
+       /** emitted when any add()ed TextCtrl loses focus */
+       boost::signals2::signal<void ()> KillFocus;
+
+       void add(wxTextCtrl* c);
+
+       static FocusManager* instance();
+
+private:
+       void set_focus(wxFocusEvent &);
+       void kill_focus(wxFocusEvent &);
+
+       static FocusManager* _instance;
+};
index 476cd468a6ba36d8330a06c7921bc75f9d9905cf..35861db00f144cb77861b123154fc407c975454c 100644 (file)
@@ -57,6 +57,7 @@ sources = """
           film_viewer.cc
           filter_dialog.cc
           filter_editor.cc
+          focus_manager.cc
           fonts_dialog.cc
           font_files_dialog.cc
           full_config_dialog.cc