WIP: Adding Sophia developer interface
This commit is contained in:
parent
fd85edd4f3
commit
e7670411b0
@ -49,7 +49,8 @@
|
||||
|
||||
-type state() :: #s{}.
|
||||
-type ui_name() :: gmc_v_netman
|
||||
| gmc_v_wallman.
|
||||
| gmc_v_wallman
|
||||
| gmc_v_devman.
|
||||
|
||||
|
||||
|
||||
@ -451,7 +452,9 @@ task_data(gmc_v_netman, #s{wallet = #wallet{nets = Nets}}) ->
|
||||
task_data(gmc_v_netman, #s{wallet = none}) ->
|
||||
[];
|
||||
task_data(gmc_v_wallman, #s{wallets = Wallets}) ->
|
||||
Wallets.
|
||||
Wallets;
|
||||
task_data(gmc_v_devman, #s{}) ->
|
||||
[].
|
||||
|
||||
|
||||
|
||||
|
@ -6,7 +6,7 @@
|
||||
%%% Version 1 of the protocol consists of two verbs with two contexts each, collapsed to
|
||||
%%% four symbols for brevity.
|
||||
%%%
|
||||
%%% The GRIDS schema begins with "grids://" or "grids://"
|
||||
%%% The GRIDS schema begins with "grids://" or "grid://"
|
||||
%%% Which way this is interpreted can vary depending on the verb.
|
||||
%%%
|
||||
%%% The typical "host" component is either an actual hostname or address and an optional
|
||||
@ -78,12 +78,6 @@ parse(URL) ->
|
||||
U = #{path := "/1/d/" ++ L, scheme := "grid"} ->
|
||||
NewURL = uri_string:recompose(U#{scheme := "http", path := L}),
|
||||
{ok, {{sign, http}, NewURL}};
|
||||
U = #{path := "/1/v/" ++ L, scheme := "grids"} ->
|
||||
NewURL = uri_string:recompose(U#{scheme := "https", path := L}),
|
||||
{ok ,{{mess, https}, NewURL}};
|
||||
U = #{path := "/1/v/" ++ L, scheme := "grid"} ->
|
||||
NewURL = uri_string:recompose(U#{scheme := "http", path := L}),
|
||||
{ok, {{mess, http}, NewURL}};
|
||||
{error, Reason, Info} ->
|
||||
ok = tell("URL parsing failed with ~w: ~p", [Reason, Info]),
|
||||
{error, bad_url};
|
||||
|
@ -92,12 +92,14 @@ init(Prefs) ->
|
||||
MainSz = wxBoxSizer:new(?wxVERTICAL),
|
||||
Picker = wxListBox:new(Frame, ?wxID_ANY, [{style, ?wxLC_SINGLE_SEL}]),
|
||||
|
||||
WallB = wxButton:new(Frame, ?wxID_ANY, [{label, "[none]"}, {style, ?wxBORDER_NONE}]),
|
||||
WallW = #w{name = wallet, id = wxButton:getId(WallB), wx = WallB},
|
||||
WallB = wxButton:new(Frame, ?wxID_ANY, [{label, "[none]"}, {style, ?wxBORDER_NONE}]),
|
||||
WallW = #w{name = wallet, id = wxButton:getId(WallB), wx = WallB},
|
||||
ChainB = wxButton:new(Frame, ?wxID_ANY, [{label, "[ChainID]"}, {style, ?wxBORDER_NONE}]),
|
||||
ChainW = #w{name = chain, id = wxButton:getId(ChainB), wx = ChainB},
|
||||
NodeB = wxButton:new(Frame, ?wxID_ANY, [{label, "[Node]"}, {style, ?wxBORDER_NONE}]),
|
||||
NodeW = #w{name = node, id = wxButton:getId(NodeB), wx = NodeB},
|
||||
ChainW = #w{name = chain, id = wxButton:getId(ChainB), wx = ChainB},
|
||||
NodeB = wxButton:new(Frame, ?wxID_ANY, [{label, "[Node]"}, {style, ?wxBORDER_NONE}]),
|
||||
NodeW = #w{name = node, id = wxButton:getId(NodeB), wx = NodeB},
|
||||
DevB = wxButton:new(Frame, ?wxID_ANY, [{label, "𝑓 () →"}]),
|
||||
DevW = #w{name = dev, id = wxButton:getId(DevB), wx = DevB},
|
||||
|
||||
ID_L = wxStaticText:new(Frame, ?wxID_ANY, J("Account ID: ")),
|
||||
ID_T = wxStaticText:new(Frame, ?wxID_ANY, ""),
|
||||
@ -140,7 +142,7 @@ init(Prefs) ->
|
||||
#w{name = Name, id = wxButton:getId(B), wx = B}
|
||||
end,
|
||||
|
||||
Buttons = [WallW, ChainW, NodeW | lists:map(MakeButton, ButtonTemplates)],
|
||||
Buttons = [WallW, ChainW, NodeW, DevW | lists:map(MakeButton, ButtonTemplates)],
|
||||
|
||||
ChainSz = wxBoxSizer:new(?wxHORIZONTAL),
|
||||
AccountSz = wxBoxSizer:new(?wxHORIZONTAL),
|
||||
@ -148,9 +150,10 @@ init(Prefs) ->
|
||||
ActionsSz = wxBoxSizer:new(?wxHORIZONTAL),
|
||||
HistorySz = wxBoxSizer:new(?wxVERTICAL),
|
||||
|
||||
_ = wxSizer:add(ChainSz, WallB, zxw:flags(wide)),
|
||||
_ = wxSizer:add(ChainSz, WallB, zxw:flags(wide)),
|
||||
_ = wxSizer:add(ChainSz, ChainB, zxw:flags(wide)),
|
||||
_ = wxSizer:add(ChainSz, NodeB, zxw:flags(wide)),
|
||||
_ = wxSizer:add(ChainSz, NodeB, zxw:flags(wide)),
|
||||
_ = wxSizer:add(ChainSz, DevB, zxw:flags(base)),
|
||||
|
||||
#w{wx = CopyBn} = lists:keyfind(copy, #w.name, Buttons),
|
||||
#w{wx = WWW_Bn} = lists:keyfind(www, #w.name, Buttons),
|
||||
@ -277,6 +280,7 @@ handle_event(#wx{event = #wxCommand{type = command_button_clicked},
|
||||
case lists:keyfind(ID, #w.id, Buttons) of
|
||||
#w{name = wallet} -> wallman(State);
|
||||
#w{name = chain} -> netman(State);
|
||||
#w{name = dev} -> devman(State);
|
||||
#w{name = node} -> set_node(State);
|
||||
#w{name = make_key} -> make_key(State);
|
||||
#w{name = recover} -> recover_key(State);
|
||||
@ -345,6 +349,12 @@ netman(State) ->
|
||||
ok = gmc_con:show_ui(gmc_v_netman),
|
||||
State.
|
||||
|
||||
|
||||
devman(State) ->
|
||||
ok = gmc_con:show_ui(gmc_v_devman),
|
||||
State.
|
||||
|
||||
|
||||
set_node(State = #s{frame = Frame, j = J}) ->
|
||||
Dialog = wxDialog:new(Frame, ?wxID_ANY, J("Set Node")),
|
||||
Sizer = wxBoxSizer:new(?wxVERTICAL),
|
||||
|
551
src/gmc_v_devman.erl
Normal file
551
src/gmc_v_devman.erl
Normal file
@ -0,0 +1,551 @@
|
||||
-module(gmc_v_devman).
|
||||
-vsn("0.1.4").
|
||||
-author("Craig Everett <zxq9@zxq9.com>").
|
||||
-copyright("QPQ AG <info@qpq.swiss>").
|
||||
-license("GPL-3.0-or-later").
|
||||
|
||||
-behavior(wx_object).
|
||||
%-behavior(gmc_v).
|
||||
-include_lib("wx/include/wx.hrl").
|
||||
-export([to_front/1]).
|
||||
-export([set_manifest/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").
|
||||
-include("gmc.hrl").
|
||||
|
||||
|
||||
-record(w,
|
||||
{name = none :: atom() | {FunName :: binary(), call | dryr},
|
||||
id = 0 :: integer(),
|
||||
wx = none :: none | wx:wx_object()}).
|
||||
|
||||
-record(f,
|
||||
{name = <<"">> :: binary(),
|
||||
call = #w{} :: #w{},
|
||||
dryrun = #w{} :: none | #w{},
|
||||
args = [] :: [{wx:wx_object(), wx:wx_object(), argt()}]}).
|
||||
|
||||
-record(p,
|
||||
{path = "" :: file:filename(),
|
||||
win = none :: none | wx:wx_object(),
|
||||
code = none :: none | wxStyledTextCtrl:wxStyledTextCtrl(),
|
||||
cons = none :: none | wxStyledTextCtrl:wxStyledTextCtrl(),
|
||||
side_sz = none :: none | wx:wx_object(),
|
||||
instances = none :: none | wx:wx_object(),
|
||||
funs = {#w{}, []} :: {#w{}, [#f{}]},
|
||||
builds = #{} :: #{InstanceID :: binary() := Build :: map()}}).
|
||||
|
||||
-record(s,
|
||||
{wx = none :: none | wx:wx_object(),
|
||||
frame = none :: none | wx:wx_object(),
|
||||
lang = en :: en | jp,
|
||||
j = none :: none | fun(),
|
||||
prefs = #{} :: map(),
|
||||
buttons = #{} :: #{WX_ID :: integer() := #w{}},
|
||||
book = {none, []} :: {Notebook :: none | wx:wx_object(), Pages :: [#p{}]}}).
|
||||
|
||||
-type argt() :: int | string | address | list(argt()).
|
||||
|
||||
%%% Interface
|
||||
|
||||
-spec to_front(Win) -> ok
|
||||
when Win :: wx:wx_object().
|
||||
|
||||
to_front(Win) ->
|
||||
wx_object:cast(Win, to_front).
|
||||
|
||||
|
||||
-spec set_manifest(Entries) -> ok
|
||||
when Entries :: [ael:conf_meta()].
|
||||
|
||||
set_manifest(Entries) ->
|
||||
case is_pid(whereis(?MODULE)) of
|
||||
true -> wx_object:cast(?MODULE, {set_manifest, Entries});
|
||||
false -> ok
|
||||
end.
|
||||
|
||||
|
||||
|
||||
|
||||
%%% Startup Functions
|
||||
|
||||
start_link(Args) ->
|
||||
wx_object:start_link({local, ?MODULE}, ?MODULE, Args, []).
|
||||
|
||||
|
||||
init({Prefs, Manifest}) ->
|
||||
Lang = maps:get(lang, Prefs, en_us),
|
||||
Trans = gmc_jt:read_translations(?MODULE),
|
||||
J = gmc_jt:j(Lang, Trans),
|
||||
Wx = wx:new(),
|
||||
Frame = wxFrame:new(Wx, ?wxID_ANY, J("Contracts")),
|
||||
|
||||
MainSz = wxBoxSizer:new(?wxVERTICAL),
|
||||
ButtSz = wxBoxSizer:new(?wxHORIZONTAL),
|
||||
|
||||
ButtonTemplates =
|
||||
[{new, J("New")},
|
||||
{open, J("Open")},
|
||||
{save, J("Save")},
|
||||
{saven, J("Save (new name)")},
|
||||
{compile, J("Compile")},
|
||||
{close, J("Close")}],
|
||||
|
||||
MakeButton =
|
||||
fun({Name, Label}) ->
|
||||
B = wxButton:new(Frame, ?wxID_ANY, [{label, Label}]),
|
||||
#w{name = Name, id = wxButton:getId(B), wx = B}
|
||||
end,
|
||||
|
||||
Buttons = lists:map(MakeButton, ButtonTemplates),
|
||||
|
||||
AddButton = fun(#w{wx = B}) -> wxSizer:add(ButtSz, B, zxw:flags(wide)) end,
|
||||
|
||||
Notebook = wxNotebook:new(Frame, ?wxID_ANY, [{style, ?wxBK_DEFAULT}]),
|
||||
|
||||
ok = lists:foreach(AddButton, Buttons),
|
||||
_ = wxSizer:add(MainSz, ButtSz, zxw:flags(base)),
|
||||
_ = wxSizer:add(MainSz, Notebook, zxw:flags(wide)),
|
||||
_ = wxFrame:setSizer(Frame, MainSz),
|
||||
_ = wxSizer:layout(MainSz),
|
||||
|
||||
ok = gmc_v:safe_size(Frame, Prefs),
|
||||
|
||||
ok = wxFrame:connect(Frame, close_window),
|
||||
ok = wxFrame:connect(Frame, command_button_clicked),
|
||||
ok = wxFrame:center(Frame),
|
||||
true = wxFrame:show(Frame),
|
||||
|
||||
MapButton = fun(B = #w{id = I}, M) -> maps:put(I, B, M) end,
|
||||
ButtonMap = lists:foldl(MapButton, #{}, Buttons),
|
||||
State =
|
||||
#s{wx = Wx, frame = Frame,
|
||||
j = J, prefs = Prefs,
|
||||
buttons = ButtonMap, book = {Notebook, []}},
|
||||
NewState = add_pages(State, Manifest),
|
||||
{Frame, NewState}.
|
||||
|
||||
|
||||
add_pages(State, Files) ->
|
||||
lists:foldl(fun add_page/2, State, Files).
|
||||
|
||||
add_page(State = #s{book = {Notebook, Pages}}, File) ->
|
||||
case keyfind_index(File, #p.path, Pages) of
|
||||
error ->
|
||||
add_page2(State, File);
|
||||
{ok, Index} ->
|
||||
_ = wxNotebook:setSelection(Notebook, Index - 1),
|
||||
State
|
||||
end.
|
||||
|
||||
add_page2(State = #s{j = J}, File) ->
|
||||
case file:read_file(File) of
|
||||
{ok, Bin} ->
|
||||
case unicode:characters_to_list(Bin) of
|
||||
Code when is_list(Code) ->
|
||||
add_page(State, File, Code);
|
||||
Error ->
|
||||
Message = io_lib:format(J("Opening ~p failed with: ~p"), [File, Error]),
|
||||
ok = gmc_gui:trouble(Message),
|
||||
State
|
||||
end;
|
||||
{error, Reason} ->
|
||||
Message = io_lib:format(J("Opening ~p failed with: ~p"), [File, Reason]),
|
||||
ok = gmc_gui:trouble(Message),
|
||||
State
|
||||
end.
|
||||
|
||||
add_page(State = #s{j = J, book = {Notebook, Pages}}, File, Code) ->
|
||||
% FIXME: One of these days we need to define the text area as a wxStyledTextCtrl and will
|
||||
% have to contend with system theme issues (light/dark themese, namely)
|
||||
% Leaving this little thing here to remind myself how any of that works later.
|
||||
% The call below returns a wx_color4() type (not that we need alpha...).
|
||||
% Color = wxSystemSettings:getColour(?wxSYS_COLOUR_WINDOW),
|
||||
% tell("Color: ~p", [Color]),
|
||||
Window = wxWindow:new(Notebook, ?wxID_ANY),
|
||||
PageSz = wxBoxSizer:new(?wxHORIZONTAL),
|
||||
|
||||
ProgSz = wxBoxSizer:new(?wxVERTICAL),
|
||||
CodeSz = wxStaticBoxSizer:new(?wxVERTICAL, Window, [{label, J("Code")}]),
|
||||
ConsSz = wxStaticBoxSizer:new(?wxVERTICAL, Window, [{label, J("Console")}]),
|
||||
CodeTxStyle = {style, ?wxTE_MULTILINE bor ?wxTE_PROCESS_TAB bor ?wxTE_DONTWRAP},
|
||||
CodeTx = wxTextCtrl:new(Window, ?wxID_ANY, [CodeTxStyle]),
|
||||
ConsTxStyle = {style, ?wxTE_MULTILINE bor ?wxTE_READONLY},
|
||||
ConsTx = wxTextCtrl:new(Window, ?wxID_ANY, [ConsTxStyle]),
|
||||
Mono = wxFont:new(10, ?wxMODERN, ?wxNORMAL, ?wxNORMAL, [{face, "Monospace"}]),
|
||||
TextAt = wxTextAttr:new(),
|
||||
ok = wxTextAttr:setFont(TextAt, Mono),
|
||||
true = wxTextCtrl:setDefaultStyle(CodeTx, TextAt),
|
||||
ok = wxTextCtrl:setValue(CodeTx, Code),
|
||||
|
||||
_ = wxSizer:add(CodeSz, CodeTx, zxw:flags(wide)),
|
||||
_ = wxSizer:add(ConsSz, ConsTx, zxw:flags(wide)),
|
||||
_ = wxSizer:add(ProgSz, CodeSz, [{proportion, 5}, {flag, ?wxEXPAND}]),
|
||||
_ = wxSizer:add(ProgSz, ConsSz, [{proportion, 1}, {flag, ?wxEXPAND}]),
|
||||
|
||||
SideSz = wxBoxSizer:new(?wxVERTICAL),
|
||||
|
||||
InstanceSz = wxStaticBoxSizer:new(?wxVERTICAL, Window, [{label, J("Instances")}]),
|
||||
Instances = wxChoice:new(Window, ?wxID_ANY, [{choices, []}]),
|
||||
_ = wxSizer:add(InstanceSz, Instances, zxw:flags(wide)),
|
||||
|
||||
ScrollWin = wxScrolledWindow:new(Window),
|
||||
FunSz = wxStaticBoxSizer:new(?wxVERTICAL, ScrollWin, [{label, J("Function Interfaces")}]),
|
||||
ok = wxWindow:setSizer(ScrollWin, FunSz),
|
||||
_ = wxSizer:add(SideSz, InstanceSz, zxw:flags(base)),
|
||||
_ = wxSizer:add(SideSz, ScrollWin, zxw:flags(wide)),
|
||||
|
||||
_ = wxSizer:add(PageSz, ProgSz, [{proportion, 2}, {flag, ?wxEXPAND}]),
|
||||
_ = wxSizer:add(PageSz, SideSz, [{proportion, 1}, {flag, ?wxEXPAND}]),
|
||||
|
||||
ok = wxWindow:setSizer(Window, PageSz),
|
||||
ok = wxSizer:layout(PageSz),
|
||||
FileName = filename:basename(File),
|
||||
true = wxNotebook:addPage(Notebook, Window, FileName, [{bSelect, true}]),
|
||||
Page = #p{path = File, win = Window,
|
||||
code = CodeTx, cons = ConsTx,
|
||||
side_sz = SideSz, instances = Instances,
|
||||
funs = {ScrollWin, []}},
|
||||
NewPages = Pages ++ [Page],
|
||||
State#s{book = {Notebook, NewPages}}.
|
||||
|
||||
|
||||
|
||||
%%% OTP callbacks
|
||||
|
||||
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(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(E = #wx{event = #wxCommand{type = command_button_clicked},
|
||||
id = ID},
|
||||
State = #s{buttons = Buttons}) ->
|
||||
NewState =
|
||||
case maps:get(ID, Buttons, undefined) of
|
||||
#w{name = new} -> new_file(State);
|
||||
#w{name = open} -> open_file(State);
|
||||
#w{name = close} -> close_file(State);
|
||||
#w{name = compile} -> compile(State);
|
||||
#w{name = Name} -> clicked(State, Name);
|
||||
undefined ->
|
||||
tell("Received message: ~w", [E]),
|
||||
State
|
||||
end,
|
||||
{noreply, NewState};
|
||||
handle_event(#wx{event = #wxClose{}}, State = #s{frame = Frame, prefs = Prefs}) ->
|
||||
Geometry =
|
||||
case wxTopLevelWindow:isMaximized(Frame) of
|
||||
true ->
|
||||
max;
|
||||
false ->
|
||||
{X, Y} = wxWindow:getPosition(Frame),
|
||||
{W, H} = wxWindow:getSize(Frame),
|
||||
{X, Y, W, H}
|
||||
end,
|
||||
NewPrefs = maps:put(geometry, Geometry, Prefs),
|
||||
ok = gmc_con:save(?MODULE, NewPrefs),
|
||||
ok = wxWindow:destroy(Frame),
|
||||
{noreply, State};
|
||||
handle_event(Event, State) ->
|
||||
ok = tell(info, "Unexpected event ~tp State: ~tp~n", [Event, State]),
|
||||
{noreply, State}.
|
||||
|
||||
|
||||
code_change(_, State, _) ->
|
||||
{ok, State}.
|
||||
|
||||
|
||||
terminate(Reason, State) ->
|
||||
ok = log(info, "Reason: ~tp, State: ~tp", [Reason, State]),
|
||||
wx:destroy().
|
||||
|
||||
|
||||
|
||||
%%% Doers
|
||||
|
||||
clicked(State = #s{book = {Notebook, Pages}}, Name) ->
|
||||
case wxNotebook:getSelection(Notebook) of
|
||||
?wxNOT_FOUND ->
|
||||
State;
|
||||
Index ->
|
||||
Page = lists:nth(Index + 1, Pages),
|
||||
clicked(State, Page, Name)
|
||||
end.
|
||||
|
||||
clicked(State, #p{instances = Is, funs = {_, Funs}, builds = Builds}, {<<"init">>, call}) ->
|
||||
BuildLabel = wxChoice:getStringSelection(Is),
|
||||
Build = maps:get(BuildLabel, Builds),
|
||||
#f{args = Args} = lists:keyfind(<<"init">>, #f.name, Funs),
|
||||
InitArgs = lists:map(fun get_arg/1, Args),
|
||||
ok = tell("BuildLabel: ~p~nArgs: ~p~nInitArgs: ~p", [BuildLabel, Args, InitArgs]),
|
||||
% contract_create_built(
|
||||
State;
|
||||
clicked(State, Page, Name) ->
|
||||
ok = tell("Button: ~p~nPage: ~p", [Name, Page]),
|
||||
State.
|
||||
|
||||
get_arg({_, InputField, _}) ->
|
||||
wxTextCtrl:getValue(InputField).
|
||||
|
||||
|
||||
new_file(State = #s{frame = Frame, j = J, prefs = Prefs}) ->
|
||||
DefaultDir =
|
||||
case maps:find(dir, Prefs) of
|
||||
{ok, PrefDir} ->
|
||||
PrefDir;
|
||||
error ->
|
||||
case os:getenv("ZOMP_DIR") of
|
||||
"" -> file:get_pwd();
|
||||
D -> filename:basename(D)
|
||||
end
|
||||
end,
|
||||
Options =
|
||||
[{message, J("Save Location")},
|
||||
{defaultDir, DefaultDir},
|
||||
{defaultFile, "my_contract.aes"},
|
||||
{wildCard, "*.aes"},
|
||||
{style, ?wxFD_SAVE bor ?wxFD_OVERWRITE_PROMPT}],
|
||||
Dialog = wxFileDialog:new(Frame, Options),
|
||||
NewState =
|
||||
case wxFileDialog:showModal(Dialog) of
|
||||
?wxID_OK ->
|
||||
Dir = wxFileDialog:getDirectory(Dialog),
|
||||
case wxFileDialog:getFilename(Dialog) of
|
||||
"" ->
|
||||
State;
|
||||
Name ->
|
||||
File =
|
||||
case filename:extension(Name) of
|
||||
".aes" -> Name;
|
||||
_ -> Name ++ ".aes"
|
||||
end,
|
||||
Path = filename:join(Dir, File),
|
||||
NewPrefs = maps:put(dir, Dir, Prefs),
|
||||
NextState = State#s{prefs = NewPrefs},
|
||||
add_page(NextState, Path, "")
|
||||
end;
|
||||
?wxID_CANCEL ->
|
||||
State
|
||||
end,
|
||||
ok = wxFileDialog:destroy(Dialog),
|
||||
NewState.
|
||||
|
||||
|
||||
compile(State = #s{book = {Notebook, Pages}}) ->
|
||||
case wxNotebook:getSelection(Notebook) of
|
||||
?wxNOT_FOUND ->
|
||||
State;
|
||||
Index ->
|
||||
Page = #p{code = CodeTx} = lists:nth(Index + 1, Pages),
|
||||
Source = wxTextCtrl:getValue(CodeTx),
|
||||
compile(State, Page, Source)
|
||||
end.
|
||||
|
||||
compile(State = #s{book = {Notebook, Pages}, j = J, buttons = Buttons},
|
||||
Page = #p{path = Path, win = Win, cons = ConsTx,
|
||||
side_sz = SideSz, instances = Instances, funs = Funs, builds = Builds},
|
||||
Source) ->
|
||||
case aeso_compiler:from_string(Source, [{aci, json}]) of
|
||||
{ok, Build = #{aci := ACI}} ->
|
||||
BuildName = build_name(Path),
|
||||
I = wxChoice:append(Instances, BuildName),
|
||||
ok = wxChoice:select(Instances, I),
|
||||
NewBuilds = maps:put(BuildName, Build, Builds),
|
||||
FunDefs = find_main(ACI),
|
||||
UpdateInterfaces = fun() -> fun_interfaces(Win, Buttons, Funs, FunDefs, J) end,
|
||||
{NewButtons, NewFuns} = wx:batch(UpdateInterfaces),
|
||||
ScrollWin = element(1, NewFuns),
|
||||
_ = wxSizer:add(SideSz, ScrollWin, zxw:flags(wide)),
|
||||
ok = wxSizer:layout(SideSz),
|
||||
NewPage = Page#p{funs = NewFuns, builds = NewBuilds},
|
||||
NewPages = lists:keystore(Path, #p.path, Pages, NewPage),
|
||||
State#s{book = {Notebook, NewPages}, buttons = NewButtons};
|
||||
Other ->
|
||||
ok = wxTextCtrl:setValue(ConsTx, io_lib:format("~tp", [Other])),
|
||||
State
|
||||
end.
|
||||
|
||||
build_name(Path) ->
|
||||
File = filename:basename(Path, ".aes"),
|
||||
TS = integer_to_list(os:system_time(millisecond)),
|
||||
unicode:characters_to_list([File, "-", TS]).
|
||||
|
||||
find_main(ACI) ->
|
||||
find_main(ACI, none, []).
|
||||
|
||||
find_main([#{contract := I = #{kind := contract_interface}} | T], M, Is) ->
|
||||
find_main(T, M, [I | Is]);
|
||||
find_main([#{contract := M = #{kind := contract_main}} | T], _, Is) ->
|
||||
find_main(T, M, Is);
|
||||
find_main([#{namespace := _} | T], M, Is) ->
|
||||
find_main(T, M, Is);
|
||||
find_main([C | T], M, Is) ->
|
||||
ok = tell("Surprising ACI element: ~p", [C]),
|
||||
find_main(T, M, Is);
|
||||
find_main([], M, Is) ->
|
||||
{M, Is}.
|
||||
|
||||
fun_interfaces(Window,
|
||||
Buttons,
|
||||
{OldScrollWin, OldIfaces},
|
||||
{#{name := Name, functions := Funs}, ConIfaces},
|
||||
J) ->
|
||||
ok = wxScrolledWindow:destroy(OldScrollWin),
|
||||
OldButtonIDs = button_key_list(OldIfaces),
|
||||
NextButtons = maps:without(OldButtonIDs, Buttons),
|
||||
ScrollWin = wxScrolledWindow:new(Window),
|
||||
FSOpts = [{label, J("Function Interfaces")}],
|
||||
FunSizer = wxStaticBoxSizer:new(?wxVERTICAL, ScrollWin, FSOpts),
|
||||
ok = wxScrolledWindow:setSizerAndFit(ScrollWin, FunSizer),
|
||||
ok = wxScrolledWindow:setScrollRate(ScrollWin, 5, 5),
|
||||
ConName = wxStaticText:new(ScrollWin, ?wxID_ANY, Name),
|
||||
_ = wxSizer:add(FunSizer, ConName),
|
||||
MakeIface =
|
||||
fun(#{name := N, arguments := As}) ->
|
||||
FunName = unicode:characters_to_list([N, "/", integer_to_list(length(As))]),
|
||||
FN = wxStaticBoxSizer:new(?wxVERTICAL, ScrollWin, [{label, FunName}]),
|
||||
GridSz = wxFlexGridSizer:new(2, 4, 4),
|
||||
ok = wxFlexGridSizer:setFlexibleDirection(GridSz, ?wxHORIZONTAL),
|
||||
ok = wxFlexGridSizer:addGrowableCol(GridSz, 1),
|
||||
MakeArgField =
|
||||
fun(#{name := AN, type := T}) ->
|
||||
Type =
|
||||
case T of
|
||||
<<"address">> -> address;
|
||||
<<"int">> -> integer;
|
||||
<<"bool">> -> boolean;
|
||||
L when is_list(L) -> list; % FIXME
|
||||
% I when is_binary(I) -> iface % FIXME
|
||||
I when is_binary(I) -> address % FIXME
|
||||
end,
|
||||
ANT = wxStaticText:new(ScrollWin, ?wxID_ANY, AN),
|
||||
TCT = wxTextCtrl:new(ScrollWin, ?wxID_ANY),
|
||||
_ = wxFlexGridSizer:add(GridSz, ANT, zxw:flags(base)),
|
||||
_ = wxFlexGridSizer:add(GridSz, TCT, zxw:flags(wide)),
|
||||
{ANT, TCT, Type}
|
||||
end,
|
||||
ArgFields = lists:map(MakeArgField, As),
|
||||
ButtSz = wxBoxSizer:new(?wxHORIZONTAL),
|
||||
{CallButton, DryRunButton} =
|
||||
case N =:= <<"init">> of
|
||||
false ->
|
||||
CallBn = wxButton:new(ScrollWin, ?wxID_ANY, [{label, J("Call")}]),
|
||||
DryRBn = wxButton:new(ScrollWin, ?wxID_ANY, [{label, J("Dry Run")}]),
|
||||
true = wxButton:disable(CallBn),
|
||||
true = wxButton:disable(DryRBn),
|
||||
_ = wxBoxSizer:add(ButtSz, CallBn, zxw:flags(wide)),
|
||||
_ = wxBoxSizer:add(ButtSz, DryRBn, zxw:flags(wide)),
|
||||
{#w{name = {N, call}, id = wxButton:getId(CallBn), wx = CallBn},
|
||||
#w{name = {N, dryr}, id = wxButton:getId(DryRBn), wx = DryRBn}};
|
||||
true ->
|
||||
Deploy = wxButton:new(ScrollWin, ?wxID_ANY, [{label, J("Deploy")}]),
|
||||
_ = wxBoxSizer:add(ButtSz, Deploy, zxw:flags(wide)),
|
||||
{#w{name = {N, call}, id = wxButton:getId(Deploy), wx = Deploy},
|
||||
none}
|
||||
end,
|
||||
_ = wxStaticBoxSizer:add(FN, GridSz, zxw:flags(wide)),
|
||||
_ = wxStaticBoxSizer:add(FN, ButtSz, zxw:flags(base)),
|
||||
_ = wxSizer:add(FunSizer, FN, zxw:flags(base)),
|
||||
#f{name = N, call = CallButton, dryrun = DryRunButton, args = ArgFields}
|
||||
end,
|
||||
Ifaces = lists:map(MakeIface, Funs),
|
||||
NewButtons = lists:foldl(fun map_iface_buttons/2, NextButtons, Ifaces),
|
||||
ok = wxSizer:layout(FunSizer),
|
||||
{NewButtons, {ScrollWin, Ifaces}}.
|
||||
|
||||
button_key_list([#f{call = #w{id = C}, dryrun = #w{id = D}} | T]) ->
|
||||
[C, D | button_key_list(T)];
|
||||
button_key_list([#f{call = #w{id = C}, dryrun = none} | T]) ->
|
||||
[C | button_key_list(T)];
|
||||
button_key_list([]) ->
|
||||
[].
|
||||
|
||||
map_iface_buttons(#f{call = C = #w{id = CID}, dryrun = D = #w{id = DID}}, A) ->
|
||||
maps:put(DID, D, maps:put(CID, C, A));
|
||||
map_iface_buttons(#f{call = C = #w{id = CID}, dryrun = none}, A) ->
|
||||
maps:put(CID, C, A).
|
||||
|
||||
|
||||
open_file(State = #s{frame = Frame, j = J, prefs = Prefs}) ->
|
||||
DefaultDir =
|
||||
case maps:find(dir, Prefs) of
|
||||
{ok, PrefDir} ->
|
||||
PrefDir;
|
||||
error ->
|
||||
case os:getenv("ZOMP_DIR") of
|
||||
"" -> file:get_pwd();
|
||||
D -> filename:basename(D)
|
||||
end
|
||||
end,
|
||||
Options =
|
||||
[{message, J("Load Contract Source")},
|
||||
{defaultDir, DefaultDir},
|
||||
{wildCard, "*.aes"},
|
||||
{style, ?wxFD_OPEN}],
|
||||
Dialog = wxFileDialog:new(Frame, Options),
|
||||
NewState =
|
||||
case wxFileDialog:showModal(Dialog) of
|
||||
?wxID_OK ->
|
||||
Dir = wxFileDialog:getDirectory(Dialog),
|
||||
case wxFileDialog:getFilename(Dialog) of
|
||||
"" ->
|
||||
State;
|
||||
Name ->
|
||||
File =
|
||||
case filename:extension(Name) of
|
||||
".aes" -> Name;
|
||||
_ -> Name ++ ".aes"
|
||||
end,
|
||||
Path = filename:join(Dir, File),
|
||||
NewPrefs = maps:put(dir, Dir, Prefs),
|
||||
NextState = State#s{prefs = NewPrefs},
|
||||
add_page(NextState, Path)
|
||||
end;
|
||||
?wxID_CANCEL ->
|
||||
State
|
||||
end,
|
||||
ok = wxFileDialog:destroy(Dialog),
|
||||
NewState.
|
||||
|
||||
|
||||
close_file(State = #s{book = {Notebook, Pages}}) ->
|
||||
case wxNotebook:getSelection(Notebook) of
|
||||
?wxNOT_FOUND ->
|
||||
State;
|
||||
Index ->
|
||||
NewPages = drop_nth(Index + 1, Pages),
|
||||
true = wxNotebook:deletePage(Notebook, Index),
|
||||
State#s{book = {Notebook, NewPages}}
|
||||
end.
|
||||
|
||||
|
||||
drop_nth(1, [_ | T]) -> T;
|
||||
drop_nth(N, [H | T]) -> [H | drop_nth(N - 1, T)].
|
||||
|
||||
|
||||
keyfind_index(K, E, L) ->
|
||||
keyfind_index(K, E, 1, L).
|
||||
|
||||
keyfind_index(K, E, I, [H | T]) ->
|
||||
case element(E, H) =:= K of
|
||||
false -> keyfind_index(K, E, I + 1, T);
|
||||
true -> {ok, I}
|
||||
end;
|
||||
keyfind_index(_, _, _, []) ->
|
||||
error.
|
Loading…
x
Reference in New Issue
Block a user