From 3e9bc7531cf651036248f482a683c17baf639404 Mon Sep 17 00:00:00 2001 From: a2n-s <44101798+AntoineStevan@users.noreply.github.com> Date: Wed, 29 Jun 2022 19:56:02 +0200 Subject: [PATCH 01/19] add a script to automatically compute color gradients --- scripts/a2n-s-compute-color-gradient | 161 +++++++++++++++++++++++++++ 1 file changed, 161 insertions(+) create mode 100755 scripts/a2n-s-compute-color-gradient diff --git a/scripts/a2n-s-compute-color-gradient b/scripts/a2n-s-compute-color-gradient new file mode 100755 index 0000000..0847db9 --- /dev/null +++ b/scripts/a2n-s-compute-color-gradient @@ -0,0 +1,161 @@ +#!/usr/bin/env python3 + +import argparse +import numpy as np +from tqdm import trange + +Color = str + + +def is_valid_color(color: Color) -> bool: + return color.startswith("#") and len(color) == 7 + + +def is_valid_rgb(red: int, green: int, blue: int) -> bool: + return (0 <= red <= 255) and (0 <= green <= 255) and (0 <= blue <= 255) + + +def make_random_color() -> Color: + return int_to_color( + np.random.randint(0, 256), np.random.randint(0, 256), np.random.randint(0, 256) + ) + + +def int_to_color(red: int, green: int, blue: int) -> Color: + if not is_valid_rgb(red, green, blue): + raise ValueError( + "Channels should be between 0 and 255, " + f"got '{red}', '{green}' and '{blue}'." + ) + + color = hex((red << 16) + (green << 8) + (blue << 0)).replace("0x", "") + return f"#{color:>06}" + + +def color_to_int(color: Color) -> (int, int, int): + if not is_valid_color(color): + raise ValueError(f"'color' is not valid, got '{color}'") + return ( + int(f"0x{color[1:3]}", base=16), + int(f"0x{color[3:5]}", base=16), + int(f"0x{color[5:7]}", base=16), + ) + + +def compute_color_gradient( + c1: Color, + c2: Color, + *, + nb_colors: int = 2, + reverse: bool = False, + verbose: bool = False, +): + if nb_colors < 2: + raise ValueError(f"'nb_colors' should be at least 2, got '{nb_colors}'.") + r1, g1, b1 = color_to_int(c1) + r2, g2, b2 = color_to_int(c2) + if verbose: + print(f"{c1} -> ({r1}, {g1}, {b1})") + print(f"{c2} -> ({r2}, {g2}, {b2})") + red_gradient = np.linspace(r1, r2, nb_colors).astype(int) + green_gradient = np.linspace(g1, g2, nb_colors).astype(int) + blue_gradient = np.linspace(b1, b2, nb_colors).astype(int) + if verbose: + print(f"red: {red_gradient}") + print(f"green: {green_gradient}") + print(f"blue: {blue_gradient}") + ziped_gradients = list(zip(red_gradient, green_gradient, blue_gradient)) + if reverse: + ziped_gradients = reversed(ziped_gradients) + return [int_to_color(r, g, b) for (r, g, b) in ziped_gradients] + + +def test(): + for r in trange(256, desc="Testing the color conversions"): + for g in range(256): + for b in range(256): + assert (r, g, b) == color_to_int(int_to_color(r, g, b)) + print("Tests are successful!!") + + +if __name__ == "__main__": + parser = argparse.ArgumentParser() + parser.add_argument( + "-1", + "--color_1", + type=str, + default="#ff0000", + help=( + "the first color of the gradient of the form '#rrggbb' " + "(defaults to red, i.e '#ff0000')." + ), + ) + parser.add_argument( + "-2", + "--color_2", + type=str, + default="#00ff00", + help=( + "the first color of the gradient of the form '#rrggbb' " + "(defaults to green, i.e '#00ff00')." + ), + ) + parser.add_argument( + "-n", + "--nb_colors", + type=int, + default=8, + help=( + "the total number of colors in the gradient, including the two " + "end colors (defaults to '8')." + ), + ) + parser.add_argument( + "-r", + "--reverse", + action="store_true", + help="print the gradient in reverse (defaults to 'False').", + ) + parser.add_argument( + "-R", + "--random_colors", + action="store_true", + help=( + "use random colors for the two ends of the gradient " + "(defaults to 'False'). Overwrites -1 and -2." + ), + ) + parser.add_argument( + "-v", + "--verbose", + action="store_true", + help="be more verbose (defaults to 'False').", + ) + parser.add_argument( + "-t", + "--test", + action="store_true", + help="run the tests (defaults to 'False').", + ) + + args = parser.parse_args() + + if args.test: + test() + else: + if args.random_colors: + color_1 = make_random_color() + color_2 = make_random_color() + else: + color_1 = args.color_1 + color_2 = args.color_2 + + color_gradient = compute_color_gradient( + color_1, + color_2, + nb_colors=args.nb_colors, + reverse=args.reverse, + verbose=args.verbose, + ) + + print(" ".join(color_gradient)) From c88419ecad3d37fbff768388137679377afff98a Mon Sep 17 00:00:00 2001 From: a2n-s <44101798+AntoineStevan@users.noreply.github.com> Date: Wed, 29 Jun 2022 22:18:24 +0200 Subject: [PATCH 02/19] add the possibility to compute complitely random colors --- ...r-gradient => a2n-s-compute-color-palette} | 40 ++++++++++++------- 1 file changed, 26 insertions(+), 14 deletions(-) rename scripts/{a2n-s-compute-color-gradient => a2n-s-compute-color-palette} (83%) diff --git a/scripts/a2n-s-compute-color-gradient b/scripts/a2n-s-compute-color-palette similarity index 83% rename from scripts/a2n-s-compute-color-gradient rename to scripts/a2n-s-compute-color-palette index 0847db9..df04190 100755 --- a/scripts/a2n-s-compute-color-gradient +++ b/scripts/a2n-s-compute-color-palette @@ -117,14 +117,23 @@ if __name__ == "__main__": help="print the gradient in reverse (defaults to 'False').", ) parser.add_argument( - "-R", - "--random_colors", + "-G", + "--random_gradient", action="store_true", help=( "use random colors for the two ends of the gradient " "(defaults to 'False'). Overwrites -1 and -2." ), ) + parser.add_argument( + "-R", + "--random_colors", + action="store_true", + help=( + "use random colors for the whole gradient " + "(defaults to 'False'). Overwrites -G, -1 and -2." + ), + ) parser.add_argument( "-v", "--verbose", @@ -144,18 +153,21 @@ if __name__ == "__main__": test() else: if args.random_colors: - color_1 = make_random_color() - color_2 = make_random_color() + color_gradient = [make_random_color() for _ in range(args.nb_colors)] else: - color_1 = args.color_1 - color_2 = args.color_2 - - color_gradient = compute_color_gradient( - color_1, - color_2, - nb_colors=args.nb_colors, - reverse=args.reverse, - verbose=args.verbose, - ) + if args.random_gradient: + color_1 = make_random_color() + color_2 = make_random_color() + else: + color_1 = args.color_1 + color_2 = args.color_2 + + color_gradient = compute_color_gradient( + color_1, + color_2, + nb_colors=args.nb_colors, + reverse=args.reverse, + verbose=args.verbose, + ) print(" ".join(color_gradient)) From 9efc5500572c0ab4f7f92cfe301d5bfce28e65dd Mon Sep 17 00:00:00 2001 From: a2n-s <44101798+AntoineStevan@users.noreply.github.com> Date: Sat, 9 Jul 2022 12:56:34 +0200 Subject: [PATCH 03/19] add tests for the random color generation --- scripts/a2n-s-compute-color-palette | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/scripts/a2n-s-compute-color-palette b/scripts/a2n-s-compute-color-palette index df04190..185d73c 100755 --- a/scripts/a2n-s-compute-color-palette +++ b/scripts/a2n-s-compute-color-palette @@ -42,6 +42,16 @@ def color_to_int(color: Color) -> (int, int, int): ) +def test(): + for r in trange(256, desc="Testing the color conversions"): + for g in range(256): + for b in range(256): + assert (r, g, b) == color_to_int(int_to_color(r, g, b)) + for i in trange(100000, desc="Testing the random color generation"): + assert is_valid_rgb(*color_to_int(make_random_color())) + print("Tests are successful!!") + + def compute_color_gradient( c1: Color, c2: Color, @@ -70,14 +80,6 @@ def compute_color_gradient( return [int_to_color(r, g, b) for (r, g, b) in ziped_gradients] -def test(): - for r in trange(256, desc="Testing the color conversions"): - for g in range(256): - for b in range(256): - assert (r, g, b) == color_to_int(int_to_color(r, g, b)) - print("Tests are successful!!") - - if __name__ == "__main__": parser = argparse.ArgumentParser() parser.add_argument( From 78b4be7aae289d3a15be064fcc89cfb5f159efa0 Mon Sep 17 00:00:00 2001 From: a2n-s <44101798+AntoineStevan@users.noreply.github.com> Date: Sat, 9 Jul 2022 13:35:29 +0200 Subject: [PATCH 04/19] create a whole palette and not just a gradient --- scripts/a2n-s-compute-color-palette | 156 ++++++++++++++++++++-------- 1 file changed, 111 insertions(+), 45 deletions(-) diff --git a/scripts/a2n-s-compute-color-palette b/scripts/a2n-s-compute-color-palette index 185d73c..15da885 100755 --- a/scripts/a2n-s-compute-color-palette +++ b/scripts/a2n-s-compute-color-palette @@ -7,6 +7,53 @@ from tqdm import trange Color = str +PALETTE_NAMES = [ + "bg", + "fg", + "sel_fg", + "sel_bg", + "cursor", + "cl0", + "cl1", + "cl2", + "cl3", + "cl4", + "cl5", + "cl6", + "cl7", + "cl8", + "cl9", + "cl10", + "cl11", + "cl12", + "cl13", + "cl14", + "cl15", +] + +GRADIENT_NAMES = [ + "gd0", + "gd1", + "gd2", + "gd3", + "gd4", + "gd5", + "gd6", + "gd7", + "gd8", + "gd9", + "gd10", + "gd11", + "gd12", + "gd13", + "gd14", + "gd15", + "gd15", +] + +NAMES = PALETTE_NAMES + GRADIENT_NAMES + + def is_valid_color(color: Color) -> bool: return color.startswith("#") and len(color) == 7 @@ -15,12 +62,6 @@ def is_valid_rgb(red: int, green: int, blue: int) -> bool: return (0 <= red <= 255) and (0 <= green <= 255) and (0 <= blue <= 255) -def make_random_color() -> Color: - return int_to_color( - np.random.randint(0, 256), np.random.randint(0, 256), np.random.randint(0, 256) - ) - - def int_to_color(red: int, green: int, blue: int) -> Color: if not is_valid_rgb(red, green, blue): raise ValueError( @@ -42,14 +83,19 @@ def color_to_int(color: Color) -> (int, int, int): ) -def test(): - for r in trange(256, desc="Testing the color conversions"): - for g in range(256): - for b in range(256): - assert (r, g, b) == color_to_int(int_to_color(r, g, b)) - for i in trange(100000, desc="Testing the random color generation"): - assert is_valid_rgb(*color_to_int(make_random_color())) - print("Tests are successful!!") +def make_random_color() -> Color: + return int_to_color( + np.random.randint(0, 256), np.random.randint(0, 256), np.random.randint(0, 256) + ) + + +def make_random_colors(names): + return dict( + zip( + names, + [make_random_color() for _ in range(len(names))], + ) + ) def compute_color_gradient( @@ -80,36 +126,36 @@ def compute_color_gradient( return [int_to_color(r, g, b) for (r, g, b) in ziped_gradients] +def test(): + for r in trange(256, desc="Testing the color conversions"): + for g in range(256): + for b in range(256): + assert (r, g, b) == color_to_int(int_to_color(r, g, b)) + for i in trange(100000, desc="Testing the random color generation"): + assert is_valid_rgb(*color_to_int(make_random_color())) + print("Tests are successful!!") + + if __name__ == "__main__": parser = argparse.ArgumentParser() parser.add_argument( "-1", - "--color_1", + "--gds", type=str, default="#ff0000", help=( - "the first color of the gradient of the form '#rrggbb' " - "(defaults to red, i.e '#ff0000')." + f"the first color of the gradient, i.e. \"{GRADIENT_NAMES[0]}\", " + "of the form '#rrggbb' (defaults to red, i.e '#ff0000')." ), ) parser.add_argument( "-2", - "--color_2", + "--gde", type=str, default="#00ff00", help=( - "the first color of the gradient of the form '#rrggbb' " - "(defaults to green, i.e '#00ff00')." - ), - ) - parser.add_argument( - "-n", - "--nb_colors", - type=int, - default=8, - help=( - "the total number of colors in the gradient, including the two " - "end colors (defaults to '8')." + f"the last color of the gradient, i.e. \"{GRADIENT_NAMES[-1]}\", " + "of the form '#rrggbb' (defaults to green, i.e '#00ff00')." ), ) parser.add_argument( @@ -123,16 +169,18 @@ if __name__ == "__main__": "--random_gradient", action="store_true", help=( - "use random colors for the two ends of the gradient " + "use random colors for the two ends of the gradient, i.e. \"gd0\" " + "to \"gd15\" keys " "(defaults to 'False'). Overwrites -1 and -2." ), ) parser.add_argument( "-R", - "--random_colors", + "--random_palette", action="store_true", help=( - "use random colors for the whole gradient " + "use random colors for the whole palette, i.e. all the keys in " + f"'{', '.join(NAMES)}' " "(defaults to 'False'). Overwrites -G, -1 and -2." ), ) @@ -154,22 +202,40 @@ if __name__ == "__main__": if args.test: test() else: - if args.random_colors: - color_gradient = [make_random_color() for _ in range(args.nb_colors)] + if args.random_palette: + palette = make_random_colors(names=NAMES) else: + colors = make_random_colors(names=PALETTE_NAMES) + if args.random_gradient: - color_1 = make_random_color() - color_2 = make_random_color() + gd_start = make_random_color() + gd_end = make_random_color() else: - color_1 = args.color_1 - color_2 = args.color_2 - - color_gradient = compute_color_gradient( - color_1, - color_2, - nb_colors=args.nb_colors, + gd_start = args.gds + gd_end = args.gde + + if is_valid_color(f"#{gd_start}"): + gd_start = "#" + gd_start + if is_valid_color(f"#{gd_end}"): + gd_end = "#" + gd_end + + assert is_valid_color(gd_start) or gd_start in PALETTE_NAMES + assert is_valid_color(gd_end) or gd_end in PALETTE_NAMES + + if not is_valid_color(gd_start): + gd_start = colors[gd_start] + if not is_valid_color(gd_end): + gd_end = colors[gd_end] + + gradient_colors = compute_color_gradient( + gd_start, + gd_end, + nb_colors=len(GRADIENT_NAMES), reverse=args.reverse, verbose=args.verbose, ) + color_gradient = dict(zip(GRADIENT_NAMES, gradient_colors)) + + palette = {**colors, **color_gradient} - print(" ".join(color_gradient)) + print("\n".join([f"{key}:{value}" for key, value in palette.items()])) From f1d0fdb1a47ea370dd45f89b95ca5c8decb2746c Mon Sep 17 00:00:00 2001 From: a2n-s <44101798+AntoineStevan@users.noreply.github.com> Date: Sat, 9 Jul 2022 13:55:00 +0200 Subject: [PATCH 05/19] refactor into functions and add doc or TODOs --- scripts/a2n-s-compute-color-palette | 83 +++++++++++++++++++---------- 1 file changed, 55 insertions(+), 28 deletions(-) diff --git a/scripts/a2n-s-compute-color-palette b/scripts/a2n-s-compute-color-palette index 15da885..7c3d5c3 100755 --- a/scripts/a2n-s-compute-color-palette +++ b/scripts/a2n-s-compute-color-palette @@ -55,14 +55,17 @@ NAMES = PALETTE_NAMES + GRADIENT_NAMES def is_valid_color(color: Color) -> bool: + """TODO.""" return color.startswith("#") and len(color) == 7 def is_valid_rgb(red: int, green: int, blue: int) -> bool: + """TODO.""" return (0 <= red <= 255) and (0 <= green <= 255) and (0 <= blue <= 255) def int_to_color(red: int, green: int, blue: int) -> Color: + """TODO.""" if not is_valid_rgb(red, green, blue): raise ValueError( "Channels should be between 0 and 255, " @@ -74,6 +77,7 @@ def int_to_color(red: int, green: int, blue: int) -> Color: def color_to_int(color: Color) -> (int, int, int): + """TODO.""" if not is_valid_color(color): raise ValueError(f"'color' is not valid, got '{color}'") return ( @@ -83,13 +87,20 @@ def color_to_int(color: Color) -> (int, int, int): ) +def complete_color_representation(color: str) -> Color: + """TODO.""" + return f"#{color}" if is_valid_color(f"#{color}") else color + + def make_random_color() -> Color: + """TODO.""" return int_to_color( np.random.randint(0, 256), np.random.randint(0, 256), np.random.randint(0, 256) ) def make_random_colors(names): + """TODO.""" return dict( zip( names, @@ -98,6 +109,24 @@ def make_random_colors(names): ) +def get_gradient_end_points(theme, args): + """TODO.""" + if args.random_gradient: + gradient_start = make_random_color() + gradient_end = make_random_color() + else: + # get the colors given as arguments. + gradient_start = complete_color_representation(args.gds) + gradient_end = complete_color_representation(args.gde) + + if not is_valid_color(gradient_start): + gradient_start = theme[gradient_start] + if not is_valid_color(gradient_end): + gradient_end = theme[gradient_end] + + return gradient_start, gradient_end + + def compute_color_gradient( c1: Color, c2: Color, @@ -106,6 +135,7 @@ def compute_color_gradient( reverse: bool = False, verbose: bool = False, ): + """TODO.""" if nb_colors < 2: raise ValueError(f"'nb_colors' should be at least 2, got '{nb_colors}'.") r1, g1, b1 = color_to_int(c1) @@ -127,6 +157,7 @@ def compute_color_gradient( def test(): + """TODO.""" for r in trange(256, desc="Testing the color conversions"): for g in range(256): for b in range(256): @@ -137,7 +168,14 @@ def test(): if __name__ == "__main__": - parser = argparse.ArgumentParser() + parser = argparse.ArgumentParser( + description=( + f"{PALETTE_NAMES = }" + "\n" + f"{GRADIENT_NAMES = }" + ), + formatter_class=argparse.RawTextHelpFormatter + ) parser.add_argument( "-1", "--gds", @@ -145,7 +183,8 @@ if __name__ == "__main__": default="#ff0000", help=( f"the first color of the gradient, i.e. \"{GRADIENT_NAMES[0]}\", " - "of the form '#rrggbb' (defaults to red, i.e '#ff0000')." + "of the form '#rrggbb' or a name in 'PALETTE_NAMES' " + "(defaults to red, i.e '#ff0000')." ), ) parser.add_argument( @@ -155,7 +194,8 @@ if __name__ == "__main__": default="#00ff00", help=( f"the last color of the gradient, i.e. \"{GRADIENT_NAMES[-1]}\", " - "of the form '#rrggbb' (defaults to green, i.e '#00ff00')." + "of the form '#rrggbb' or a name in 'PALETTE_NAMES' " + "(defaults to green, i.e '#00ff00')." ), ) parser.add_argument( @@ -169,9 +209,9 @@ if __name__ == "__main__": "--random_gradient", action="store_true", help=( - "use random colors for the two ends of the gradient, i.e. \"gd0\" " - "to \"gd15\" keys " - "(defaults to 'False'). Overwrites -1 and -2." + "use random colors for the two ends of the gradient, i.e. " + f"\"{GRADIENT_NAMES[0]}\" to \"{GRADIENT_NAMES[-1]}\" keys in " + "'GRADIENT_NAMES' (defaults to 'False'). Overwrites -1 and -2." ), ) parser.add_argument( @@ -180,7 +220,7 @@ if __name__ == "__main__": action="store_true", help=( "use random colors for the whole palette, i.e. all the keys in " - f"'{', '.join(NAMES)}' " + "'PALETTE_NAMES' or 'GRADIENT_NAMES' " "(defaults to 'False'). Overwrites -G, -1 and -2." ), ) @@ -203,29 +243,16 @@ if __name__ == "__main__": test() else: if args.random_palette: + # all the colors should be completely random. palette = make_random_colors(names=NAMES) else: - colors = make_random_colors(names=PALETTE_NAMES) - - if args.random_gradient: - gd_start = make_random_color() - gd_end = make_random_color() - else: - gd_start = args.gds - gd_end = args.gde - - if is_valid_color(f"#{gd_start}"): - gd_start = "#" + gd_start - if is_valid_color(f"#{gd_end}"): - gd_end = "#" + gd_end - - assert is_valid_color(gd_start) or gd_start in PALETTE_NAMES - assert is_valid_color(gd_end) or gd_end in PALETTE_NAMES + # TODO: add a real palette generation here. + # NOTE: that will probably be something that generates + # either light or dark with color0 and color8 being slightly red, + # the background following the theme, etc, etc, ... + color_theme = make_random_colors(names=PALETTE_NAMES) - if not is_valid_color(gd_start): - gd_start = colors[gd_start] - if not is_valid_color(gd_end): - gd_end = colors[gd_end] + gd_start, gd_end = get_gradient_end_points(color_theme, args) gradient_colors = compute_color_gradient( gd_start, @@ -236,6 +263,6 @@ if __name__ == "__main__": ) color_gradient = dict(zip(GRADIENT_NAMES, gradient_colors)) - palette = {**colors, **color_gradient} + palette = {**color_theme, **color_gradient} print("\n".join([f"{key}:{value}" for key, value in palette.items()])) From 763766906b9dcebcbfc4579675347540d682c06b Mon Sep 17 00:00:00 2001 From: a2n-s <44101798+AntoineStevan@users.noreply.github.com> Date: Sat, 9 Jul 2022 13:59:31 +0200 Subject: [PATCH 06/19] move the theme generation to function and add light switch --- scripts/a2n-s-compute-color-palette | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/scripts/a2n-s-compute-color-palette b/scripts/a2n-s-compute-color-palette index 7c3d5c3..cf2e259 100755 --- a/scripts/a2n-s-compute-color-palette +++ b/scripts/a2n-s-compute-color-palette @@ -109,6 +109,11 @@ def make_random_colors(names): ) +def make_color_theme(light: bool = False): + """TODO.""" + return make_random_colors(names=PALETTE_NAMES) + + def get_gradient_end_points(theme, args): """TODO.""" if args.random_gradient: @@ -198,6 +203,12 @@ if __name__ == "__main__": "(defaults to green, i.e '#00ff00')." ), ) + parser.add_argument( + "-l", + "--light", + action="store_true", + help="turns on light theme mode (defaults to false, i.e dark theme).", + ) parser.add_argument( "-r", "--reverse", @@ -246,11 +257,7 @@ if __name__ == "__main__": # all the colors should be completely random. palette = make_random_colors(names=NAMES) else: - # TODO: add a real palette generation here. - # NOTE: that will probably be something that generates - # either light or dark with color0 and color8 being slightly red, - # the background following the theme, etc, etc, ... - color_theme = make_random_colors(names=PALETTE_NAMES) + color_theme = make_color_theme(light=args.light) gd_start, gd_end = get_gradient_end_points(color_theme, args) From 1146866c324cdee0771dcef6bc5e196a9e73532c Mon Sep 17 00:00:00 2001 From: a2n-s <44101798+AntoineStevan@users.noreply.github.com> Date: Sat, 9 Jul 2022 15:12:01 +0200 Subject: [PATCH 07/19] add a flag to get only the gradient --- scripts/a2n-s-compute-color-palette | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/scripts/a2n-s-compute-color-palette b/scripts/a2n-s-compute-color-palette index cf2e259..00a1cdb 100755 --- a/scripts/a2n-s-compute-color-palette +++ b/scripts/a2n-s-compute-color-palette @@ -203,6 +203,12 @@ if __name__ == "__main__": "(defaults to green, i.e '#00ff00')." ), ) + parser.add_argument( + "-g", + "--gradient_only", + action="store_true", + help="print the gradient only (defaults to 'False').", + ) parser.add_argument( "-l", "--light", @@ -270,6 +276,9 @@ if __name__ == "__main__": ) color_gradient = dict(zip(GRADIENT_NAMES, gradient_colors)) - palette = {**color_theme, **color_gradient} + if args.gradient_only: + palette = color_gradient + else: + palette = {**color_theme, **color_gradient} print("\n".join([f"{key}:{value}" for key, value in palette.items()])) From 00cdc1d459060a780bd8bcacc77c3c0305be029b Mon Sep 17 00:00:00 2001 From: a2n-s <44101798+AntoineStevan@users.noreply.github.com> Date: Sat, 9 Jul 2022 15:56:57 +0200 Subject: [PATCH 08/19] add a simple default theme generation --- scripts/a2n-s-compute-color-palette | 130 ++++++++++++++++++---------- 1 file changed, 82 insertions(+), 48 deletions(-) diff --git a/scripts/a2n-s-compute-color-palette b/scripts/a2n-s-compute-color-palette index 00a1cdb..a2cf094 100755 --- a/scripts/a2n-s-compute-color-palette +++ b/scripts/a2n-s-compute-color-palette @@ -3,57 +3,11 @@ import argparse import numpy as np from tqdm import trange +import colorsys Color = str -PALETTE_NAMES = [ - "bg", - "fg", - "sel_fg", - "sel_bg", - "cursor", - "cl0", - "cl1", - "cl2", - "cl3", - "cl4", - "cl5", - "cl6", - "cl7", - "cl8", - "cl9", - "cl10", - "cl11", - "cl12", - "cl13", - "cl14", - "cl15", -] - -GRADIENT_NAMES = [ - "gd0", - "gd1", - "gd2", - "gd3", - "gd4", - "gd5", - "gd6", - "gd7", - "gd8", - "gd9", - "gd10", - "gd11", - "gd12", - "gd13", - "gd14", - "gd15", - "gd15", -] - -NAMES = PALETTE_NAMES + GRADIENT_NAMES - - def is_valid_color(color: Color) -> bool: """TODO.""" return color.startswith("#") and len(color) == 7 @@ -109,9 +63,89 @@ def make_random_colors(names): ) +PALETTE_NAMES = [ + "bg", + "fg", + "sel_bg", + "sel_fg", + "cursor", + "cl0", + "cl1", + "cl2", + "cl3", + "cl4", + "cl5", + "cl6", + "cl7", + "cl8", + "cl9", + "cl10", + "cl11", + "cl12", + "cl13", + "cl14", + "cl15", +] + +GRADIENT_NAMES = [ + "gd0", + "gd1", + "gd2", + "gd3", + "gd4", + "gd5", + "gd6", + "gd7", + "gd8", + "gd9", + "gd10", + "gd11", + "gd12", + "gd13", + "gd14", + "gd15", + "gd15", +] + +NAMES = PALETTE_NAMES + GRADIENT_NAMES + + def make_color_theme(light: bool = False): """TODO.""" - return make_random_colors(names=PALETTE_NAMES) + hsv_black = colorsys.rgb_to_hsv(0.0, 0.0, 0.0) + hsv_grey = colorsys.rgb_to_hsv(0.2, 0.2, 0.2) + hsv_red = colorsys.rgb_to_hsv(1.0, 0.0, 0.0) + hsv_green = colorsys.rgb_to_hsv(0.0, 1.0, 0.0) + hsv_yellow = colorsys.rgb_to_hsv(1.0, 1.0, 0.0) + hsv_blue = colorsys.rgb_to_hsv(0.0, 0.0, 1.0) + hsv_magenta = colorsys.rgb_to_hsv(1.0, 0.0, 1.0) + hsv_cyan = colorsys.rgb_to_hsv(0.0, 1.0, 1.0) + hsv_white = colorsys.rgb_to_hsv(1.0, 1.0, 1.0) + color_theme = { + "bg": hsv_black, + "fg": hsv_white, + "sel_bg": hsv_white, + "sel_fg": hsv_black, + "cursor": hsv_white, + "cl8": hsv_grey, + "cl9": hsv_red, + "cl10": hsv_green, + "cl11": hsv_yellow, + "cl12": hsv_blue, + "cl13": hsv_magenta, + "cl14": hsv_cyan, + "cl15": hsv_white, + } + color_theme["cl0"] = tuple(np.array([1, 1, .8]) * np.array(color_theme["cl8"])) + color_theme["cl1"] = tuple(np.array([1, 1, .8]) * np.array(color_theme["cl9"])) + color_theme["cl2"] = tuple(np.array([1, 1, .8]) * np.array(color_theme["cl10"])) + color_theme["cl3"] = tuple(np.array([1, 1, .8]) * np.array(color_theme["cl11"])) + color_theme["cl4"] = tuple(np.array([1, 1, .8]) * np.array(color_theme["cl12"])) + color_theme["cl5"] = tuple(np.array([1, 1, .8]) * np.array(color_theme["cl13"])) + color_theme["cl6"] = tuple(np.array([1, 1, .8]) * np.array(color_theme["cl14"])) + color_theme["cl7"] = tuple(np.array([1, 1, .8]) * np.array(color_theme["cl15"])) + + return {key: int_to_color(*(np.array(colorsys.hsv_to_rgb(*value)) * 255).astype(int)) for key, value in color_theme.items()} def get_gradient_end_points(theme, args): From 96c7a8c4e8f3b0a31094b30ecde344a58525fe55 Mon Sep 17 00:00:00 2001 From: a2n-s <44101798+AntoineStevan@users.noreply.github.com> Date: Sat, 9 Jul 2022 16:46:11 +0200 Subject: [PATCH 09/19] add missing documentation --- scripts/a2n-s-compute-color-palette | 92 ++++++++++++++++++----------- 1 file changed, 58 insertions(+), 34 deletions(-) diff --git a/scripts/a2n-s-compute-color-palette b/scripts/a2n-s-compute-color-palette index a2cf094..1879173 100755 --- a/scripts/a2n-s-compute-color-palette +++ b/scripts/a2n-s-compute-color-palette @@ -1,4 +1,5 @@ #!/usr/bin/env python3 +from typing import List, Dict, Tuple import argparse import numpy as np @@ -6,20 +7,21 @@ from tqdm import trange import colorsys Color = str +Args = argparse.Namespace def is_valid_color(color: Color) -> bool: - """TODO.""" + """Check if a color is valid, i.e. of the form '#rrggbb'.""" return color.startswith("#") and len(color) == 7 def is_valid_rgb(red: int, green: int, blue: int) -> bool: - """TODO.""" + """Check if each r, g and gb channels are integers between 0 and 255.""" return (0 <= red <= 255) and (0 <= green <= 255) and (0 <= blue <= 255) def int_to_color(red: int, green: int, blue: int) -> Color: - """TODO.""" + """Convert the R, G and B channels into a valid Color.""" if not is_valid_rgb(red, green, blue): raise ValueError( "Channels should be between 0 and 255, " @@ -31,7 +33,7 @@ def int_to_color(red: int, green: int, blue: int) -> Color: def color_to_int(color: Color) -> (int, int, int): - """TODO.""" + """Convert a Color into its R, G and B channels.""" if not is_valid_color(color): raise ValueError(f"'color' is not valid, got '{color}'") return ( @@ -42,19 +44,19 @@ def color_to_int(color: Color) -> (int, int, int): def complete_color_representation(color: str) -> Color: - """TODO.""" + """Add a '#' in front of a color is it is one indeed.""" return f"#{color}" if is_valid_color(f"#{color}") else color def make_random_color() -> Color: - """TODO.""" + """Make a valid completely random color.""" return int_to_color( np.random.randint(0, 256), np.random.randint(0, 256), np.random.randint(0, 256) ) -def make_random_colors(names): - """TODO.""" +def make_random_colors(names: List[str]) -> Dict[str, Color]: + """Make a bunch of completely random colors, indexed by the names.""" return dict( zip( names, @@ -110,8 +112,13 @@ GRADIENT_NAMES = [ NAMES = PALETTE_NAMES + GRADIENT_NAMES -def make_color_theme(light: bool = False): - """TODO.""" +def make_color_theme(*, light: bool = False) -> Dict[str, Color]: + """Make a full color theme centered around sensible colors. + + Args: + light: tell whether to use a light theme or not. + """ + # define some color constants. hsv_black = colorsys.rgb_to_hsv(0.0, 0.0, 0.0) hsv_grey = colorsys.rgb_to_hsv(0.2, 0.2, 0.2) hsv_red = colorsys.rgb_to_hsv(1.0, 0.0, 0.0) @@ -136,20 +143,30 @@ def make_color_theme(light: bool = False): "cl14": hsv_cyan, "cl15": hsv_white, } - color_theme["cl0"] = tuple(np.array([1, 1, .8]) * np.array(color_theme["cl8"])) - color_theme["cl1"] = tuple(np.array([1, 1, .8]) * np.array(color_theme["cl9"])) - color_theme["cl2"] = tuple(np.array([1, 1, .8]) * np.array(color_theme["cl10"])) - color_theme["cl3"] = tuple(np.array([1, 1, .8]) * np.array(color_theme["cl11"])) - color_theme["cl4"] = tuple(np.array([1, 1, .8]) * np.array(color_theme["cl12"])) - color_theme["cl5"] = tuple(np.array([1, 1, .8]) * np.array(color_theme["cl13"])) - color_theme["cl6"] = tuple(np.array([1, 1, .8]) * np.array(color_theme["cl14"])) - color_theme["cl7"] = tuple(np.array([1, 1, .8]) * np.array(color_theme["cl15"])) - return {key: int_to_color(*(np.array(colorsys.hsv_to_rgb(*value)) * 255).astype(int)) for key, value in color_theme.items()} + # alter the color a little to complete the theme. + color_theme["cl0"] = tuple(np.array([1, 1, 0.8]) * np.array(color_theme["cl8"])) + color_theme["cl1"] = tuple(np.array([1, 1, 0.8]) * np.array(color_theme["cl9"])) + color_theme["cl2"] = tuple(np.array([1, 1, 0.8]) * np.array(color_theme["cl10"])) + color_theme["cl3"] = tuple(np.array([1, 1, 0.8]) * np.array(color_theme["cl11"])) + color_theme["cl4"] = tuple(np.array([1, 1, 0.8]) * np.array(color_theme["cl12"])) + color_theme["cl5"] = tuple(np.array([1, 1, 0.8]) * np.array(color_theme["cl13"])) + color_theme["cl6"] = tuple(np.array([1, 1, 0.8]) * np.array(color_theme["cl14"])) + color_theme["cl7"] = tuple(np.array([1, 1, 0.8]) * np.array(color_theme["cl15"])) + + # convert the theme back to its + return { + key: int_to_color(*(np.array(colorsys.hsv_to_rgb(*value)) * 255).astype(int)) + for key, value in color_theme.items() + } -def get_gradient_end_points(theme, args): - """TODO.""" +def get_gradient_end_points( + *, + theme: Dict[str, Color], + args: Args, +) -> Tuple[Color, Color]: + """Get the two end points of the color gradient from user input.""" if args.random_gradient: gradient_start = make_random_color() gradient_end = make_random_color() @@ -158,6 +175,9 @@ def get_gradient_end_points(theme, args): gradient_start = complete_color_representation(args.gds) gradient_end = complete_color_representation(args.gde) + # use the pre-computed values inside the theme if the colors + # given as arguments are not valid... they might just be the + # color keys for the other colors of the theme. if not is_valid_color(gradient_start): gradient_start = theme[gradient_start] if not is_valid_color(gradient_end): @@ -173,8 +193,16 @@ def compute_color_gradient( nb_colors: int = 2, reverse: bool = False, verbose: bool = False, -): - """TODO.""" +) -> List[Color]: + """Compute a color gradient from its two endpoints. + + Args: + c1: the first end point. + c2: the second end point. + nb_colors: the number of colors, c1 and c2 included, in the gradient. + reverse: reverse the gradient. + verbose: turn on verbose mode. + """ if nb_colors < 2: raise ValueError(f"'nb_colors' should be at least 2, got '{nb_colors}'.") r1, g1, b1 = color_to_int(c1) @@ -196,7 +224,7 @@ def compute_color_gradient( def test(): - """TODO.""" + """Run some tests on the above functions.""" for r in trange(256, desc="Testing the color conversions"): for g in range(256): for b in range(256): @@ -208,12 +236,8 @@ def test(): if __name__ == "__main__": parser = argparse.ArgumentParser( - description=( - f"{PALETTE_NAMES = }" - "\n" - f"{GRADIENT_NAMES = }" - ), - formatter_class=argparse.RawTextHelpFormatter + description=(f"{PALETTE_NAMES = }" "\n" f"{GRADIENT_NAMES = }"), + formatter_class=argparse.RawTextHelpFormatter, ) parser.add_argument( "-1", @@ -221,7 +245,7 @@ if __name__ == "__main__": type=str, default="#ff0000", help=( - f"the first color of the gradient, i.e. \"{GRADIENT_NAMES[0]}\", " + f'the first color of the gradient, i.e. "{GRADIENT_NAMES[0]}", ' "of the form '#rrggbb' or a name in 'PALETTE_NAMES' " "(defaults to red, i.e '#ff0000')." ), @@ -232,7 +256,7 @@ if __name__ == "__main__": type=str, default="#00ff00", help=( - f"the last color of the gradient, i.e. \"{GRADIENT_NAMES[-1]}\", " + f'the last color of the gradient, i.e. "{GRADIENT_NAMES[-1]}", ' "of the form '#rrggbb' or a name in 'PALETTE_NAMES' " "(defaults to green, i.e '#00ff00')." ), @@ -261,7 +285,7 @@ if __name__ == "__main__": action="store_true", help=( "use random colors for the two ends of the gradient, i.e. " - f"\"{GRADIENT_NAMES[0]}\" to \"{GRADIENT_NAMES[-1]}\" keys in " + f'"{GRADIENT_NAMES[0]}" to "{GRADIENT_NAMES[-1]}" keys in ' "'GRADIENT_NAMES' (defaults to 'False'). Overwrites -1 and -2." ), ) @@ -299,7 +323,7 @@ if __name__ == "__main__": else: color_theme = make_color_theme(light=args.light) - gd_start, gd_end = get_gradient_end_points(color_theme, args) + gd_start, gd_end = get_gradient_end_points(theme=color_theme, args=args) gradient_colors = compute_color_gradient( gd_start, From 9c1845b9afc719ec443f733dee454019a737be6a Mon Sep 17 00:00:00 2001 From: a2n-s <44101798+AntoineStevan@users.noreply.github.com> Date: Sat, 9 Jul 2022 17:02:44 +0200 Subject: [PATCH 10/19] add some level of effect with the light switch --- scripts/a2n-s-compute-color-palette | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/scripts/a2n-s-compute-color-palette b/scripts/a2n-s-compute-color-palette index 1879173..b2dad1e 100755 --- a/scripts/a2n-s-compute-color-palette +++ b/scripts/a2n-s-compute-color-palette @@ -128,11 +128,18 @@ def make_color_theme(*, light: bool = False) -> Dict[str, Color]: hsv_magenta = colorsys.rgb_to_hsv(1.0, 0.0, 1.0) hsv_cyan = colorsys.rgb_to_hsv(0.0, 1.0, 1.0) hsv_white = colorsys.rgb_to_hsv(1.0, 1.0, 1.0) + + if light: + fg, bg, sel_fg, sel_bg = hsv_black, hsv_white, hsv_white, hsv_black + else: + fg, bg, sel_fg, sel_bg = hsv_white, hsv_black, hsv_black, hsv_white + + # define the base colors of the color theme. color_theme = { - "bg": hsv_black, - "fg": hsv_white, - "sel_bg": hsv_white, - "sel_fg": hsv_black, + "bg": bg, + "fg": fg, + "sel_bg": sel_fg, + "sel_fg": sel_bg, "cursor": hsv_white, "cl8": hsv_grey, "cl9": hsv_red, From e4cb2d2a25ab52153654415d39bfa1b5298ee125 Mon Sep 17 00:00:00 2001 From: a2n-s <44101798+AntoineStevan@users.noreply.github.com> Date: Sat, 9 Jul 2022 17:18:48 +0200 Subject: [PATCH 11/19] make all the colors in the theme real arrays --- scripts/a2n-s-compute-color-palette | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/scripts/a2n-s-compute-color-palette b/scripts/a2n-s-compute-color-palette index b2dad1e..670edb5 100755 --- a/scripts/a2n-s-compute-color-palette +++ b/scripts/a2n-s-compute-color-palette @@ -118,6 +118,7 @@ def make_color_theme(*, light: bool = False) -> Dict[str, Color]: Args: light: tell whether to use a light theme or not. """ + bright_to_normal_value = 0.8 # define some color constants. hsv_black = colorsys.rgb_to_hsv(0.0, 0.0, 0.0) hsv_grey = colorsys.rgb_to_hsv(0.2, 0.2, 0.2) @@ -150,16 +151,14 @@ def make_color_theme(*, light: bool = False) -> Dict[str, Color]: "cl14": hsv_cyan, "cl15": hsv_white, } + for key, value in color_theme.items(): + color_theme[key] = np.array(value) # alter the color a little to complete the theme. - color_theme["cl0"] = tuple(np.array([1, 1, 0.8]) * np.array(color_theme["cl8"])) - color_theme["cl1"] = tuple(np.array([1, 1, 0.8]) * np.array(color_theme["cl9"])) - color_theme["cl2"] = tuple(np.array([1, 1, 0.8]) * np.array(color_theme["cl10"])) - color_theme["cl3"] = tuple(np.array([1, 1, 0.8]) * np.array(color_theme["cl11"])) - color_theme["cl4"] = tuple(np.array([1, 1, 0.8]) * np.array(color_theme["cl12"])) - color_theme["cl5"] = tuple(np.array([1, 1, 0.8]) * np.array(color_theme["cl13"])) - color_theme["cl6"] = tuple(np.array([1, 1, 0.8]) * np.array(color_theme["cl14"])) - color_theme["cl7"] = tuple(np.array([1, 1, 0.8]) * np.array(color_theme["cl15"])) + scale = np.array([1, 1, bright_to_normal_value]) + for id in range(8): + new_value = scale * color_theme[f"cl{id + 8}"] + color_theme[f"cl{id}"] = np.clip(new_value, a_min=0.0, a_max=1.0) # convert the theme back to its return { From 2ee76abcec26afaa80a0ab05d678ddee1808ee8d Mon Sep 17 00:00:00 2001 From: a2n-s <44101798+AntoineStevan@users.noreply.github.com> Date: Sat, 9 Jul 2022 17:36:48 +0200 Subject: [PATCH 12/19] add some deterministic transformations --- scripts/a2n-s-compute-color-palette | 31 +++++++++++++++++++++++++++-- 1 file changed, 29 insertions(+), 2 deletions(-) diff --git a/scripts/a2n-s-compute-color-palette b/scripts/a2n-s-compute-color-palette index 670edb5..9a6079b 100755 --- a/scripts/a2n-s-compute-color-palette +++ b/scripts/a2n-s-compute-color-palette @@ -112,13 +112,29 @@ GRADIENT_NAMES = [ NAMES = PALETTE_NAMES + GRADIENT_NAMES -def make_color_theme(*, light: bool = False) -> Dict[str, Color]: +def make_color_theme( + *, + light: bool = False, + bright_to_normal_value: float = 0.8, + hue_bias: float = 0.0, + hue_focus: float = 1.0, + saturation: float = 1.0, + brightness: float = 1.0, +) -> Dict[str, Color]: """Make a full color theme centered around sensible colors. Args: light: tell whether to use a light theme or not. + bright_to_normal_value: the factor to go from bright to normal on the + brightness. + hue_bias: the amount to rotate around the hue circle. + hue_focus: the focus factor. the bigger the focus, the more the colors + will be centered around the bias. + saturation: the final scaling to apply to the saturation of all the + colors. + brightness: the final scaling to apply to the brightness of all the + colors. """ - bright_to_normal_value = 0.8 # define some color constants. hsv_black = colorsys.rgb_to_hsv(0.0, 0.0, 0.0) hsv_grey = colorsys.rgb_to_hsv(0.2, 0.2, 0.2) @@ -160,6 +176,17 @@ def make_color_theme(*, light: bool = False) -> Dict[str, Color]: new_value = scale * color_theme[f"cl{id + 8}"] color_theme[f"cl{id}"] = np.clip(new_value, a_min=0.0, a_max=1.0) + # rotate the hue a bit. + value_bias = np.array([hue_bias, 0, 0]) + value_scale = np.array([1/hue_focus, 1, 1]) + for key, value in color_theme.items(): + color_theme[key] = value_bias + value * value_scale + + # apply final transformations on the saturation and the brightness. + scale = np.array([1, saturation, brightness]) + for key, value in color_theme.items(): + color_theme[key] = np.clip(scale * value, a_min=0.0, a_max=1.0) + # convert the theme back to its return { key: int_to_color(*(np.array(colorsys.hsv_to_rgb(*value)) * 255).astype(int)) From f1b27145754c4fb894879c3ffd494d2be908ee8b Mon Sep 17 00:00:00 2001 From: a2n-s <44101798+AntoineStevan@users.noreply.github.com> Date: Sun, 10 Jul 2022 10:38:38 +0200 Subject: [PATCH 13/19] remove the clipping on the hue Clipping the saturation and the brightness between 0 and 1 does make sense as these values only leave on that segment. However, the hue value lies on a clock, i.e. 1 wraps back to 0. Thus the script should not clip the hue, otherwise everything tends to turn red when applying a big bias. --- scripts/a2n-s-compute-color-palette | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/scripts/a2n-s-compute-color-palette b/scripts/a2n-s-compute-color-palette index 9a6079b..1e3abb5 100755 --- a/scripts/a2n-s-compute-color-palette +++ b/scripts/a2n-s-compute-color-palette @@ -174,7 +174,7 @@ def make_color_theme( scale = np.array([1, 1, bright_to_normal_value]) for id in range(8): new_value = scale * color_theme[f"cl{id + 8}"] - color_theme[f"cl{id}"] = np.clip(new_value, a_min=0.0, a_max=1.0) + color_theme[f"cl{id}"] = new_value # rotate the hue a bit. value_bias = np.array([hue_bias, 0, 0]) @@ -185,7 +185,12 @@ def make_color_theme( # apply final transformations on the saturation and the brightness. scale = np.array([1, saturation, brightness]) for key, value in color_theme.items(): - color_theme[key] = np.clip(scale * value, a_min=0.0, a_max=1.0) + color_theme[key] = scale * value + + # make sure the saturation and the brightness are between 0 and 1. + for key, value in color_theme.items(): + clipped_value = np.array([value[0], *np.clip(value[1:], a_min=0.0, a_max=1.0)]) + color_theme[key] = clipped_value # convert the theme back to its return { From 5d2628a2f9e36a23f49d2058d720e54e0feafe92 Mon Sep 17 00:00:00 2001 From: a2n-s <44101798+AntoineStevan@users.noreply.github.com> Date: Sun, 10 Jul 2022 10:46:17 +0200 Subject: [PATCH 14/19] add the flags to control the theme generation --- scripts/a2n-s-compute-color-palette | 58 ++++++++++++++++++++++++++++- 1 file changed, 57 insertions(+), 1 deletion(-) diff --git a/scripts/a2n-s-compute-color-palette b/scripts/a2n-s-compute-color-palette index 1e3abb5..4819e71 100755 --- a/scripts/a2n-s-compute-color-palette +++ b/scripts/a2n-s-compute-color-palette @@ -337,6 +337,55 @@ if __name__ == "__main__": "(defaults to 'False'). Overwrites -G, -1 and -2." ), ) + parser.add_argument( + "--bright_to_normal_value", + type=float, + default="0.8", + help=( + "the multiplicative factor to go from bright to normal colors. " + "Should be between 0 and 1 (defaults to 0.8)." + ), + ) + parser.add_argument( + "--hue_bias", + type=float, + default="0.0", + help=( + "the additive bias which rotates the color wheel, can be either " + "negative or positive and values that are 1 apart result in the " + "same rotation of the color wheel (defaults to 0.0)." + ), + ) + parser.add_argument( + "--hue_focus", + type=float, + default="1.0", + help=( + "the multiplicative factor by which the color wheel is dilated. " + "The result is that the colors are then zoomed around the hue " + "bias (defaults to 1.0, i.e. normal focus)." + ), + ) + parser.add_argument( + "--saturation", + type=float, + default="1.0", + help=( + "the multiplicative factor to apply to the saturation at the end. " + "A low value will dilute the colors, a high one will reinforce " + "them (defaults to 1.0)." + ), + ) + parser.add_argument( + "--brightness", + type=float, + default="1.0", + help=( + "the multiplicative factor to go from bright to normal colors. " + "A high value will bump the brightness up, a low one will darken " + "the theme (defaults to 1.0)." + ), + ) parser.add_argument( "-v", "--verbose", @@ -359,7 +408,14 @@ if __name__ == "__main__": # all the colors should be completely random. palette = make_random_colors(names=NAMES) else: - color_theme = make_color_theme(light=args.light) + color_theme = make_color_theme( + light=args.light, + bright_to_normal_value=args.bright_to_normal_value, + hue_bias=args.hue_bias, + hue_focus=args.hue_focus, + saturation=args.saturation, + brightness=args.brightness, + ) gd_start, gd_end = get_gradient_end_points(theme=color_theme, args=args) From f5b7e94992df461265e68e15b7de47ef6c56910b Mon Sep 17 00:00:00 2001 From: a2n-s <44101798+AntoineStevan@users.noreply.github.com> Date: Sun, 10 Jul 2022 10:55:50 +0200 Subject: [PATCH 15/19] put the base colors in the same structure --- scripts/a2n-s-compute-color-palette | 38 +++++++++++++++-------------- 1 file changed, 20 insertions(+), 18 deletions(-) diff --git a/scripts/a2n-s-compute-color-palette b/scripts/a2n-s-compute-color-palette index 4819e71..24a62f3 100755 --- a/scripts/a2n-s-compute-color-palette +++ b/scripts/a2n-s-compute-color-palette @@ -136,15 +136,17 @@ def make_color_theme( colors. """ # define some color constants. - hsv_black = colorsys.rgb_to_hsv(0.0, 0.0, 0.0) - hsv_grey = colorsys.rgb_to_hsv(0.2, 0.2, 0.2) - hsv_red = colorsys.rgb_to_hsv(1.0, 0.0, 0.0) - hsv_green = colorsys.rgb_to_hsv(0.0, 1.0, 0.0) - hsv_yellow = colorsys.rgb_to_hsv(1.0, 1.0, 0.0) - hsv_blue = colorsys.rgb_to_hsv(0.0, 0.0, 1.0) - hsv_magenta = colorsys.rgb_to_hsv(1.0, 0.0, 1.0) - hsv_cyan = colorsys.rgb_to_hsv(0.0, 1.0, 1.0) - hsv_white = colorsys.rgb_to_hsv(1.0, 1.0, 1.0) + base = dict( + hsv_black=colorsys.rgb_to_hsv(0.0, 0.0, 0.0), + hsv_grey=colorsys.rgb_to_hsv(0.2, 0.2, 0.2), + hsv_red=colorsys.rgb_to_hsv(1.0, 0.0, 0.0), + hsv_green=colorsys.rgb_to_hsv(0.0, 1.0, 0.0), + hsv_yellow=colorsys.rgb_to_hsv(1.0, 1.0, 0.0), + hsv_blue=colorsys.rgb_to_hsv(0.0, 0.0, 1.0), + hsv_magenta=colorsys.rgb_to_hsv(1.0, 0.0, 1.0), + hsv_cyan=colorsys.rgb_to_hsv(0.0, 1.0, 1.0), + hsv_white=colorsys.rgb_to_hsv(1.0, 1.0, 1.0), + ) if light: fg, bg, sel_fg, sel_bg = hsv_black, hsv_white, hsv_white, hsv_black @@ -157,15 +159,15 @@ def make_color_theme( "fg": fg, "sel_bg": sel_fg, "sel_fg": sel_bg, - "cursor": hsv_white, - "cl8": hsv_grey, - "cl9": hsv_red, - "cl10": hsv_green, - "cl11": hsv_yellow, - "cl12": hsv_blue, - "cl13": hsv_magenta, - "cl14": hsv_cyan, - "cl15": hsv_white, + "cursor": base["hsv_white"], + "cl8": base["hsv_grey"], + "cl9": base["hsv_red"], + "cl10": base["hsv_green"], + "cl11": base["hsv_yellow"], + "cl12": base["hsv_blue"], + "cl13": base["hsv_magenta"], + "cl14": base["hsv_cyan"], + "cl15": base["hsv_white"], } for key, value in color_theme.items(): color_theme[key] = np.array(value) From 1fc17bd0f65795091fe8f0b958987297024cae53 Mon Sep 17 00:00:00 2001 From: a2n-s <44101798+AntoineStevan@users.noreply.github.com> Date: Sun, 10 Jul 2022 11:00:34 +0200 Subject: [PATCH 16/19] add a function to pick the ground colors --- scripts/a2n-s-compute-color-palette | 22 ++++++++++++++++++---- 1 file changed, 18 insertions(+), 4 deletions(-) diff --git a/scripts/a2n-s-compute-color-palette b/scripts/a2n-s-compute-color-palette index 24a62f3..e91af9b 100755 --- a/scripts/a2n-s-compute-color-palette +++ b/scripts/a2n-s-compute-color-palette @@ -7,6 +7,7 @@ from tqdm import trange import colorsys Color = str +HSVColor = Tuple[float, float, float] Args = argparse.Namespace @@ -65,6 +66,22 @@ def make_random_colors(names: List[str]) -> Dict[str, Color]: ) +def make_grounds( + base: Dict[str, HSVColor], *, light: bool = False +) -> Tuple[HSVColor, HSVColor, HSVColor, HSVColor]: + """Make all the 'grounds' used by a theme from base colors.""" + fg, bg, sel_fg, sel_bg = ( + base["hsv_white"], + base["hsv_black"], + base["hsv_black"], + base["hsv_white"], + ) + if light: + fg, bg = bg, fg + sel_fg, sel_bg = sel_bg, sel_fg + return fg, bg, sel_fg, sel_bg + + PALETTE_NAMES = [ "bg", "fg", @@ -148,10 +165,7 @@ def make_color_theme( hsv_white=colorsys.rgb_to_hsv(1.0, 1.0, 1.0), ) - if light: - fg, bg, sel_fg, sel_bg = hsv_black, hsv_white, hsv_white, hsv_black - else: - fg, bg, sel_fg, sel_bg = hsv_white, hsv_black, hsv_black, hsv_white + fg, bg, sel_fg, sel_bg = make_grounds(base, light=light) # define the base colors of the color theme. color_theme = { From 7192a511c531f61453c9a4688bfdcbd0d55c180f Mon Sep 17 00:00:00 2001 From: a2n-s <44101798+AntoineStevan@users.noreply.github.com> Date: Sun, 10 Jul 2022 11:13:06 +0200 Subject: [PATCH 17/19] add random variations controlled by temperature --- scripts/a2n-s-compute-color-palette | 23 ++++++++++++++++++++--- 1 file changed, 20 insertions(+), 3 deletions(-) diff --git a/scripts/a2n-s-compute-color-palette b/scripts/a2n-s-compute-color-palette index e91af9b..d5b41d8 100755 --- a/scripts/a2n-s-compute-color-palette +++ b/scripts/a2n-s-compute-color-palette @@ -137,6 +137,7 @@ def make_color_theme( hue_focus: float = 1.0, saturation: float = 1.0, brightness: float = 1.0, + temperature: float = 0.0, ) -> Dict[str, Color]: """Make a full color theme centered around sensible colors. @@ -154,7 +155,7 @@ def make_color_theme( """ # define some color constants. base = dict( - hsv_black=colorsys.rgb_to_hsv(0.0, 0.0, 0.0), + hsv_black=colorsys.rgb_to_hsv(0.1, 0.1, 0.1), hsv_grey=colorsys.rgb_to_hsv(0.2, 0.2, 0.2), hsv_red=colorsys.rgb_to_hsv(1.0, 0.0, 0.0), hsv_green=colorsys.rgb_to_hsv(0.0, 1.0, 0.0), @@ -203,9 +204,14 @@ def make_color_theme( for key, value in color_theme.items(): color_theme[key] = scale * value - # make sure the saturation and the brightness are between 0 and 1. + # apply some random variations based on the temperature. for key, value in color_theme.items(): - clipped_value = np.array([value[0], *np.clip(value[1:], a_min=0.0, a_max=1.0)]) + color_theme[key] = np.random.normal(loc=value, scale=temperature) + + # make sure the saturation and the brightness are between 0 and 1, and the + # the hue wraps around 0 and 1. + for key, value in color_theme.items(): + clipped_value = np.array([value[0] % 1, *np.clip(value[1:], a_min=0.0, a_max=1.0)]) color_theme[key] = clipped_value # convert the theme back to its @@ -402,6 +408,16 @@ if __name__ == "__main__": "the theme (defaults to 1.0)." ), ) + parser.add_argument( + "--temperature", + type=float, + default="0.0", + help=( + "the hotter, the more the colors will be random around the " + "deterministic values generated by all the parameters above " + "(defaults to 0.0)." + ), + ) parser.add_argument( "-v", "--verbose", @@ -431,6 +447,7 @@ if __name__ == "__main__": hue_focus=args.hue_focus, saturation=args.saturation, brightness=args.brightness, + temperature=args.temperature, ) gd_start, gd_end = get_gradient_end_points(theme=color_theme, args=args) From 4997cae0bb8ee07b3d07660ae09952622e25cf8f Mon Sep 17 00:00:00 2001 From: a2n-s <44101798+AntoineStevan@users.noreply.github.com> Date: Sun, 10 Jul 2022 11:13:45 +0200 Subject: [PATCH 18/19] refactor the script with black --- scripts/a2n-s-compute-color-palette | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/scripts/a2n-s-compute-color-palette b/scripts/a2n-s-compute-color-palette index d5b41d8..ab2cbae 100755 --- a/scripts/a2n-s-compute-color-palette +++ b/scripts/a2n-s-compute-color-palette @@ -195,7 +195,7 @@ def make_color_theme( # rotate the hue a bit. value_bias = np.array([hue_bias, 0, 0]) - value_scale = np.array([1/hue_focus, 1, 1]) + value_scale = np.array([1 / hue_focus, 1, 1]) for key, value in color_theme.items(): color_theme[key] = value_bias + value * value_scale @@ -211,7 +211,9 @@ def make_color_theme( # make sure the saturation and the brightness are between 0 and 1, and the # the hue wraps around 0 and 1. for key, value in color_theme.items(): - clipped_value = np.array([value[0] % 1, *np.clip(value[1:], a_min=0.0, a_max=1.0)]) + clipped_value = np.array( + [value[0] % 1, *np.clip(value[1:], a_min=0.0, a_max=1.0)] + ) color_theme[key] = clipped_value # convert the theme back to its From 60a5f1cc326c4b4e3a71a02cb4a5cf8248a9c27f Mon Sep 17 00:00:00 2001 From: a2n-s <44101798+AntoineStevan@users.noreply.github.com> Date: Wed, 13 Jul 2022 21:22:29 +0200 Subject: [PATCH 19/19] make sure -h mentions False, not false or 'False' --- scripts/a2n-s-compute-color-palette | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/scripts/a2n-s-compute-color-palette b/scripts/a2n-s-compute-color-palette index ab2cbae..e888c03 100755 --- a/scripts/a2n-s-compute-color-palette +++ b/scripts/a2n-s-compute-color-palette @@ -327,13 +327,13 @@ if __name__ == "__main__": "-g", "--gradient_only", action="store_true", - help="print the gradient only (defaults to 'False').", + help="print the gradient only (defaults to False).", ) parser.add_argument( "-l", "--light", action="store_true", - help="turns on light theme mode (defaults to false, i.e dark theme).", + help="turns on light theme mode (defaults to False, i.e dark theme).", ) parser.add_argument( "-r", @@ -348,7 +348,7 @@ if __name__ == "__main__": help=( "use random colors for the two ends of the gradient, i.e. " f'"{GRADIENT_NAMES[0]}" to "{GRADIENT_NAMES[-1]}" keys in ' - "'GRADIENT_NAMES' (defaults to 'False'). Overwrites -1 and -2." + "'GRADIENT_NAMES' (defaults to False). Overwrites -1 and -2." ), ) parser.add_argument( @@ -358,7 +358,7 @@ if __name__ == "__main__": help=( "use random colors for the whole palette, i.e. all the keys in " "'PALETTE_NAMES' or 'GRADIENT_NAMES' " - "(defaults to 'False'). Overwrites -G, -1 and -2." + "(defaults to False). Overwrites -G, -1 and -2." ), ) parser.add_argument( @@ -424,13 +424,13 @@ if __name__ == "__main__": "-v", "--verbose", action="store_true", - help="be more verbose (defaults to 'False').", + help="be more verbose (defaults to False).", ) parser.add_argument( "-t", "--test", action="store_true", - help="run the tests (defaults to 'False').", + help="run the tests (defaults to False).", ) args = parser.parse_args()