diff options
Diffstat (limited to 'wx+')
-rw-r--r-- | wx+/file_drop.h | 8 | ||||
-rw-r--r-- | wx+/key_event.h | 118 | ||||
-rw-r--r-- | wx+/popup_dlg_generated.cpp | 2 | ||||
-rw-r--r-- | wx+/popup_dlg_generated.h | 2 |
4 files changed, 120 insertions, 10 deletions
diff --git a/wx+/file_drop.h b/wx+/file_drop.h index 1cc24ebd..5a28096d 100644 --- a/wx+/file_drop.h +++ b/wx+/file_drop.h @@ -35,14 +35,6 @@ void setupFileDrop(wxWindow& wnd); - - - - - - - - namespace impl { inline diff --git a/wx+/key_event.h b/wx+/key_event.h new file mode 100644 index 00000000..60cb7372 --- /dev/null +++ b/wx+/key_event.h @@ -0,0 +1,118 @@ +// ************************************************************************** +// * This file is part of the FreeFileSync project. It is distributed under * +// * GNU General Public License: http://www.gnu.org/licenses/gpl.html * +// * Copyright (C) Zenju (zenju AT gmx DOT de) - All Rights Reserved * +// ************************************************************************** + +#ifndef KEY_EVENT_H_086130871086708354674 +#define KEY_EVENT_H_086130871086708354674 + +#include <functional> +#include <zen/scope_guard.h> +#include <wx/toplevel.h> +#include <wx/window.h> +#include <wx/event.h> + +namespace zen +{ +//wxWidgets provides no elegant way to register shortcut keys scoped for dialog windows => +//enable dialog-specific local key events! + +//setup in wxDialog-derived class' constructor, e.g.: +// setupLocalKeyEvents(*this, [this](wxKeyEvent& event){ this->onLocalKeyEvent(event); }); +// +// => redirects local key events to: +// void MyDlg::onLocalKeyEvent(wxKeyEvent& event); +void setupLocalKeyEvents(wxWindow& wnd, const std::function<void(wxKeyEvent& event)>& callback); //callback held during life time of "wnd"! + + + + + + + +//pretty much the same like "bool wxWindowBase::IsDescendant(wxWindowBase* child) const" but without the obvious misnaming +inline +bool isComponentOf(const wxWindow* child, const wxWindow* top) +{ + for (const wxWindow* wnd = child; wnd != nullptr; wnd = wnd->GetParent()) + if (wnd == top) + return true; + return false; +} + + +namespace impl +{ +inline +const wxTopLevelWindow* getTopLevelWindow(const wxWindow* child) +{ + for (const wxWindow* wnd = child; wnd != nullptr; wnd = wnd->GetParent()) + if (auto tlw = dynamic_cast<const wxTopLevelWindow*>(wnd)) + return tlw; + return nullptr; +} + + +class LokalKeyEventHandler : public wxWindow //private wxEvtHandler +{ +public: + LokalKeyEventHandler(wxWindow& parent, const std::function<void(wxKeyEvent& event)>& callback) : wxWindow(&parent, wxID_ANY), //use a dummy child window to bind instance life time to parent + parent_(parent), + callback_(callback), + processingCallback(false) + { + Hide(); //this is just a dummy window so that its parent can have ownership + Disable(); // + + //register global hotkeys (without needing explicit menu entry) + wxTheApp->Connect(wxEVT_KEY_DOWN, wxKeyEventHandler(LokalKeyEventHandler::onGlobalKeyEvent), nullptr, this); + wxTheApp->Connect(wxEVT_CHAR_HOOK, wxKeyEventHandler(LokalKeyEventHandler::onGlobalKeyEvent), nullptr, this); //capture direction keys + } + + ~LokalKeyEventHandler() + { + //important! event source wxTheApp lives longer than this instance -> disconnect! + wxTheApp->Disconnect(wxEVT_KEY_DOWN, wxKeyEventHandler(LokalKeyEventHandler::onGlobalKeyEvent), nullptr, this); + wxTheApp->Disconnect(wxEVT_CHAR_HOOK, wxKeyEventHandler(LokalKeyEventHandler::onGlobalKeyEvent), nullptr, this); + } + +private: + void onGlobalKeyEvent(wxKeyEvent& event) + { + const wxWindow* focus = wxWindow::FindFocus(); + const wxTopLevelWindow* tlw = getTopLevelWindow(&parent_); + + //avoid recursion!!! -> this ugly construct seems to be the only (portable) way to avoid re-entrancy + //recursion may happen in multiple situations: e.g. modal dialogs, Grid::ProcessEvent()! + if (processingCallback || + !isComponentOf(focus, &parent_) || + !parent_.IsEnabled() || //only handle if window is in use and no modal dialog is shown: + !tlw || !const_cast<wxTopLevelWindow*>(tlw)->IsActive()) //thanks to wxWidgets non-portability we need both checks: + //IsEnabled() is sufficient for Windows, IsActive() is needed on OS X since it does NOT disable the parent when showing a modal dialog + { + event.Skip(); + return; + } + processingCallback = true; + ZEN_ON_SCOPE_EXIT(processingCallback = false;) + + callback_(event); + } + + wxWindow& parent_; + const std::function<void(wxKeyEvent& event)> callback_; + bool processingCallback; +}; +} + + +inline +void setupLocalKeyEvents(wxWindow& wnd, const std::function<void(wxKeyEvent& event)>& callback) +{ + new impl::LokalKeyEventHandler(wnd, callback); //ownership passed to "wnd"! +} + +} + +#endif //KEY_EVENT_H_086130871086708354674 diff --git a/wx+/popup_dlg_generated.cpp b/wx+/popup_dlg_generated.cpp index 70c5cb20..bb804026 100644 --- a/wx+/popup_dlg_generated.cpp +++ b/wx+/popup_dlg_generated.cpp @@ -1,5 +1,5 @@ /////////////////////////////////////////////////////////////////////////// -// C++ code generated with wxFormBuilder (version Oct 8 2012) +// C++ code generated with wxFormBuilder (version Feb 26 2014) // http://www.wxformbuilder.org/ // // PLEASE DO "NOT" EDIT THIS FILE! diff --git a/wx+/popup_dlg_generated.h b/wx+/popup_dlg_generated.h index 3aab2257..0afd1f55 100644 --- a/wx+/popup_dlg_generated.h +++ b/wx+/popup_dlg_generated.h @@ -1,5 +1,5 @@ /////////////////////////////////////////////////////////////////////////// -// C++ code generated with wxFormBuilder (version Oct 8 2012) +// C++ code generated with wxFormBuilder (version Feb 26 2014) // http://www.wxformbuilder.org/ // // PLEASE DO "NOT" EDIT THIS FILE! |