-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 ).