-module(etui@color).
-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]).
-define(FILEPATH, "src/etui/color.gleam").
-export([lerp_rgb/4, hue_to_rgb/1, rainbow/2, gradient/3, pulse/3, scale/2]).
-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/color.gleam", 13).
?DOC(
" Linear interpolation between two Rgb colors.\n"
" For non-Rgb inputs, returns whichever endpoint is closer to t.\n"
).
-spec lerp_rgb(etui@style:color(), etui@style:color(), integer(), integer()) -> etui@style:color().
lerp_rgb(A, B, T, Max) ->
case {A, B} of
{{rgb, R1, G1, B1}, {rgb, R2, G2, B2}} ->
{rgb,
etui@anim:lerp(R1, R2, T, Max),
etui@anim:lerp(G1, G2, T, Max),
etui@anim:lerp(B1, B2, T, Max)};
{_, _} ->
case (T * 2) < Max of
true ->
A;
false ->
B
end
end.
-file("src/etui/color.gleam", 39).
?DOC(
" Convert a hue angle (0–359) to a fully-saturated Rgb color.\n"
" Implements the HSV→RGB formula with S=1, V=1, integer arithmetic.\n"
).
-spec hue_to_rgb(integer()) -> etui@style:color().
hue_to_rgb(Hue) ->
H = ((Hue rem 360) + 360) rem 360,
Sector = H div 60,
F = H rem 60,
Up = (F * 255) div 60,
Dn = ((60 - F) * 255) div 60,
case Sector of
0 ->
{rgb, 255, Up, 0};
1 ->
{rgb, Dn, 255, 0};
2 ->
{rgb, 0, 255, Up};
3 ->
{rgb, 0, Dn, 255};
4 ->
{rgb, Up, 0, 255};
_ ->
{rgb, 255, 0, Dn}
end.
-file("src/etui/color.gleam", 60).
?DOC(
" Returns an Rgb color that cycles through the full hue spectrum\n"
" with the given period in frames.\n"
).
-spec rainbow(integer(), integer()) -> etui@style:color().
rainbow(Frame, Period) ->
P = gleam@int:max(1, Period),
hue_to_rgb(case P of
0 -> 0;
Gleam@denominator -> etui@anim:cycle(Frame, P) * 360 div Gleam@denominator
end).
-file("src/etui/color.gleam", 127).
-spec get_nth(list(etui@style:color()), integer()) -> etui@style:color().
get_nth(Colors, N) ->
case Colors of
[] ->
default;
[C | _] when N =< 0 ->
C;
[_ | Rest] ->
get_nth(Rest, N - 1)
end.
-file("src/etui/color.gleam", 71).
?DOC(
" Color at integer position `pos` within [0, max] across a list of\n"
" color stops. Stops are distributed evenly. Lerps between adjacent\n"
" stops. Requires Rgb stops for smooth blending; non-Rgb stops snap.\n"
).
-spec gradient(list(etui@style:color()), integer(), integer()) -> etui@style:color().
gradient(Stops, Pos, Max) ->
N = erlang:length(Stops),
case N of
0 ->
default;
1 ->
case Stops of
[C | _] ->
C;
[] ->
default
end;
_ ->
Segs = N - 1,
Seg_size = gleam@int:max(1, case Segs of
0 -> 0;
Gleam@denominator -> Max div Gleam@denominator
end),
Seg_idx = gleam@int:min(Segs - 1, case Seg_size of
0 -> 0;
Gleam@denominator@1 -> Pos div Gleam@denominator@1
end),
Seg_pos = Pos - (Seg_idx * Seg_size),
lerp_rgb(
get_nth(Stops, Seg_idx),
get_nth(Stops, Seg_idx + 1),
Seg_pos,
Seg_size
)
end.
-file("src/etui/color.gleam", 101).
?DOC(
" Oscillate an Rgb color between half and full brightness.\n"
" Use `frame + x * phase_step` for a per-cell wave effect.\n"
" Non-Rgb colors are returned unchanged.\n"
).
-spec pulse(etui@style:color(), integer(), integer()) -> etui@style:color().
pulse(C, Frame, Period) ->
case C of
{rgb, R, G, B} ->
Bright = etui@anim:oscillate(
128,
255,
Frame,
gleam@int:max(1, Period)
),
{rgb,
(R * Bright) div 255,
(G * Bright) div 255,
(B * Bright) div 255};
_ ->
C
end.
-file("src/etui/color.gleam", 116).
?DOC(
" Scale all RGB channels by `factor` / 255.\n"
" factor=255 → unchanged, factor=128 → half brightness.\n"
).
-spec scale(etui@style:color(), integer()) -> etui@style:color().
scale(C, Factor) ->
case C of
{rgb, R, G, B} ->
{rgb,
(R * Factor) div 255,
(G * Factor) div 255,
(B * Factor) div 255};
_ ->
C
end.