1%% This module is actually handwritten see ../api_gen/wx_extra/wxEvtHandler.erl
2%%
3%% @doc The Event handler.
4%%
5%% To get events from wxwidgets objects you subscribe to them by
6%% calling connect/[2-3].  Events are sent as messages, if no callback
7%% was supplied  These messages will be {@link wx(). #wx{}} where
8%% EventRecord is a record that depends on the {@link
9%% wxEventType(). event type}.  The records are defined in:
10%% wx/include/wx.hrl.
11%%
12%% If a callback was supplied to connect, the callback will be invoked
13%% (in another process) to handle the event. The callback should be of
14%% arity 2.  fun(EventRecord::wx(), EventObject::wxObject()).
15%%
16%% Beware that the callback will be in executed in new process each time.
17%%
18%% <a href="http://www.wxwidgets.org/manuals/stable/wx_wxevthandler.html">
19%% The orginal documentation</a>.
20%%
21%%
22-module(wxEvtHandler).
23-include("wxe.hrl").
24-include("../include/wx.hrl").
25
26%% API
27-export([connect/2, connect/3, disconnect/1, disconnect/2, disconnect/3]).
28
29%% internal exports
30-export([connect_impl/2, disconnect_impl/2]).
31
32-export_type([wxEvtHandler/0, wx/0, event/0]).
33-type wxEvtHandler() :: wx:wx_object().
34
35%% @doc Equivalent to {@link connect/3. connect(This, EventType, [])}
36-spec connect(This::wxEvtHandler(), EventType::wxEventType()) -> 'ok'.
37connect(This, EventType) ->
38    connect(This, EventType, []).
39
40%% @doc This function subscribes the to events of EventType,
41%% in the range id, lastId. The events will be received as messages
42%% if no callback is supplied.
43%%
44%% Options:
45%%    {id, integer()},      The identifier (or first of the identifier range) to be
46%%                            associated with this event handler.
47%%                          Default ?wxID_ANY
48%%    {lastId, integer()},  The second part of the identifier range.
49%%                          If used 'id' must be set as the starting identifier range.
50%%                          Default ?wxID_ANY
51%%    {skip,  boolean()},   If skip is true further event_handlers will be called.
52%%                          This is not used if the 'callback' option is used.
53%%                          Default false.
54%%    {callback, function()} Use a callback fun(EventRecord::wx(), EventObject::wxObject())
55%%                          to process the event. Default not specfied i.e. a message will
56%%                          be delivered to the process calling this function.
57%%    {userData, term()}    An erlang term that will be sent with the event. Default: [].
58-spec connect(This::wxEvtHandler(), EventType::wxEventType(), [Option]) -> 'ok' when
59      Option :: {'id', integer()} | {'lastId', integer()} | {'skip', boolean()} |
60		'callback' | {'callback', function()} | {'userData', term()}.
61connect(This=#wx_ref{type=ThisT}, EventType, Options) ->
62    EvH = parse_opts(Options, #evh{et=EventType}),
63    ?CLASS(ThisT,wxEvtHandler),
64    case wxe_util:connect_cb(This, EvH) of
65	ok -> ok;
66	{badarg, event_type} ->
67	    erlang:error({badarg,EventType})
68    end.
69
70parse_opts([{callback,Fun}|R], Opts) when is_function(Fun) ->
71    %% Check Fun Arity?
72    parse_opts(R, Opts#evh{cb=Fun});
73parse_opts([{callback,CB={nospawn, Fun}}|R], Opts) when is_function(Fun) ->
74    parse_opts(R, Opts#evh{cb=CB});
75parse_opts([callback|R], Opts) ->
76    parse_opts(R, Opts#evh{cb=self()});
77parse_opts([{userData, UserData}|R],Opts) ->
78    parse_opts(R, Opts#evh{userdata=UserData});
79parse_opts([{skip, Skip}|R],Opts) when is_boolean(Skip) ->
80    parse_opts(R, Opts#evh{skip=Skip});
81parse_opts([{id, Id}|R],Opts) when is_integer(Id) ->
82    parse_opts(R, Opts#evh{id=Id});
83parse_opts([{lastId, Id}|R],Opts) when is_integer(Id) ->
84    parse_opts(R, Opts#evh{lastId=Id});
85parse_opts([_BadArg|R], Opts) ->
86    parse_opts(R, Opts);
87parse_opts([], Opts = #evh{id=Id,lastId=Lid,skip=Skip, cb=CB}) ->
88    if
89	Skip =/= undefined andalso CB =/= 0 ->
90	    erlang:error({badarg, {combined, skip, callback}});
91	Lid =/= ?wxID_ANY andalso Id =:= ?wxID_ANY  ->
92	    erlang:error({badarg, no_start_identifier_range});
93	Skip =:= undefined ->  %% Default
94	    Opts#evh{skip=false};
95	true ->
96	    Opts
97    end.
98
99
100%% @doc Equivalent to {@link disconnect/3. disconnect(This, null, [])}
101%% Can also have an optional callback Fun() as an additional last argument.
102-spec disconnect(This::wxEvtHandler()) -> boolean().
103disconnect(This=#wx_ref{type=ThisT,ref=_ThisRef}) ->
104    ?CLASS(ThisT,wxEvtHandler),
105    disconnect(This, null, []).
106
107%% @doc Equivalent to {@link disconnect/3. disconnect(This, EventType, [])}
108-spec disconnect(This::wxEvtHandler(), EventType::wxEventType()) -> boolean().
109disconnect(This=#wx_ref{type=ThisT,ref=_ThisRef}, EventType) when is_atom(EventType) ->
110    ?CLASS(ThisT,wxEvtHandler),
111    disconnect(This, EventType, []).
112
113%% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxevthandler.html#wxevthandlerdisconnect">external documentation</a>
114%% This function unsubscribes the process or callback fun from the event handler.
115%% EventType may be the atom 'null' to match any eventtype.
116%% Notice that the options skip and userdata is not used to match the eventhandler.
117-spec disconnect(This::wxEvtHandler(), EventType::wxEventType(), [Option]) -> boolean() when
118      Option :: {'id', integer()} | {'lastId', integer()} | {'callback', function()}.
119disconnect(This=#wx_ref{type=ThisT,ref=_ThisRef}, EventType, Opts) ->
120    ?CLASS(ThisT,wxEvtHandler),
121    EvH = parse_opts(Opts, #evh{et=EventType}),
122    case wxe_util:disconnect_cb(This, EvH) of
123	{badarg, event_type} ->
124	    erlang:error({badarg,EventType});
125	Bool ->
126	    Bool
127    end.
128
129
130%% @hidden
131connect_impl(#wx_ref{type=ThisT,ref=ThisRef},
132	     #evh{id=Winid, lastId=LastId, et=EventType,
133		  skip=Skip, userdata=Userdata, cb=FunID})
134  when is_integer(FunID)->
135    EventTypeBin = list_to_binary([atom_to_list(EventType)|[0]]),
136    ThisTypeBin = list_to_binary([atom_to_list(ThisT)|[0]]),
137    UD = if Userdata =:= [] -> 0;
138	    true ->
139		 wxe_util:send_bin(term_to_binary(Userdata)),
140		 1
141	 end,
142    wxe_util:call(100, <<ThisRef:32/?UI,
143			Winid:32/?UI,LastId:32/?UI,
144			(wxe_util:from_bool(Skip)):32/?UI,
145			UD:32/?UI,
146			FunID:32/?UI,
147			(size(EventTypeBin)):32/?UI,
148			(size(ThisTypeBin)):32/?UI,
149			%% Note no alignment
150			EventTypeBin/binary,ThisTypeBin/binary>>).
151
152%% @hidden
153disconnect_impl(#wx_ref{type=_ThisT,ref=ThisRef},
154		#evh{id=Winid, lastId=LastId, et=EventType,
155		     handler=#wx_ref{type=wxeEvtListener,ref=EvtList}}) ->
156    EventTypeBin = list_to_binary([atom_to_list(EventType)|[0]]),
157    wxe_util:call(101, <<EvtList:32/?UI,
158			ThisRef:32/?UI,Winid:32/?UI,LastId:32/?UI,
159			(size(EventTypeBin)):32/?UI,
160			%% Note no alignment
161			EventTypeBin/binary>>).
162