20#include <unordered_map>
22#include <wx/eventfilter.h>
23#include <wx/spinctrl.h>
24#include <wx/textctrl.h>
41using Types = std::vector< Type >;
56using ByTypeMap = std::map< wxEventType, const Type& >;
60using ByCodeMap = std::unordered_map< Code, const Type & >;
84 std::function< std::optional<wxArrayStringEx>(
const wxEvent& ) >;
92 template<
typename Tag,
typename SerialFn >
96 return [
fn = std::move(
fn )](
const wxEvent &e ){
97 return fn(
dynamic_cast<const Tag&
>(e));
105 template<
typename Tag,
typename Fn >
110 using DeserializerResult =
112 static_assert( std::is_same_v< Tag&, DeserializerResult >,
113 "deserializer produces the wrong type" );
115 return std::move(
fn );
126 wxEventTypeTag<Tag> type,
129 const Code &code, SerialFn serialFn, DeserialFn deserialFn )
133 , serializer{ makeSerializer<Tag>(
std::move( serialFn ) ) }
134 , deserializer{ checkDeserializer( type,
std::move( deserialFn ) ) }
147 bool handled =
false;
148 if ( !fields.empty() ) {
150 auto first = fields.begin();
151 if (
auto iter = catalog.find( *first ); iter != catalog.end()) {
152 auto &type = iter->second;
153 fields.erase( first );
154 auto pEvent = type.deserializer( type.type, fields );
158 if (
auto pHandler =
dynamic_cast<wxEvtHandler*
>(
159 pEvent->GetEventObject() )
161 if (
auto pWindow =
dynamic_cast<wxWindow *
>(pHandler))
164 pHandler = pWindow->GetEventHandler();
165 pHandler->SafelyProcessEvent( *pEvent );
177 if (
auto pWindow =
dynamic_cast< wxWindow *
>( event.GetEventObject() ) )
184 std::optional< wxArrayStringEx > result;
192template<
typename Event = wxCommandEvent,
typename EventType >
194 const auto deserialize =
196 std::unique_ptr< wxCommandEvent > result;
197 if ( components.size() == 1 ) {
199 result = std::make_unique< wxCommandEvent >(
200 evtType, pWindow->GetId() );
201 result->SetEventObject( pWindow );
210template<
typename Event = wxCommandEvent,
typename EventType >
213 const auto serialize =
214 [](
const Event &event ) {
218 wxString::Format( L
"%d", event.GetInt() ? 1 : 0 ) );
222 const auto deserialize =
224 std::unique_ptr< Event > result;
226 if ( components.size() == 2 ) {
228 if (
long longValue; components[1].ToLong( &longValue ) ) {
229 bool value = (longValue != 0);
230 result = std::make_unique< Event >(
231 type, pWindow->GetId() );
232 result->SetEventObject( pWindow );
233 result->SetInt( value );
237 wxGenericValidator validator( &value );
238 validator.SetWindow( pWindow );
239 validator.TransferToWindow();
246 return Type{ type, code, serialize, deserialize };
249template<
typename Event = wxCommandEvent,
typename EventType >
252 const auto serialize =
253 [](
const Event &event ) {
256 result->push_back( wxString::Format( L
"%d", event.GetInt() ) );
260 const auto deserialize =
262 std::unique_ptr< Event > result;
264 if ( components.size() == 2 ) {
267 components[1].ToLong( &longValue ) &&
268 longValue == (value =
static_cast<int>(longValue) )
270 result = std::make_unique< Event >(
271 type, pWindow->GetId() );
272 result->SetEventObject( pWindow );
273 result->SetInt( value );
277 wxGenericValidator validator( &value );
278 validator.SetWindow( pWindow );
279 validator.TransferToWindow();
286 return Type{ type, code, serialize, deserialize };
289template<
typename Event = wxCommandEvent,
typename EventType >
292 const auto serialize =
293 [](
const Event &event ) {
296 result->push_back( event.GetString() );
300 const auto deserialize =
302 std::unique_ptr< Event > result;
303 if ( components.size() == 2 ) {
305 auto value = components[1];
306 result = std::make_unique< Event >(
307 type, pWindow->GetId() );
308 result->SetEventObject( pWindow );
309 result->SetString( value );
312 if (
auto pCtrl =
dynamic_cast<wxTextEntry*
>( pWindow ) ) {
316 pCtrl->ChangeValue( value );
320 wxGenericValidator validator( &value );
321 validator.SetWindow( pWindow );
322 validator.TransferToWindow();
329 return Type{ type, code, serialize, deserialize };
334 static Types result {
346 NumericalCommandType<wxSpinEvent>( wxEVT_SPINCTRL,
"Spin" ),
347 NumericalCommandType<wxSpinEvent>( wxEVT_SPIN_DOWN,
"SpinUp" ),
348 NumericalCommandType<wxSpinEvent>( wxEVT_SPIN_UP,
"SpinDown" ),
359 static std::once_flag
flag;
361 std::call_once(
flag, []{
363 result.emplace( type.type, type );
370 static std::once_flag
flag;
372 std::call_once(
flag, []{
374 result.emplace( type.code, type );
384 wxEvtHandler::AddFilter(
this );
389 wxEvtHandler::RemoveFilter(
this );
399 const auto type =
event.GetEventType();
400 if (
const auto iter = catalog.find(type); iter != catalog.end()) {
402 const auto &info = iter->second;
403 auto pStrings = info.serializer(event);
407 pStrings->insert(pStrings->begin(), info.code.GET());
Declare abstract class AudacityException, some often-used subclasses, and GuardedCall.
Toolkit-neutral facade for basic user interface services.
The output stream of the journal system.
Journal system's error status, command dictionary, initializers.
An explicitly nonlocalized string, not meant for the user to see.
const wxString & GET() const
Explicit conversion to wxString, meant to be ugly-looking and demanding of a comment why it's correct...
Extend wxArrayString with move operations and construction and insertion fromstd::initializer_list.
void CallAfter(Action action)
Schedule an action to be done later, and in the main thread.
MessageBoxResult ShowMessageBox(const TranslatableString &message, MessageBoxOptions options={})
Show a modal message box with either Ok or Yes and No, and optionally Cancel.
static bool sWatching
Whether the event filter is still watching events.
static const ByCodeMap & ByCode()
wxString WindowEventName(const wxEvent &event)
RegisteredInitializer initializer
static const ByTypeMap & ByType()
std::vector< Type > Types
static Type BooleanCommandType(EventType type, const wxString &code)
static const Types & TypeCatalog()
static Type NumericalCommandType(EventType type, const wxString &code)
static Type NullaryCommandType(EventType type, const wxString &code)
std::map< wxEventType, const Type & > ByTypeMap
std::unordered_map< Code, const Type & > ByCodeMap
std::optional< wxArrayStringEx > WindowEventSerialization(const wxEvent &event)
static Type TextualCommandType(EventType type, const wxString &code)
void FailedEventSerialization()
Path FindPath(const wxWindow &window)
wxWindow * FindByPath(const Path &path)
Facilities for recording and playback of sequences of user interaction.
void Output(const wxString &string)
RegisteredEventType(Code code)
Deserializer checkDeserializer(wxEventTypeTag< Tag > type, Fn fn)
std::function< std::optional< wxArrayStringEx >(const wxEvent &) > Serializer
Deserializer deserializer
Serializer makeSerializer(SerialFn fn)
std::function< std::unique_ptr< wxEvent >(wxEventType, const wxArrayStringEx &) > Deserializer
Code code
Persistent cross-platform name corresponding to the int.
wxEventType type
Just an int!
Type(wxEventTypeTag< Tag > type, const Code &code, SerialFn serialFn, DeserialFn deserialFn)
Singleton object listens to global wxEvent stream.
int FilterEvent(wxEvent &event) override