Skip to main content

src/minigui.erl

-module(minigui).
-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]).
-define(FILEPATH, "src/minigui.gleam").
-export([start/0, start_with_path/1, create_window/2, set_label/2, set_text/2, add_button/3, run/2, quit/1]).
-export_type([handle/0, recv_result/0, start_error/0, event/0]).

-type handle() :: {handle, gleam@dynamic:dynamic_()}.

-type recv_result() :: {data, bitstring()} | timeout | port_closed.

-type start_error() :: {ensure_port_failed, binary()} |
    {open_port_failed, binary()} |
    {handshake_failed, binary()}.

-type event() :: {button_clicked, integer()} |
    closed |
    {text_changed, binary()} |
    {key_down, integer()} |
    {log, binary()} |
    {port_error, binary()}.

-file("src/minigui.gleam", 79).
-spec map_start_error(binary()) -> start_error().
map_start_error(Msg) ->
    case gleam_stdlib:contains_string(Msg, <<"ensure_port_failed"/utf8>>) of
        true ->
            {ensure_port_failed, Msg};

        false ->
            case gleam_stdlib:contains_string(Msg, <<"open_port_failed"/utf8>>) of
                true ->
                    {open_port_failed, Msg};

                false ->
                    {open_port_failed, Msg}
            end
    end.

-file("src/minigui.gleam", 122).
-spec wait_for_message(handle(), integer()) -> {ok, bitstring()} |
    {error, binary()}.
wait_for_message(Handle, Timeout_ms) ->
    case minigui_ffi:recv(erlang:element(2, Handle), Timeout_ms) of
        {data, Msg} ->
            {ok, Msg};

        timeout ->
            {error, <<"timeout"/utf8>>};

        port_closed ->
            {error, <<"port closed"/utf8>>}
    end.

-file("src/minigui.gleam", 100).
-spec handshake(handle()) -> {ok, nil} | {error, binary()}.
handshake(Handle) ->
    minigui_ffi:send_hello(erlang:element(2, Handle), 1),
    case wait_for_message(Handle, 2000) of
        {ok, Msg} ->
            case Msg of
                <<16#F0, V_hi, V_lo, _:4/binary>> ->
                    V = (V_hi * 256) + V_lo,
                    case V =:= 1 of
                        true ->
                            {ok, nil};

                        false ->
                            {error,
                                <<"protocol mismatch: "/utf8,
                                    (erlang:integer_to_binary(V))/binary>>}
                    end;

                _ ->
                    {error, <<"handshake: unexpected response"/utf8>>}
            end;

        {error, E} ->
            {error, E}
    end.

-file("src/minigui.gleam", 52).
-spec start() -> {ok, handle()} | {error, start_error()}.
start() ->
    case minigui_ffi:start() of
        {ok, Port} ->
            Handle = {handle, Port},
            case handshake(Handle) of
                {ok, _} ->
                    {ok, Handle};

                {error, E} ->
                    {error, {handshake_failed, E}}
            end;

        {error, E@1} ->
            {error, map_start_error(E@1)}
    end.

-file("src/minigui.gleam", 66).
-spec start_with_path(binary()) -> {ok, handle()} | {error, start_error()}.
start_with_path(Path) ->
    case minigui_ffi:start_with_path(Path) of
        {ok, Port} ->
            Handle = {handle, Port},
            case handshake(Handle) of
                {ok, _} ->
                    {ok, Handle};

                {error, E} ->
                    {error, {handshake_failed, E}}
            end;

        {error, E@1} ->
            {error, map_start_error(E@1)}
    end.

-file("src/minigui.gleam", 93).
-spec mod_u8(integer()) -> integer().
mod_u8(N) ->
    case gleam@int:modulo(N, 256) of
        {ok, V} ->
            V;

        {error, _} ->
            0
    end.

-file("src/minigui.gleam", 139).
-spec wait_for_ok(handle(), integer(), integer()) -> {ok, nil} |
    {error, binary()}.
wait_for_ok(Handle, Req_id, Timeout_ms) ->
    case minigui_ffi:recv(erlang:element(2, Handle), Timeout_ms) of
        timeout ->
            {error, <<"timeout waiting for OK/ERR"/utf8>>};

        port_closed ->
            {error, <<"port closed"/utf8>>};

        {data, Msg} ->
            case Msg of
                <<16#70, Got:32/unsigned-integer>> ->
                    case Got =:= Req_id of
                        true ->
                            {ok, nil};

                        false ->
                            wait_for_ok(Handle, Req_id, Timeout_ms)
                    end;

                <<16#71, Got@1:32/unsigned-integer, Rest/bitstring>> ->
                    case Got@1 =:= Req_id of
                        true ->
                            case gleam@bit_array:to_string(Rest) of
                                {ok, Text} ->
                                    {error, Text};

                                {error, _} ->
                                    {error, <<"error (invalid utf8)"/utf8>>}
                            end;

                        false ->
                            wait_for_ok(Handle, Req_id, Timeout_ms)
                    end;

                _ ->
                    wait_for_ok(Handle, Req_id, Timeout_ms)
            end
    end.

-file("src/minigui.gleam", 130).
-spec send_cmd_wait_ok(handle(), integer(), binary()) -> {ok, nil} |
    {error, binary()}.
send_cmd_wait_ok(Handle, Cmd, Payload) ->
    Req_id = minigui_ffi:unique_request_id(),
    minigui_ffi:send_cmd(erlang:element(2, Handle), Cmd, Req_id, Payload),
    wait_for_ok(Handle, Req_id, 5000).

-file("src/minigui.gleam", 172).
-spec create_window(handle(), binary()) -> {ok, nil} | {error, binary()}.
create_window(Handle, Title) ->
    send_cmd_wait_ok(Handle, 16#10, Title).

-file("src/minigui.gleam", 177).
-spec set_label(handle(), binary()) -> {ok, nil} | {error, binary()}.
set_label(Handle, Text) ->
    send_cmd_wait_ok(Handle, 16#11, Text).

-file("src/minigui.gleam", 182).
-spec set_text(handle(), binary()) -> {ok, nil} | {error, binary()}.
set_text(Handle, Text) ->
    send_cmd_wait_ok(Handle, 16#12, Text).

-file("src/minigui.gleam", 187).
-spec add_button(handle(), integer(), binary()) -> {ok, nil} | {error, binary()}.
add_button(Handle, Id, Label) ->
    Id_u8 = mod_u8(Id),
    Req_id = minigui_ffi:unique_request_id(),
    minigui_ffi:send_add_button(erlang:element(2, Handle), Req_id, Id_u8, Label),
    wait_for_ok(Handle, Req_id, 5000).

-file("src/minigui.gleam", 226).
-spec decode_event(bitstring()) -> event().
decode_event(Msg) ->
    case Msg of
        <<16#81, Id:8/unsigned-integer>> ->
            {button_clicked, Id};

        <<16#82>> ->
            closed;

        <<16#84, Rest/bitstring>> ->
            case gleam@bit_array:to_string(Rest) of
                {ok, Text} ->
                    {text_changed, Text};

                {error, _} ->
                    {port_error, <<"text_changed (invalid utf8)"/utf8>>}
            end;

        <<16#85, Key:32/unsigned-integer>> ->
            {key_down, Key};

        <<16#83, Rest@1/bitstring>> ->
            case gleam@bit_array:to_string(Rest@1) of
                {ok, Text@1} ->
                    {log, Text@1};

                {error, _} ->
                    {log, <<"log (invalid utf8)"/utf8>>}
            end;

        <<16#86, Rest@2/bitstring>> ->
            case gleam@bit_array:to_string(Rest@2) of
                {ok, Text@2} ->
                    {port_error, Text@2};

                {error, _} ->
                    {port_error, <<"error (invalid utf8)"/utf8>>}
            end;

        _ ->
            {log, <<"unknown message"/utf8>>}
    end.

-file("src/minigui.gleam", 208).
-spec loop_events(handle(), fun((event()) -> nil)) -> {ok, nil} |
    {error, binary()}.
loop_events(Handle, On_event) ->
    case minigui_ffi:recv(erlang:element(2, Handle), 60000) of
        timeout ->
            loop_events(Handle, On_event);

        port_closed ->
            On_event(closed),
            {ok, nil};

        {data, Msg} ->
            Ev = decode_event(Msg),
            On_event(Ev),
            case Ev of
                closed ->
                    {ok, nil};

                _ ->
                    loop_events(Handle, On_event)
            end
    end.

-file("src/minigui.gleam", 195).
-spec run(handle(), fun((event()) -> nil)) -> {ok, nil} | {error, binary()}.
run(Handle, On_event) ->
    case send_cmd_wait_ok(Handle, 16#14, <<""/utf8>>) of
        {ok, _} ->
            loop_events(Handle, On_event);

        {error, E} ->
            {error, E}
    end.

-file("src/minigui.gleam", 203).
-spec quit(handle()) -> {ok, nil} | {error, binary()}.
quit(Handle) ->
    send_cmd_wait_ok(Handle, 16#15, <<""/utf8>>).