-module(etui@widgets@multi_select).
-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]).
-define(FILEPATH, "src/etui/widgets/multi_select.gleam").
-export([multi_select_new/1, with_max/2, with_marks/3, with_cursor_mark/2, with_cursor_style/2, with_selected_style/2, with_colors/3, state_new/0, select_next/2, select_prev/1, toggle/2, is_selected/2, selected_indices/1, selected_values/2, clear_selection/1, effective_offset/2, render/4]).
-export_type([multi_select_widget/0, multi_select_state/0]).
-if(?OTP_RELEASE >= 27).
-define(MODULEDOC(Str), -moduledoc(Str)).
-define(DOC(Str), -doc(Str)).
-else.
-define(MODULEDOC(Str), -compile([])).
-define(DOC(Str), -compile([])).
-endif.
-type multi_select_widget() :: {multi_select_widget,
list(binary()),
etui@style:style(),
etui@style:style(),
binary(),
binary(),
binary(),
integer(),
etui@style:color(),
etui@style:color()}.
-type multi_select_state() :: {multi_select_state,
integer(),
list(integer()),
integer()}.
-file("src/etui/widgets/multi_select.gleam", 37).
-spec multi_select_new(list(binary())) -> multi_select_widget().
multi_select_new(Items) ->
{multi_select_widget,
Items,
{style, default, default, etui@style:reverse()},
{style, default, default, etui@style:bold()},
<<"[x] "/utf8>>,
<<"[ ] "/utf8>>,
<<"â–¶ "/utf8>>,
0,
default,
default}.
-file("src/etui/widgets/multi_select.gleam", 60).
?DOC(" Cap the number of selected items. 0 = unlimited.\n").
-spec with_max(multi_select_widget(), integer()) -> multi_select_widget().
with_max(W, M) ->
{multi_select_widget,
erlang:element(2, W),
erlang:element(3, W),
erlang:element(4, W),
erlang:element(5, W),
erlang:element(6, W),
erlang:element(7, W),
gleam@int:max(0, M),
erlang:element(9, W),
erlang:element(10, W)}.
-file("src/etui/widgets/multi_select.gleam", 64).
-spec with_marks(multi_select_widget(), binary(), binary()) -> multi_select_widget().
with_marks(W, Checked, Unchecked) ->
{multi_select_widget,
erlang:element(2, W),
erlang:element(3, W),
erlang:element(4, W),
Checked,
Unchecked,
erlang:element(7, W),
erlang:element(8, W),
erlang:element(9, W),
erlang:element(10, W)}.
-file("src/etui/widgets/multi_select.gleam", 72).
-spec with_cursor_mark(multi_select_widget(), binary()) -> multi_select_widget().
with_cursor_mark(W, M) ->
{multi_select_widget,
erlang:element(2, W),
erlang:element(3, W),
erlang:element(4, W),
erlang:element(5, W),
erlang:element(6, W),
M,
erlang:element(8, W),
erlang:element(9, W),
erlang:element(10, W)}.
-file("src/etui/widgets/multi_select.gleam", 76).
-spec with_cursor_style(multi_select_widget(), etui@style:style()) -> multi_select_widget().
with_cursor_style(W, S) ->
{multi_select_widget,
erlang:element(2, W),
S,
erlang:element(4, W),
erlang:element(5, W),
erlang:element(6, W),
erlang:element(7, W),
erlang:element(8, W),
erlang:element(9, W),
erlang:element(10, W)}.
-file("src/etui/widgets/multi_select.gleam", 83).
-spec with_selected_style(multi_select_widget(), etui@style:style()) -> multi_select_widget().
with_selected_style(W, S) ->
{multi_select_widget,
erlang:element(2, W),
erlang:element(3, W),
S,
erlang:element(5, W),
erlang:element(6, W),
erlang:element(7, W),
erlang:element(8, W),
erlang:element(9, W),
erlang:element(10, W)}.
-file("src/etui/widgets/multi_select.gleam", 90).
-spec with_colors(multi_select_widget(), etui@style:color(), etui@style:color()) -> multi_select_widget().
with_colors(W, Fg, Bg) ->
{multi_select_widget,
erlang:element(2, W),
erlang:element(3, W),
erlang:element(4, W),
erlang:element(5, W),
erlang:element(6, W),
erlang:element(7, W),
erlang:element(8, W),
Fg,
Bg}.
-file("src/etui/widgets/multi_select.gleam", 101).
-spec state_new() -> multi_select_state().
state_new() ->
{multi_select_state, 0, [], 0}.
-file("src/etui/widgets/multi_select.gleam", 105).
-spec select_next(multi_select_state(), integer()) -> multi_select_state().
select_next(State, Item_count) ->
Max_idx = gleam@int:max(0, Item_count - 1),
{multi_select_state,
gleam@int:min(erlang:element(2, State) + 1, Max_idx),
erlang:element(3, State),
erlang:element(4, State)}.
-file("src/etui/widgets/multi_select.gleam", 113).
-spec select_prev(multi_select_state()) -> multi_select_state().
select_prev(State) ->
{multi_select_state,
gleam@int:max(erlang:element(2, State) - 1, 0),
erlang:element(3, State),
erlang:element(4, State)}.
-file("src/etui/widgets/multi_select.gleam", 263).
-spec insert_sorted(list(integer()), integer()) -> list(integer()).
insert_sorted(Lst, N) ->
case Lst of
[] ->
[N];
[H | _] when N < H ->
[N | Lst];
[H@1 | _] when N =:= H@1 ->
Lst;
[H@2 | T] ->
[H@2 | insert_sorted(T, N)]
end.
-file("src/etui/widgets/multi_select.gleam", 118).
?DOC(" Toggle the cursor item. Respects `max` from the widget config.\n").
-spec toggle(multi_select_state(), integer()) -> multi_select_state().
toggle(State, Max) ->
case gleam@list:contains(erlang:element(3, State), erlang:element(2, State)) of
true ->
{multi_select_state,
erlang:element(2, State),
gleam@list:filter(
erlang:element(3, State),
fun(I) -> I /= erlang:element(2, State) end
),
erlang:element(4, State)};
false ->
case (Max > 0) andalso (erlang:length(erlang:element(3, State)) >= Max) of
true ->
State;
false ->
{multi_select_state,
erlang:element(2, State),
insert_sorted(
erlang:element(3, State),
erlang:element(2, State)
),
erlang:element(4, State)}
end
end.
-file("src/etui/widgets/multi_select.gleam", 137).
-spec is_selected(multi_select_state(), integer()) -> boolean().
is_selected(State, Idx) ->
gleam@list:contains(erlang:element(3, State), Idx).
-file("src/etui/widgets/multi_select.gleam", 141).
-spec selected_indices(multi_select_state()) -> list(integer()).
selected_indices(State) ->
erlang:element(3, State).
-file("src/etui/widgets/multi_select.gleam", 146).
?DOC(" Pull the selected item strings in original order.\n").
-spec selected_values(list(binary()), multi_select_state()) -> list(binary()).
selected_values(Items, State) ->
_pipe = Items,
_pipe@1 = gleam@list:index_map(_pipe, fun(Item, I) -> {I, Item} end),
gleam@list:filter_map(
_pipe@1,
fun(Pair) ->
case gleam@list:contains(
erlang:element(3, State),
erlang:element(1, Pair)
) of
true ->
{ok, erlang:element(2, Pair)};
false ->
{error, nil}
end
end
).
-file("src/etui/widgets/multi_select.gleam", 160).
-spec clear_selection(multi_select_state()) -> multi_select_state().
clear_selection(State) ->
{multi_select_state, erlang:element(2, State), [], erlang:element(4, State)}.
-file("src/etui/widgets/multi_select.gleam", 248).
-spec scroll_offset(integer(), integer(), integer()) -> integer().
scroll_offset(Cursor, Offset, Height) ->
case Cursor < Offset of
true ->
Cursor;
false ->
case Height =< 0 of
true ->
Offset;
false ->
case Cursor >= (Offset + Height) of
true ->
(Cursor - Height) + 1;
false ->
Offset
end
end
end.
-file("src/etui/widgets/multi_select.gleam", 165).
?DOC(" Effective scroll offset for a viewport of `height` rows.\n").
-spec effective_offset(multi_select_state(), integer()) -> integer().
effective_offset(State, Height) ->
scroll_offset(erlang:element(2, State), erlang:element(4, State), Height).
-file("src/etui/widgets/multi_select.gleam", 187).
-spec render_rows(
etui@buffer:buffer(),
etui@geometry:rect(),
multi_select_widget(),
multi_select_state(),
integer(),
integer()
) -> etui@buffer:buffer().
render_rows(Buf, Area, W, State, Offset, Row_off) ->
case Row_off >= erlang:element(3, erlang:element(3, Area)) of
true ->
Buf;
false ->
Item_idx = Offset + Row_off,
case gleam@list:drop(erlang:element(2, W), Item_idx) of
[] ->
Buf;
[Item | _] ->
Y = erlang:element(3, erlang:element(2, Area)) + Row_off,
Is_cursor = Item_idx =:= erlang:element(2, State),
Is_sel = gleam@list:contains(
erlang:element(3, State),
Item_idx
),
Prefix = case Is_cursor of
true ->
erlang:element(7, W);
false ->
gleam@string:repeat(
<<" "/utf8>>,
etui@text:cell_width(erlang:element(7, W))
)
end,
Mark = case Is_sel of
true ->
erlang:element(5, W);
false ->
erlang:element(6, W)
end,
Raw = <<<<Prefix/binary, Mark/binary>>/binary, Item/binary>>,
Truncated = etui@text:truncate(
Raw,
erlang:element(2, erlang:element(3, Area)),
<<""/utf8>>
),
Padded = etui@text:pad_right(
Truncated,
erlang:element(2, erlang:element(3, Area))
),
{Fg, Bg, Modifier} = case {Is_cursor, Is_sel} of
{true, _} ->
{erlang:element(2, erlang:element(3, W)),
erlang:element(3, erlang:element(3, W)),
erlang:element(4, erlang:element(3, W))};
{false, true} ->
{erlang:element(2, erlang:element(4, W)),
erlang:element(3, erlang:element(4, W)),
erlang:element(4, erlang:element(4, W))};
{false, false} ->
{erlang:element(9, W),
erlang:element(10, W),
etui@style:none()}
end,
Buf2 = etui@buffer:set_string(
Buf,
{position,
erlang:element(2, erlang:element(2, Area)),
Y},
Padded,
Fg,
Bg,
Modifier
),
render_rows(Buf2, Area, W, State, Offset, Row_off + 1)
end
end.
-file("src/etui/widgets/multi_select.gleam", 172).
-spec render(
etui@buffer:buffer(),
etui@geometry:rect(),
multi_select_widget(),
multi_select_state()
) -> etui@buffer:buffer().
render(Buf, Area, W, State) ->
case (erlang:element(3, erlang:element(3, Area)) =< 0) orelse (erlang:element(
2,
erlang:element(3, Area)
)
=< 0) of
true ->
Buf;
false ->
Offset = scroll_offset(
erlang:element(2, State),
erlang:element(4, State),
erlang:element(3, erlang:element(3, Area))
),
render_rows(Buf, Area, W, State, Offset, 0)
end.