Skip to main content

src/etui@widgets@scrollbar.erl

-module(etui@widgets@scrollbar).
-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]).
-define(FILEPATH, "src/etui/widgets/scrollbar.gleam").
-export([scrollbar_new/3, with_chars/3, with_arrows/3, with_colors/3, with_thumb_colors/3, render_vertical/3, render_horizontal/3]).
-export_type([scrollbar/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 scrollbar() :: {scrollbar,
        integer(),
        integer(),
        integer(),
        binary(),
        binary(),
        binary(),
        binary(),
        etui@style:color(),
        etui@style:color(),
        etui@style:color(),
        etui@style:color()}.

-file("src/etui/widgets/scrollbar.gleam", 48).
?DOC(
    " New scrollbar. `total` = total items, `visible` = viewport size,\n"
    " `offset` = first visible item index.\n"
).
-spec scrollbar_new(integer(), integer(), integer()) -> scrollbar().
scrollbar_new(Total, Visible, Offset) ->
    {scrollbar,
        gleam@int:max(1, Total),
        gleam@int:max(1, Visible),
        gleam@int:max(0, Offset),
        <<"â–‘"/utf8>>,
        <<"â–ˆ"/utf8>>,
        <<"â–²"/utf8>>,
        <<"â–¼"/utf8>>,
        default,
        default,
        default,
        default}.

-file("src/etui/widgets/scrollbar.gleam", 65).
?DOC(" Override track and thumb characters.\n").
-spec with_chars(scrollbar(), binary(), binary()) -> scrollbar().
with_chars(S, Track, Thumb) ->
    {scrollbar,
        erlang:element(2, S),
        erlang:element(3, S),
        erlang:element(4, S),
        Track,
        Thumb,
        erlang:element(7, S),
        erlang:element(8, S),
        erlang:element(9, S),
        erlang:element(10, S),
        erlang:element(11, S),
        erlang:element(12, S)}.

-file("src/etui/widgets/scrollbar.gleam", 70).
?DOC(" Override arrow characters. Pass `\"\"` to hide arrows.\n").
-spec with_arrows(scrollbar(), binary(), binary()) -> scrollbar().
with_arrows(S, Start, End_ch) ->
    {scrollbar,
        erlang:element(2, S),
        erlang:element(3, S),
        erlang:element(4, S),
        erlang:element(5, S),
        erlang:element(6, S),
        Start,
        End_ch,
        erlang:element(9, S),
        erlang:element(10, S),
        erlang:element(11, S),
        erlang:element(12, S)}.

-file("src/etui/widgets/scrollbar.gleam", 75).
?DOC(" Set colors for the track.\n").
-spec with_colors(scrollbar(), etui@style:color(), etui@style:color()) -> scrollbar().
with_colors(S, Fg, Bg) ->
    {scrollbar,
        erlang:element(2, S),
        erlang:element(3, S),
        erlang:element(4, S),
        erlang:element(5, S),
        erlang:element(6, S),
        erlang:element(7, S),
        erlang:element(8, S),
        Fg,
        Bg,
        erlang:element(11, S),
        erlang:element(12, S)}.

-file("src/etui/widgets/scrollbar.gleam", 84).
?DOC(" Set colors for the thumb.\n").
-spec with_thumb_colors(scrollbar(), etui@style:color(), etui@style:color()) -> scrollbar().
with_thumb_colors(S, Fg, Bg) ->
    {scrollbar,
        erlang:element(2, S),
        erlang:element(3, S),
        erlang:element(4, S),
        erlang:element(5, S),
        erlang:element(6, S),
        erlang:element(7, S),
        erlang:element(8, S),
        erlang:element(9, S),
        erlang:element(10, S),
        Fg,
        Bg}.

-file("src/etui/widgets/scrollbar.gleam", 265).
-spec render_vertical_track(
    etui@buffer:buffer(),
    etui@geometry:rect(),
    scrollbar(),
    integer(),
    integer(),
    integer(),
    integer()
) -> etui@buffer:buffer().
render_vertical_track(Buf, Area, S, Track_len, Thumb_start, Thumb_size, I) ->
    case I >= Track_len of
        true ->
            Buf;

        false ->
            Pos = {position,
                erlang:element(2, erlang:element(2, Area)),
                erlang:element(3, erlang:element(2, Area)) + I},
            Is_thumb = (I >= Thumb_start) andalso (I < (Thumb_start + Thumb_size)),
            {Ch, Fg, Bg} = case Is_thumb of
                true ->
                    {erlang:element(6, S),
                        erlang:element(11, S),
                        erlang:element(12, S)};

                false ->
                    {erlang:element(5, S),
                        erlang:element(9, S),
                        erlang:element(10, S)}
            end,
            Buf2 = etui@buffer:set_string(
                Buf,
                Pos,
                Ch,
                Fg,
                Bg,
                etui@style:none()
            ),
            render_vertical_track(
                Buf2,
                Area,
                S,
                Track_len,
                Thumb_start,
                Thumb_size,
                I + 1
            )
    end.

-file("src/etui/widgets/scrollbar.gleam", 249).
?DOC(" Compute thumb start position and size within a track of `track_len` cells.\n").
-spec thumb_geometry(scrollbar(), integer()) -> {integer(), integer()}.
thumb_geometry(S, Track_len) ->
    Total = gleam@int:max(1, erlang:element(2, S)),
    Visible = gleam@int:clamp(erlang:element(3, S), 1, Total),
    Offset = gleam@int:clamp(erlang:element(4, S), 0, Total - Visible),
    Thumb_size = gleam@int:max(1, case Total of
            0 -> 0;
            Gleam@denominator -> Track_len * Visible div Gleam@denominator
        end),
    Scrollable = Total - Visible,
    Thumb_start = case Scrollable of
        0 ->
            0;

        _ ->
            case Scrollable of
                0 -> 0;
                Gleam@denominator@1 -> (Track_len - Thumb_size) * Offset div Gleam@denominator@1
            end
    end,
    {Thumb_start, Thumb_size}.

-file("src/etui/widgets/scrollbar.gleam", 98).
?DOC(
    " Render a vertical scrollbar into the first column of `area`.\n"
    " Arrow characters (if non-empty) occupy the top and bottom cells;\n"
    " the track fills the remaining height.\n"
).
-spec render_vertical(etui@buffer:buffer(), etui@geometry:rect(), scrollbar()) -> etui@buffer:buffer().
render_vertical(Buf, Area, S) ->
    case (erlang:element(3, erlang:element(3, Area)) =< 0) orelse (erlang:element(
        2,
        erlang:element(3, Area)
    )
    =< 0) of
        true ->
            Buf;

        false ->
            Has_start = erlang:element(7, S) /= <<""/utf8>>,
            Has_end = erlang:element(8, S) /= <<""/utf8>>,
            Arrow_top = case Has_start of
                true ->
                    1;

                false ->
                    0
            end,
            Arrow_bot = case Has_end of
                true ->
                    1;

                false ->
                    0
            end,
            Track_len = gleam@int:max(
                0,
                (erlang:element(3, erlang:element(3, Area)) - Arrow_top) - Arrow_bot
            ),
            Buf@1 = case Has_start of
                false ->
                    Buf;

                true ->
                    etui@buffer:set_string(
                        Buf,
                        {position,
                            erlang:element(2, erlang:element(2, Area)),
                            erlang:element(3, erlang:element(2, Area))},
                        erlang:element(7, S),
                        erlang:element(9, S),
                        erlang:element(10, S),
                        etui@style:none()
                    )
            end,
            Buf@2 = case Has_end of
                false ->
                    Buf@1;

                true ->
                    etui@buffer:set_string(
                        Buf@1,
                        {position,
                            erlang:element(2, erlang:element(2, Area)),
                            (erlang:element(3, erlang:element(2, Area)) + erlang:element(
                                3,
                                erlang:element(3, Area)
                            ))
                            - 1},
                        erlang:element(8, S),
                        erlang:element(9, S),
                        erlang:element(10, S),
                        etui@style:none()
                    )
            end,
            case Track_len =< 0 of
                true ->
                    Buf@2;

                false ->
                    Track_area = etui@geometry:rect_new(
                        erlang:element(2, erlang:element(2, Area)),
                        erlang:element(3, erlang:element(2, Area)) + Arrow_top,
                        erlang:element(2, erlang:element(3, Area)),
                        Track_len
                    ),
                    {Thumb_start, Thumb_size} = thumb_geometry(S, Track_len),
                    render_vertical_track(
                        Buf@2,
                        Track_area,
                        S,
                        Track_len,
                        Thumb_start,
                        Thumb_size,
                        0
                    )
            end
    end.

-file("src/etui/widgets/scrollbar.gleam", 297).
-spec render_horizontal_track(
    etui@buffer:buffer(),
    etui@geometry:rect(),
    scrollbar(),
    integer(),
    integer(),
    integer(),
    integer()
) -> etui@buffer:buffer().
render_horizontal_track(Buf, Area, S, Track_len, Thumb_start, Thumb_size, I) ->
    case I >= Track_len of
        true ->
            Buf;

        false ->
            Pos = {position,
                erlang:element(2, erlang:element(2, Area)) + I,
                erlang:element(3, erlang:element(2, Area))},
            Is_thumb = (I >= Thumb_start) andalso (I < (Thumb_start + Thumb_size)),
            {Ch, Fg, Bg} = case Is_thumb of
                true ->
                    {erlang:element(6, S),
                        erlang:element(11, S),
                        erlang:element(12, S)};

                false ->
                    {erlang:element(5, S),
                        erlang:element(9, S),
                        erlang:element(10, S)}
            end,
            Buf2 = etui@buffer:set_string(
                Buf,
                Pos,
                Ch,
                Fg,
                Bg,
                etui@style:none()
            ),
            render_horizontal_track(
                Buf2,
                Area,
                S,
                Track_len,
                Thumb_start,
                Thumb_size,
                I + 1
            )
    end.

-file("src/etui/widgets/scrollbar.gleam", 173).
?DOC(
    " Render a horizontal scrollbar into the first row of `area`.\n"
    " Arrow characters (if non-empty) occupy the leftmost and rightmost cells;\n"
    " the track fills the remaining width.\n"
).
-spec render_horizontal(etui@buffer:buffer(), etui@geometry:rect(), scrollbar()) -> etui@buffer:buffer().
render_horizontal(Buf, Area, S) ->
    case (erlang:element(3, erlang:element(3, Area)) =< 0) orelse (erlang:element(
        2,
        erlang:element(3, Area)
    )
    =< 0) of
        true ->
            Buf;

        false ->
            Has_start = erlang:element(7, S) /= <<""/utf8>>,
            Has_end = erlang:element(8, S) /= <<""/utf8>>,
            Arrow_left = case Has_start of
                true ->
                    1;

                false ->
                    0
            end,
            Arrow_right = case Has_end of
                true ->
                    1;

                false ->
                    0
            end,
            Track_len = gleam@int:max(
                0,
                (erlang:element(2, erlang:element(3, Area)) - Arrow_left) - Arrow_right
            ),
            Buf@1 = case Has_start of
                false ->
                    Buf;

                true ->
                    etui@buffer:set_string(
                        Buf,
                        {position,
                            erlang:element(2, erlang:element(2, Area)),
                            erlang:element(3, erlang:element(2, Area))},
                        erlang:element(7, S),
                        erlang:element(9, S),
                        erlang:element(10, S),
                        etui@style:none()
                    )
            end,
            Buf@2 = case Has_end of
                false ->
                    Buf@1;

                true ->
                    etui@buffer:set_string(
                        Buf@1,
                        {position,
                            (erlang:element(2, erlang:element(2, Area)) + erlang:element(
                                2,
                                erlang:element(3, Area)
                            ))
                            - 1,
                            erlang:element(3, erlang:element(2, Area))},
                        erlang:element(8, S),
                        erlang:element(9, S),
                        erlang:element(10, S),
                        etui@style:none()
                    )
            end,
            case Track_len =< 0 of
                true ->
                    Buf@2;

                false ->
                    Track_area = etui@geometry:rect_new(
                        erlang:element(2, erlang:element(2, Area)) + Arrow_left,
                        erlang:element(3, erlang:element(2, Area)),
                        Track_len,
                        erlang:element(3, erlang:element(3, Area))
                    ),
                    {Thumb_start, Thumb_size} = thumb_geometry(S, Track_len),
                    render_horizontal_track(
                        Buf@2,
                        Track_area,
                        S,
                        Track_len,
                        Thumb_start,
                        Thumb_size,
                        0
                    )
            end
    end.