diff --git a/src/gd_v_call.erl b/src/gd_v_call.erl new file mode 100644 index 0000000..a051678 --- /dev/null +++ b/src/gd_v_call.erl @@ -0,0 +1,226 @@ +-module(gd_v_devman). +-vsn("0.8.1"). +-author("Craig Everett "). +-copyright("QPQ AG "). +-license("GPL-3.0-or-later"). + +-behavior(wx_object). +%-behavior(gd_v). +-include_lib("wx/include/wx.hrl"). +-export([to_front/1]). +% -export([]). +-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"). +-include("gd.hrl"). + + +% Widgets +-record(w, + {name = none :: atom() | {FunName :: binary(), call | dryr}, + id = 0 :: integer(), + wx = none :: none | wx:wx_object()}). + +% State +-record(s, + {wx = none :: none | wx:wx_object(), + frame = none :: none | wx:wx_object(), + lang = en :: en | jp, + j = none :: none | fun(), + args = [] :: [#wx{}], + ttl = #wx{} :: #wx{}, + gasprice = #wx{} :: #wx{}, + gas = #wx{} :: #wx{}, + amount = #wx{} :: #wx{}, + retry = #wx{} :: #wx{}, + copy = #wx{} :: #wx{}, + done = #wx{} :: #wx{}}). + + + +%%% Startup Functions + +start_link(Args) -> + wx_object:start_link({local, ?MODULE}, ?MODULE, Args, []). + + +init({Prefs, {FunName, FunType}, ConID, AACI}) -> + {aaci, ConName, FunSpecs, _} = AACI, + FunSpec = maps:get(FunName, FunSpecs), + CallType = + case FunType of + call -> J("Contract Call"); + dryr -> J("Dry Run") + end, + Title = [CallType, ": ", ConName, ".", FunName, "/", integer_to_list(length(element(1, FunSpec)))], + Lang = maps:get(lang, Prefs, en_us), + Trans = gd_jt:read_translations(?MODULE), + J = gd_jt:j(Lang, Trans), + Wx = wx:new(), + Frame = wxFrame:new(Wx, ?wxID_ANY, Title), + + {ArgSz, Args} = call_arg_sizer(Frame, J, FunSpec), + {ParamSz, TTL_T, GasPriceT, GasT, AmountT} = call_param_sizer(Frame, J), + + _ = wxFrame:setSizer(Frame, MainSz), + _ = wxSizer:layout(MainSz), + ok = gd_v:safe_size(Frame, Prefs), + ok = wxFrame:connect(Frame, close_window), + ok = wxFrame:connect(Frame, command_button_clicked), +% TODO: Decide where to put the frame -- should probably be slightly randomized. +% ok = wxFrame:center(Frame), + true = wxFrame:show(Frame), + State = + #s{wx = Wx, frame = Frame, j = J, prefs = Prefs, + args = Args, + ttl = TTL_T, gasprice = GasPriceT, gas = GasT, amount = AmountT, + retry = RetryBn, copy = CopyBn, done = DoneBn}, + {Frame, State}. + + +call_arg_sizer(Frame, J, {CallArgs, ReturnType}) -> + SpecSz = wxStaticBoxSizer:new(?wxVERTICAL, Frame, [{label, J("Function Spec")}]), + {CallSz, CallControls, Dimensions} = call_sizer(Frame, J, CallArgs), + ReturnSz = return_sizer(Frame, J, ReturnType), + _ = wxStaticBoxSizer:add(SpecSz, CallSz, zxw:flags({wide, 5})), + _ = wxStaticBoxSizer:add(SpecSz, ReturnSz, zxw:flags({base, 5})), + {SpecSz, CallControls, Dimensions}. + +call_sizer(Frame, J, []) -> + CallSz = wxStaticBoxSizer:new(?wxVERTICAL, Frame, [{label, J("Call Args")}]), + Args = wxStaticText:new(Frame, ?wxID_ANY, ["[", J("No Args"), "]"]), + _ = wxStaticBoxSizer:add(CallSz, Args, zxw:flags({wide, 5})), + {CallSz, [], {500, 500}}; +call_sizer(Frame, J, CallArgs) -> + ScrollWin = wxScrolledWindow:new(Frame), + ScrollSz = wxBoxSizer:new(?wxVERTICAL), + ok = wxScrolledWindow:setSizerAndFit(ScrollWin, ScrollSz), + ok = wxScrolledWindow:setScrollRate(ScrollWin, 5, 5), + CallSz = wxStaticBoxSizer:new(?wxVERTICAL, Frame, [{label, J("Call Args")}]), + GridSz = wxFlexGridSizer:new(2, [{gap, {4, 4}}]), + ok = wxFlexGridSizer:setFlexibleDirection(GridSz, ?wxHORIZONTAL), + ok = wxFlexGridSizer:addGrowableCol(GridSz, 1), + AddArg = + fun({Name, Type}) -> + L = wxStaticText:new(ScrollWin, ?wxID_ANY, [Name, " : ", textify(Type)]), + C = wxTextCtrl:new(ScrollWin, ?wxID_ANY), + _ = wxFlexGridSizer:add(GridSz, L, zxw:flags({base, 5})), + _ = wxFlexGridSizer:add(GridSz, C, zxw:flags({wide, 5})), + {Name, C} + end, + _ = wxStaticBoxSizer:add(ScrollSz, GridSz, zxw:flags(wide)), + _ = wxStaticBoxSizer:add(CallSz, ScrollWin, zxw:flags(wide)), + Controls = lists:map(AddArg, CallArgs), + {CallSz, Controls, {600, 700}}. + +return_sizer(Frame, J, ReturnType) -> + ReturnSz = wxStaticBoxSizer:new(?wxVERTICAL, Frame, [{label, J("Return Type")}]), + Return = wxStaticText:new(Frame, ?wxID_ANY, textify(ReturnType)), + _ = wxStaticBoxSizer:add(ReturnSz, Return, zxw:flags({wide, 5})), + ReturnSz. + + +call_param_sizer(Frame, J) -> + {ok, Height} = hz:top_height(), + DefTTL = Height + 10000, + DefGasP = hz:min_gas_price(), + DefGas = 5000000, + DefAmount = 0, + ParamSz = wxStaticBoxSizer:new(?wxVERTICAL, Frame, [{label, J("TX Parameters")}]), + GridSz = wxFlexGridSizer:new(2, 4, 4), + ok = wxFlexGridSizer:setFlexibleDirection(GridSz, ?wxHORIZONTAL), + ok = wxFlexGridSizer:addGrowableCol(GridSz, 1), + TTL_L = wxStaticText:new(Frame, ?wxID_ANY, "TTL"), + TTL_Tx = wxTextCtrl:new(Frame, ?wxID_ANY), + ok = wxTextCtrl:setValue(TTL_Tx, integer_to_list(DefTTL)), + GasP_L = wxStaticText:new(Frame, ?wxID_ANY, J("Gas Price")), + GasP_Tx = wxTextCtrl:new(Frame, ?wxID_ANY), + ok = wxTextCtrl:setValue(GasP_Tx, integer_to_list(DefGasP)), + Gas_L = wxStaticText:new(Frame, ?wxID_ANY, J("Gas")), + Gas_Tx = wxTextCtrl:new(Frame, ?wxID_ANY), + ok = wxTextCtrl:setValue(Gas_Tx, integer_to_list(DefGas)), + Amount_L = wxStaticText:new(Frame, ?wxID_ANY, J("TX Amount")), + Amount_Tx = wxTextCtrl:new(Frame, ?wxID_ANY), + ok = wxTextCtrl:setValue(Amount_Tx, integer_to_list(DefAmount)), + _ = wxFlexGridSizer:add(GridSz, TTL_L, zxw:flags({base, 5})), + _ = wxFlexGridSizer:add(GridSz, TTL_Tx, zxw:flags({wide, 5})), + _ = wxFlexGridSizer:add(GridSz, GasP_L, zxw:flags({base, 5})), + _ = wxFlexGridSizer:add(GridSz, GasP_Tx, zxw:flags({wide, 5})), + _ = wxFlexGridSizer:add(GridSz, Gas_L, zxw:flags({base, 5})), + _ = wxFlexGridSizer:add(GridSz, Gas_Tx, zxw:flags({wide, 5})), + _ = wxFlexGridSizer:add(GridSz, Amount_L, zxw:flags({base, 5})), + _ = wxFlexGridSizer:add(GridSz, Amount_Tx, zxw:flags({wide, 5})), + _ = wxSizer:add(ParamSz, GridSz, zxw:flags(wide)), + {ParamSz, TTL_Tx, GasP_Tx, Gas_Tx, Amount_Tx}. + + + +textify({integer, _, _}) -> "int"; +textify({boolean, _, _}) -> "bool"; +textify({{bytes, [I]}, _, _}) -> io_lib:format("bytes(~w)", [I]); +textify({{bytes, any}, _, _}) -> "bytes()"; +textify({T, _, _}) when is_atom(T) -> atom_to_list(T); +textify({T, _, _}) when is_list(T) -> T; +textify({T, _, _}) -> io_lib:format("~tp", [T]). + + +extract_args(Controls) -> + extract_args(Controls, []). + +extract_args([], Acc) -> + pack_args(Acc); +extract_args([{Name, Control} | T], Acc) -> + String = wxTextCtrl:getValue(Control), + extract_args(T, [{Name, String} | Acc]). + +pack_args(Args) -> + pack_args(Args, [], []). + +pack_args([], M, A) -> + Message = unicode:characters_to_list(["Call Args:\n", M]), + {Message, A}; +pack_args([{N, S} | T], M, A) -> + pack_args(T, [[N, ": ", S, "\n"] | M], [S | A]). + +call_params(Controls) -> + call_params(Controls, {[], []}). + +call_params([], {Acc, []}) -> + {ok, lists:reverse(Acc)}; +call_params([], {_, Errors}) -> + {error, lists:reverse(Errors)}; +call_params([{{Label, Validate}, Control} | T], {Acc, Errors}) -> + String = wxTextCtrl:getValue(Control), + case Validate(String) of + {ok, Value} -> call_params(T, {[Value | Acc], Errors}); + {error, Reason} -> call_params(T, {Acc, [{Label, Reason} | Errors]}) + end. + +gt_0(S) -> + C = "Must be an integer greater than 0", + R = + try + {ok, list_to_integer(S)} + catch + error:badarg -> {error, {S, C}} + end, + case R of + {ok, N} when N > 0 -> {ok, N}; + {ok, N} when N =< 0 -> {error, {S, C}}; + Error -> Error + end. + +gte_0(S) -> + C = "Must be a non-negative integer.", + R = + try + {ok, list_to_integer(S)} + catch + error:badarg -> {error, {S, C}} + end, + case R of + {ok, N} when N >= 0 -> {ok, N}; + {ok, N} when N < 0 -> {error, {S, C}}; + Error -> Error + end. diff --git a/src/gd_v_devman.erl b/src/gd_v_devman.erl index caac3ba..9d08e37 100644 --- a/src/gd_v_devman.erl +++ b/src/gd_v_devman.erl @@ -322,7 +322,9 @@ clicked(State = #s{cons = {Consbook, Contracts}}, Name) -> ok = tell(warning, "Inconcievable! No notebook page is selected!"), State; Index -> - Contract = lists:nth(Index + 1, Contracts), + #c{id = ConID, build = #{aaci := AACI}} = lists:nth(Index + 1, Contracts), + + clicked2(State, Contract, Name) end. @@ -337,8 +339,10 @@ clicked2(State, Contract, Name) -> end. clicked3(State = #s{frame = Frame, j = J}, Contract, Name = {FunName, FunType}, Selected, Keys) -> - {FunName, FunType} = Name, #c{id = ConID, build = #{aaci := AACI}} = Contract, + {FunDef, ConID, AACI} + + {aaci, ConName, FunSpecs, _} = AACI, FunSpec = maps:get(FunName, FunSpecs), tell("FunName: ~tp", [FunName]), @@ -400,149 +404,6 @@ clicked3(State = #s{frame = Frame, j = J}, Contract, Name = {FunName, FunType}, Error -> handle_troubling(State, Error) end. -extract_args(Controls) -> - extract_args(Controls, []). - -extract_args([], Acc) -> - pack_args(Acc); -extract_args([{Name, Control} | T], Acc) -> - String = wxTextCtrl:getValue(Control), - extract_args(T, [{Name, String} | Acc]). - -pack_args(Args) -> - pack_args(Args, [], []). - -pack_args([], M, A) -> - Message = unicode:characters_to_list(["Call Args:\n", M]), - {Message, A}; -pack_args([{N, S} | T], M, A) -> - pack_args(T, [[N, ": ", S, "\n"] | M], [S | A]). - - -call_arg_sizer(Dialog, J, {CallArgs, ReturnType}) -> - SpecSz = wxStaticBoxSizer:new(?wxVERTICAL, Dialog, [{label, J("Function Spec")}]), - {CallSz, CallControls, Dimensions} = call_sizer(Dialog, J, CallArgs), - ReturnSz = return_sizer(Dialog, J, ReturnType), - _ = wxStaticBoxSizer:add(SpecSz, CallSz, zxw:flags({wide, 5})), - _ = wxStaticBoxSizer:add(SpecSz, ReturnSz, zxw:flags({base, 5})), - {SpecSz, CallControls, Dimensions}. - -call_sizer(Dialog, J, []) -> - CallSz = wxStaticBoxSizer:new(?wxVERTICAL, Dialog, [{label, J("Call Args")}]), - Args = wxStaticText:new(Dialog, ?wxID_ANY, ["[", J("No Args"), "]"]), - _ = wxStaticBoxSizer:add(CallSz, Args, zxw:flags({wide, 5})), - {CallSz, [], {500, 500}}; -call_sizer(Dialog, J, CallArgs) -> - ScrollWin = wxScrolledWindow:new(Dialog), - ScrollSz = wxBoxSizer:new(?wxVERTICAL), - ok = wxScrolledWindow:setSizerAndFit(ScrollWin, ScrollSz), - ok = wxScrolledWindow:setScrollRate(ScrollWin, 5, 5), - CallSz = wxStaticBoxSizer:new(?wxVERTICAL, Dialog, [{label, J("Call Args")}]), - GridSz = wxFlexGridSizer:new(2, [{gap, {4, 4}}]), - ok = wxFlexGridSizer:setFlexibleDirection(GridSz, ?wxHORIZONTAL), - ok = wxFlexGridSizer:addGrowableCol(GridSz, 1), - AddArg = - fun({Name, Type}) -> - L = wxStaticText:new(ScrollWin, ?wxID_ANY, [Name, " : ", textify(Type)]), - C = wxTextCtrl:new(ScrollWin, ?wxID_ANY), - _ = wxFlexGridSizer:add(GridSz, L, zxw:flags({base, 5})), - _ = wxFlexGridSizer:add(GridSz, C, zxw:flags({wide, 5})), - {Name, C} - end, - _ = wxStaticBoxSizer:add(ScrollSz, GridSz, zxw:flags(wide)), - _ = wxStaticBoxSizer:add(CallSz, ScrollWin, zxw:flags(wide)), - Controls = lists:map(AddArg, CallArgs), - {CallSz, Controls, {600, 700}}. - -return_sizer(Dialog, J, ReturnType) -> - ReturnSz = wxStaticBoxSizer:new(?wxVERTICAL, Dialog, [{label, J("Return Type")}]), - Return = wxStaticText:new(Dialog, ?wxID_ANY, textify(ReturnType)), - _ = wxStaticBoxSizer:add(ReturnSz, Return, zxw:flags({wide, 5})), - ReturnSz. - -textify({integer, _, _}) -> "int"; -textify({boolean, _, _}) -> "bool"; -textify({{bytes, [I]}, _, _}) -> io_lib:format("bytes(~w)", [I]); -textify({{bytes, any}, _, _}) -> "bytes()"; -textify({T, _, _}) when is_atom(T) -> atom_to_list(T); -textify({T, _, _}) when is_list(T) -> T; -textify({T, _, _}) -> io_lib:format("~tp", [T]). - - -call_param_sizer(Dialog, J) -> - {ok, Height} = hz:top_height(), - DefTTL = Height + 10000, - DefGasP = hz:min_gas_price(), - DefGas = 5000000, - DefAmount = 0, - ParamSz = wxStaticBoxSizer:new(?wxVERTICAL, Dialog, [{label, J("TX Parameters")}]), - GridSz = wxFlexGridSizer:new(2, 4, 4), - ok = wxFlexGridSizer:setFlexibleDirection(GridSz, ?wxHORIZONTAL), - ok = wxFlexGridSizer:addGrowableCol(GridSz, 1), - TTL_L = wxStaticText:new(Dialog, ?wxID_ANY, "TTL"), - TTL_Tx = wxTextCtrl:new(Dialog, ?wxID_ANY), - ok = wxTextCtrl:setValue(TTL_Tx, integer_to_list(DefTTL)), - GasP_L = wxStaticText:new(Dialog, ?wxID_ANY, J("Gas Price")), - GasP_Tx = wxTextCtrl:new(Dialog, ?wxID_ANY), - ok = wxTextCtrl:setValue(GasP_Tx, integer_to_list(DefGasP)), - Gas_L = wxStaticText:new(Dialog, ?wxID_ANY, J("Gas")), - Gas_Tx = wxTextCtrl:new(Dialog, ?wxID_ANY), - ok = wxTextCtrl:setValue(Gas_Tx, integer_to_list(DefGas)), - Amount_L = wxStaticText:new(Dialog, ?wxID_ANY, J("TX Amount")), - Amount_Tx = wxTextCtrl:new(Dialog, ?wxID_ANY), - ok = wxTextCtrl:setValue(Amount_Tx, integer_to_list(DefAmount)), - _ = wxFlexGridSizer:add(GridSz, TTL_L, zxw:flags({base, 5})), - _ = wxFlexGridSizer:add(GridSz, TTL_Tx, zxw:flags({wide, 5})), - _ = wxFlexGridSizer:add(GridSz, GasP_L, zxw:flags({base, 5})), - _ = wxFlexGridSizer:add(GridSz, GasP_Tx, zxw:flags({wide, 5})), - _ = wxFlexGridSizer:add(GridSz, Gas_L, zxw:flags({base, 5})), - _ = wxFlexGridSizer:add(GridSz, Gas_Tx, zxw:flags({wide, 5})), - _ = wxFlexGridSizer:add(GridSz, Amount_L, zxw:flags({base, 5})), - _ = wxFlexGridSizer:add(GridSz, Amount_Tx, zxw:flags({wide, 5})), - _ = wxSizer:add(ParamSz, GridSz, zxw:flags(wide)), - {ParamSz, TTL_Tx, GasP_Tx, Gas_Tx, Amount_Tx}. - -call_params(Controls) -> - call_params(Controls, {[], []}). - -call_params([], {Acc, []}) -> - {ok, lists:reverse(Acc)}; -call_params([], {_, Errors}) -> - {error, lists:reverse(Errors)}; -call_params([{{Label, Validate}, Control} | T], {Acc, Errors}) -> - String = wxTextCtrl:getValue(Control), - case Validate(String) of - {ok, Value} -> call_params(T, {[Value | Acc], Errors}); - {error, Reason} -> call_params(T, {Acc, [{Label, Reason} | Errors]}) - end. - -gt_0(S) -> - C = "Must be an integer greater than 0", - R = - try - {ok, list_to_integer(S)} - catch - error:badarg -> {error, {S, C}} - end, - case R of - {ok, N} when N > 0 -> {ok, N}; - {ok, N} when N =< 0 -> {error, {S, C}}; - Error -> Error - end. - -gte_0(S) -> - C = "Must be a non-negative integer.", - R = - try - {ok, list_to_integer(S)} - catch - error:badarg -> {error, {S, C}} - end, - case R of - {ok, N} when N >= 0 -> {ok, N}; - {ok, N} when N < 0 -> {error, {S, C}}; - Error -> Error - end. clicked4(State, #c{id = ConID, build = #{aaci := AACI}}, @@ -785,7 +646,6 @@ deploy4(State = #s{frame = Frame, j = J}, InitSpec, Build, Selected, Keys) -> end. deploy5(State, Build, Params, Args) -> - tell(info, "Build: ~p", [Build]), ok = gd_con:deploy(Build, Params, Args), State. @@ -952,7 +812,7 @@ save(State = #s{prefs = Prefs, code = {Codebook, Pages}}) -> Index -> case lists:nth(Index + 1, Pages) of #p{path = {file, Path}, code = Widget} -> - Source = wxStyledTextCtrl:getText(Widget), + Source = gd_sophia_editor:get_text(Widget), case filelib:ensure_dir(Path) of ok -> case file:write_file(Path, Source) of