%%% @doc %%% A live modal for importing a wallet. %%% %%% Interprets [ENTER] as an "OK" button click and [ESC] as a "Cancel" button click. %%% @end -module(gd_m_wallet_importer). -vsn("0.9.0"). -author("Craig Everett "). -copyright("Craig Everett "). -license("GPL-3.0-or-later"). -behavior(zxw_modal). -export([show/6]). -export([init/1, handle_info/2, handle_event/2]). -include_lib("wx/include/wx.hrl"). -include("$zx_include/zx_logger.hrl"). -record(s, {frame = none :: none | wx:wx_object(), parent = none :: none | wx:wx_object(), caller = none :: none | pid(), name_tx = none :: none | wx:wx_object(), pass_tx = none :: none | wx:wx_object(), ok = none :: none | wx:wx_object(), cancel = none :: none | wx:wx_object()}). %%% Interface -spec show(Parent, Title, NameLabel, PassLabel, OK_L, Cancel_L) -> {ok, Name, Pass} | cancel when Parent :: wxFrame:wxFrame(), Title :: string(), NameLabel :: string(), PassLabel :: string(), OK_L :: string(), Cancel_L :: string(), Name :: string(), Pass :: string() | none. show(Parent, Title, NameLabel, PassLabel, OK_L, Cancel_L) -> zxw_modal:show(Parent, ?MODULE, {Title, NameLabel, PassLabel, OK_L, Cancel_L}). %% Init init({Parent, Caller, {Title, NameLabel, PassLabel, OK_L, Cancel_L}}) -> Frame = wxFrame:new(Parent, ?wxID_ANY, Title), Panel = wxWindow:new(Frame, ?wxID_ANY), TopSz = wxBoxSizer:new(?wxVERTICAL), _ = wxBoxSizer:add(TopSz, Panel, zxw:flags(wide)), MainSz = wxBoxSizer:new(?wxVERTICAL), NameSz = wxStaticBoxSizer:new(?wxVERTICAL, Panel, [{label, NameLabel}]), NameTx = wxTextCtrl:new(Panel, ?wxID_ANY, [{style, ?wxTE_PROCESS_TAB}]), _ = wxSizer:add(NameSz, NameTx, zxw:flags({wide, 5})), PassSz = wxStaticBoxSizer:new(?wxVERTICAL, Panel, [{label, PassLabel}]), PassTx = wxTextCtrl:new(Panel, ?wxID_ANY, [{style, ?wxTE_PROCESS_TAB bor ?wxTE_PASSWORD}]), _ = wxSizer:add(PassSz, PassTx, zxw:flags({wide, 5})), OK = wxButton:new(Panel, ?wxID_ANY, [{label, OK_L}]), Cancel = wxButton:new(Panel, ?wxID_ANY, [{label, Cancel_L}]), ButtSz = wxBoxSizer:new(?wxHORIZONTAL), _ = wxBoxSizer:add(ButtSz, OK, zxw:flags({wide, 5})), _ = wxBoxSizer:add(ButtSz, Cancel, zxw:flags({wide, 5})), _ = wxBoxSizer:add(MainSz, NameSz, zxw:flags({wide, 5})), _ = wxBoxSizer:add(MainSz, PassSz, zxw:flags({wide, 5})), _ = wxBoxSizer:add(MainSz, ButtSz, zxw:flags({wide, 5})), HandleKey = key_handler(NameTx, PassTx, OK, Cancel), ok = wxFrame:connect(Frame, key_down, [{callback, HandleKey}]), ok = wxTextCtrl:connect(NameTx, key_down, [{callback, HandleKey}]), ok = wxTextCtrl:connect(PassTx, key_down, [{callback, HandleKey}]), ok = wxTextCtrl:connect(OK, key_down, [{callback, HandleKey}]), ok = wxTextCtrl:connect(Cancel, key_down, [{callback, HandleKey}]), ok = wxFrame:connect(Frame, command_button_clicked), ok = wxFrame:connect(Frame, close_window), ok = wxFrame:setSize(Frame, {500, 220}), ok = wxWindow:setSizer(Panel, MainSz), ok = wxFrame:setSizer(Frame, TopSz), ok = wxBoxSizer:layout(MainSz), ok = wxFrame:centerOnParent(Frame), ok = wxTextCtrl:setFocus(NameTx), true = wxFrame:show(Frame), State = #s{frame = Frame, parent = Parent, caller = Caller, name_tx = NameTx, pass_tx = PassTx, ok = OK, cancel = Cancel}, {Frame, State}. key_handler(NameTx, PassTx, OK, Cancel) -> Me = self(), NameID = wxTextCtrl:getId(NameTx), PassID = wxTextCtrl:getId(PassTx), OK_ID = wxButton:getId(OK), CancelID = wxButton:getId(Cancel), fun(#wx{id = ID, event = #wxKey{type = key_down, keyCode = Code}}, KeyPress) -> case Code of 9 -> case ID of NameID -> Me ! {tab, name}; PassID -> Me ! {tab, pass}; OK_ID -> Me ! {tab, ok}; CancelID -> Me ! {tab, cancel}; _ -> wxEvent:skip(KeyPress) end; 13 -> case ID of NameID -> Me ! {enter, name}; PassID -> Me ! {enter, pass}; _ -> wxEvent:skip(KeyPress) end; 27 -> Me ! esc; _ -> wxEvent:skip(KeyPress) end end. handle_info({tab, Element}, State) -> ok = tab_traverse(Element, State), {noreply, State}; handle_info({enter, name}, State = #s{pass_tx = PassTx}) -> ok = wxTextCtrl:setFocus(PassTx), {noreply, State}; handle_info({enter, pass}, State) -> done(State); handle_info(esc, State) -> ok = cancel(State), {noreply, State}; handle_info(Message, State) -> ok = log(warning, "Message: ~p~nState: ~p~n", [Message, State]), {noreply, State}. handle_event(#wx{event = #wxCommand{type = command_button_clicked}, id = ID}, State = #s{ok = OK, cancel = Cancel}) -> OK_ID = wxButton:getId(OK), CancelID = wxButton:getId(Cancel), case ID of OK_ID -> done(State); CancelID -> cancel(State) end; handle_event(#wx{event = #wxClose{}}, State) -> NewState = cancel(State), {noreply, NewState}; handle_event(Event, State) -> ok = log(warning, "Unexpected event ~tp State: ~tp~n", [Event, State]), {noreply, State}. %%% Doers tab_traverse(name, #s{pass_tx = PassTx}) -> wxTextCtrl:setFocus(PassTx); tab_traverse(pass, #s{ok = OK}) -> wxButton:setFocus(OK); tab_traverse(ok, #s{cancel = Cancel}) -> wxButton:setFocus(Cancel); tab_traverse(cancel, #s{name_tx = NameTx}) -> wxTextCtrl:setFocus(NameTx). cancel(#s{frame = Frame, caller = Caller}) -> ok = wxFrame:destroy(Frame), zxw_modal:done(Caller, cancel). done(#s{frame = Frame, caller = Caller, name_tx = NameTx, pass_tx = PassTx}) -> Result = case wxTextCtrl:getValue(NameTx) of "" -> cancel; Name -> case wxTextCtrl:getValue(PassTx) of "" -> {ok, Name, none}; Pass -> {ok, Name, Pass} end end, ok = wxFrame:destroy(Frame), zxw_modal:done(Caller, Result).