Files
GajuDesk/src/gd_m_wallet_importer.erl
2026-05-10 12:36:44 +09:00

185 lines
6.3 KiB
Erlang

%%% @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 <zxq9@zxq9.com>").
-copyright("Craig Everett <zxq9@zxq9.com>").
-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).