%%% @doc %%% GajuMine Configuration GUI %%% @end -module(gmc_conf). -vsn("0.2.5"). -author("Craig Everett "). -copyright("QPQ AG "). -license("GPL-3.0-or-later"). -behavior(wx_object). -include_lib("wx/include/wx.hrl"). -export([to_front/0, trouble/1]). -export([start_link/1]). -export([init/1, terminate/2, code_change/3, handle_call/3, handle_cast/2, handle_info/2, handle_event/2]). -include("$zx_include/zx_logger.hrl"). -record(s, {wx = none :: none | wx:wx_object(), frame = none :: none | wx:wx_object(), lang = en :: en | jp, j = none :: none | fun(), net = none :: none | wx:wx_object(), acc = none :: none | wx:wx_object(), keys = none :: none | wx:wx_object(), cores = none :: none | wx:wx_object(), memory = none :: none | wx:wx_object()}). %%% Interface functions -spec to_front() -> ok. to_front() -> wx_object:cast(?MODULE, to_front). -spec trouble(term()) -> ok. trouble(Info) -> wx_object:cast(?MODULE, {trouble, Info}). %%% Startup Functions start_link(Prefs) -> wx_object:start_link({local, ?MODULE}, ?MODULE, Prefs, []). init({Prefs, {Net, Acc, Keys, {AProcs, AMem, MProcs, MMem}}}) -> ok = log(info, "GUI starting..."), Lang = maps:get(lang, Prefs, en_US), Trans = gd_jt:read_translations(?MODULE), J = gd_jt:j(Lang, Trans), Label = J("Configure GajuMine"), WX = wx:new(), Frame = wxFrame:new(WX, ?wxID_ANY, Label), MainSz = wxBoxSizer:new(?wxVERTICAL), AccSz = wxStaticBoxSizer:new(?wxVERTICAL, Frame, [{label, J("GajuMining Account ID")}]), AccTx = wxTextCtrl:new(Frame, ?wxID_ANY, [{value, acc(Acc)}]), _ = wxStaticBoxSizer:add(AccSz, AccTx, wide(5)), KeysSz = wxStaticBoxSizer:new(?wxVERTICAL, Frame, [{label, J("Additional Account IDs (optional)")}]), KeysTx = wxTextCtrl:new(Frame, ?wxID_ANY, [{style, ?wxTE_MULTILINE}, {value, keys(Keys)}]), _ = wxStaticBoxSizer:add(KeysSz, KeysTx, wide(5)), StatSz = wxStaticBoxSizer:new(?wxVERTICAL, Frame, [{label, J("Max System Committment (optional)")}]), AProcsS = i_to_l(AProcs), MProcsS = i_to_l(MProcs), AMemS = gigs(AMem), MMemS = gigs(MMem), Labels = [{J("HW Cores"), J("Max Cores"), AProcsS, MProcsS}, {J("Memory (GB)"), J("Max Memory"), AMemS, MMemS}], {Grid, [CoresTx, MemoryTx]} = display_box(Frame, Labels), Network = wxRadioBox:new(Frame, ?wxID_ANY, J("Network"), {0, 0}, {50, 50}, [J("Mainnet"), J("Testnet")]), ok = wxRadioBox:setSelection(Network, net_num(Net)), ButtSz = wxBoxSizer:new(?wxHORIZONTAL), Affirm = wxButton:new(Frame, ?wxID_OK), Cancel = wxButton:new(Frame, ?wxID_CANCEL), _ = wxBoxSizer:add(StatSz, Grid, wide(5)), _ = wxBoxSizer:add(ButtSz, Affirm, wide(5)), _ = wxBoxSizer:add(ButtSz, Cancel, wide(5)), _ = wxBoxSizer:add(MainSz, AccSz, base(5)), _ = wxBoxSizer:add(MainSz, KeysSz, wide(5)), _ = wxBoxSizer:add(MainSz, StatSz, base(5)), _ = wxBoxSizer:add(MainSz, Network, base(5)), _ = wxBoxSizer:add(MainSz, ButtSz, base(5)), ok = wxFrame:setSizer(Frame, MainSz), ok = wxBoxSizer:layout(MainSz), ok = wxFrame:connect(Frame, command_button_clicked), ok = wxFrame:connect(Frame, close_window), ok = wxFrame:setSize(Frame, {500, 500}), ok = wxFrame:center(Frame), true = wxFrame:show(Frame), State = #s{wx = WX, frame = Frame, lang = Lang, j = J, net = Network, acc = AccTx, keys = KeysTx, cores = CoresTx, memory = MemoryTx}, {Frame, State}. i_to_l(none) -> "0"; i_to_l(N) when is_integer(N) -> integer_to_list(N). base(Padding) -> [{proportion, 0}, {flag, ?wxEXPAND bor ?wxALL}, {border, Padding}]. wide(Padding) -> [{proportion, 1}, {flag, ?wxEXPAND bor ?wxALL}, {border, Padding}]. center() -> [{proportion, 0}, {flag, ?wxEXPAND bor ?wxALIGN_CENTER_VERTICAL}]. gigs(none) -> "0"; gigs(Bytes) -> float_to_list(Bytes / gig(), [{decimals, 2}, compact]). gig() -> 1_073_741_824. display_box(Parent, Labels) -> Grid = wxFlexGridSizer:new(2, 4, 4), ok = wxFlexGridSizer:setFlexibleDirection(Grid, ?wxHORIZONTAL), ok = wxFlexGridSizer:addGrowableCol(Grid, 1), Make = fun({SO, SI, VS, VM}) -> LO = [SO, ":"], LI = [SI, ":"], T_LO = wxStaticText:new(Parent, ?wxID_ANY, LO), T_CO = wxStaticText:new(Parent, ?wxID_ANY, VS, [{style, ?wxALIGN_LEFT}]), T_LI = wxStaticText:new(Parent, ?wxID_ANY, LI), T_CI = wxTextCtrl:new(Parent, ?wxID_ANY, [{value, VM}]), _ = wxFlexGridSizer:add(Grid, T_LO, center()), _ = wxFlexGridSizer:add(Grid, T_CO, center()), _ = wxFlexGridSizer:add(Grid, T_LI, center()), _ = wxFlexGridSizer:add(Grid, T_CI, zxw:flags(wide)), T_CI end, Controls = lists:map(Make, Labels), {Grid, Controls}. handle_call(Unexpected, From, State) -> ok = log(warning, "Unexpected call from ~tp: ~tp~n", [From, Unexpected]), {noreply, State}. handle_cast(to_front, State = #s{frame = Frame}) -> ok = wxFrame:raise(Frame), {noreply, State}; handle_cast({trouble, Info}, State) -> ok = handle_troubling(State, Info), {noreply, State}; handle_cast(Unexpected, State) -> ok = log(warning, "Unexpected cast: ~tp~n", [Unexpected]), {noreply, State}. handle_info(Unexpected, State) -> ok = log(warning, "Unexpected info: ~tp~n", [Unexpected]), {noreply, State}. handle_event(#wx{event = #wxCommand{type = command_button_clicked}, id = ID}, State) -> ok = case ID of ?wxID_OK -> done(State); ?wxID_CANCEL -> buh_bye(State) end, {noreply, State}; handle_event(#wx{event = #wxClose{}}, State) -> ok = buh_bye(State), {noreply, State}; handle_event(Event, State) -> ok = tell(info, "Unexpected event ~tp State: ~tp~n", [Event, State]), {noreply, State}. handle_troubling(#s{frame = Frame}, Info) -> zxw:show_message(Frame, Info). code_change(_, State, _) -> {ok, State}. terminate(Reason, State) -> ok = log(info, "Reason: ~tp, State: ~tp", [Reason, State]), wx:destroy(). buh_bye(#s{frame = Frame}) -> wxWindow:destroy(Frame). %%% Doers done(State = #s{net = Network, acc = AccTx, keys = KeysTx, cores = CoresTx, memory = MemTx}) -> Net = case wxRadioBox:getSelection(Network) of 0 -> <<"mainnet">>; 1 -> <<"testnet">>; _ -> <<"mainnet">> end, AccID = wxTextCtrl:getValue(AccTx), MOAR_IDs = wxTextCtrl:getValue(KeysTx), CoreS = wxTextCtrl:getValue(CoresTx), GigsS = wxTextCtrl:getValue(MemTx), ok = gmc_con:conf({Net, list_to_binary(AccID), binify_keys(MOAR_IDs), cores(CoreS), bytes(GigsS)}), buh_bye(State). cores("") -> none; cores(CoreS) -> try list_to_integer(CoreS) catch _:_ -> none end. bytes("") -> none; bytes(GigsS) -> try list_to_integer(GigsS) * gig() catch _:_ -> try trunc(list_to_float(GigsS) * gig()) catch _:_ -> none end end. % NOTE: 32 is space, 12288 is full-width space. binify_keys(MOAR) -> [list_to_binary(K) || K <- string:lexemes(MOAR, [$\r, $\n, 32, 12288, $\t, $,, $;])]. acc(none) -> ""; acc(AKID) -> AKID. keys(List) -> unicode:characters_to_list(lists:join("\n", List)). net_num(<<"mainnet">>) -> 0; net_num(<<"testnet">>) -> 1; net_num(_) -> 0.