-module(etui@braille).
-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]).
-define(FILEPATH, "src/etui/braille.gleam").
-export([new/0, set_pixel/5, bit/2, put/4, flush/4]).
-if(?OTP_RELEASE >= 27).
-define(MODULEDOC(Str), -moduledoc(Str)).
-define(DOC(Str), -doc(Str)).
-else.
-define(MODULEDOC(Str), -compile([])).
-define(DOC(Str), -compile([])).
-endif.
-file("src/etui/braille.gleam", 20).
?DOC(" Empty pixel grid.\n").
-spec new() -> gleam@dict:dict({integer(), integer()}, {integer(),
etui@style:color()}).
new() ->
maps:new().
-file("src/etui/braille.gleam", 26).
?DOC(
" Set a pixel at terminal-cell (char_x, char_y), accumulating its bit into\n"
" the existing mask. Color overrides any prior color for that cell.\n"
).
-spec set_pixel(
gleam@dict:dict({integer(), integer()}, {integer(), etui@style:color()}),
integer(),
integer(),
integer(),
etui@style:color()
) -> gleam@dict:dict({integer(), integer()}, {integer(), etui@style:color()}).
set_pixel(Pixels, Char_x, Char_y, Bit, Fg) ->
Key = {Char_x, Char_y},
Existing = case gleam_stdlib:map_get(Pixels, Key) of
{ok, {M, _}} ->
M;
{error, _} ->
0
end,
gleam@dict:insert(Pixels, Key, {erlang:'bor'(Existing, Bit), Fg}).
-file("src/etui/braille.gleam", 48).
?DOC(
" Bitmask bit for the dot at (col, row) inside a 2×4 braille cell.\n"
" Layout (Unicode braille dot numbering):\n"
" col 0 col 1\n"
" row 0 1 8\n"
" row 1 2 16\n"
" row 2 4 32\n"
" row 3 64 128\n"
).
-spec bit(integer(), integer()) -> integer().
bit(Col, Row) ->
case {Col, Row} of
{0, 0} ->
1;
{0, 1} ->
2;
{0, 2} ->
4;
{0, 3} ->
64;
{1, 0} ->
8;
{1, 1} ->
16;
{1, 2} ->
32;
{1, 3} ->
128;
{_, _} ->
0
end.
-file("src/etui/braille.gleam", 64).
?DOC(
" Write a single pixel at absolute braille-pixel coords (px, py) into the\n"
" pixel grid. Out-of-bounds coords (px < 0 or py < 0) are dropped.\n"
).
-spec put(
gleam@dict:dict({integer(), integer()}, {integer(), etui@style:color()}),
integer(),
integer(),
etui@style:color()
) -> gleam@dict:dict({integer(), integer()}, {integer(), etui@style:color()}).
put(Pixels, Px, Py, Fg) ->
case (Px < 0) orelse (Py < 0) of
true ->
Pixels;
false ->
set_pixel(Pixels, Px div 2, Py div 4, bit(Px rem 2, Py rem 4), Fg)
end.
-file("src/etui/braille.gleam", 73).
?DOC(
" Flush the pixel grid into a buffer at the given area's origin.\n"
" Each populated cell becomes one braille glyph.\n"
).
-spec flush(
etui@buffer:buffer(),
etui@geometry:rect(),
gleam@dict:dict({integer(), integer()}, {integer(), etui@style:color()}),
etui@style:color()
) -> etui@buffer:buffer().
flush(Buf, Area, Pixels, Bg) ->
gleam@dict:fold(
Pixels,
Buf,
fun(B, Key, Val) ->
{Char_x, Char_y} = Key,
{Mask, Fg} = Val,
Ch = case gleam@string:utf_codepoint(16#2800 + Mask) of
{ok, Cp} ->
gleam_stdlib:utf_codepoint_list_to_string([Cp]);
{error, _} ->
<<"·"/utf8>>
end,
etui@buffer:set_string(
B,
{position,
erlang:element(2, erlang:element(2, Area)) + Char_x,
erlang:element(3, erlang:element(2, Area)) + Char_y},
Ch,
Fg,
Bg,
etui@style:none()
)
end
).