diff --git a/.config/ags/scripts/color_generation/colorgen.sh b/.config/ags/scripts/color_generation/colorgen.sh index ef0c0948c..c26cdcb2e 100755 --- a/.config/ags/scripts/color_generation/colorgen.sh +++ b/.config/ags/scripts/color_generation/colorgen.sh @@ -6,11 +6,14 @@ if [ $# -eq 0 ]; then exit 1 fi -# check if the file ~/.cache/ags/user/colormode.txt exists. if not, create it. else, read it to $lightdark colormodefile="$HOME/.cache/ags/user/colormode.txt" lightdark="dark" transparency="opaque" materialscheme="vibrant" +terminalscheme="$HOME/.config/ags/scripts/templates/terminal/scheme-gruvbox.json" +#terminalscheme="$HOME/.config/ags/scripts/templates/terminal/scheme-catppuccin.json" +#terminalscheme="$HOME/.config/ags/scripts/templates/terminal/scheme-vscode.json" + if [ ! -f $colormodefile ]; then echo "dark" > $colormodefile echo "opaque" >> $colormodefile @@ -35,6 +38,7 @@ cd "$HOME/.config/ags/scripts/" || exit if [[ "$1" = "#"* ]]; then # this is a color color_generation/generate_colors_material.py --color "$1" \ --mode "$lightdark" --scheme "$materialscheme" --transparency "$transparency" \ + --termscheme $terminalscheme --blend_bg_fg \ > "$HOME"/.cache/ags/user/generated/material_colors.scss if [ "$2" = "--apply" ]; then cp "$HOME"/.cache/ags/user/generated/material_colors.scss "$HOME/.config/ags/scss/_material.scss" @@ -46,7 +50,9 @@ elif [ "$backend" = "material" ]; then smartflag='--smart True' fi color_generation/generate_colors_material.py --path "$1" \ - --mode "$lightdark" --scheme "$materialscheme" --transparency "$transparency" --cache "$HOME/.cache/ags/user/color.txt" $smartflag \ + --mode "$lightdark" --scheme "$materialscheme" --transparency "$transparency" \ + --termscheme $terminalscheme --blend_bg_fg \ + --cache "$HOME/.cache/ags/user/color.txt" $smartflag \ > "$HOME"/.cache/ags/user/generated/material_colors.scss if [ "$2" = "--apply" ]; then cp "$HOME"/.cache/ags/user/generated/material_colors.scss "$HOME/.config/ags/scss/_material.scss" diff --git a/.config/ags/scripts/color_generation/generate_colors_material.py b/.config/ags/scripts/color_generation/generate_colors_material.py index ea4cfaa94..5a62207ad 100755 --- a/.config/ags/scripts/color_generation/generate_colors_material.py +++ b/.config/ags/scripts/color_generation/generate_colors_material.py @@ -1,34 +1,37 @@ #!/usr/bin/env python3 import argparse import math +import json from PIL import Image from materialyoucolor.quantize import QuantizeCelebi from materialyoucolor.score.score import Score from materialyoucolor.hct import Hct from materialyoucolor.dynamiccolor.material_dynamic_colors import MaterialDynamicColors -from materialyoucolor.utils.color_utils import rgba_from_argb, argb_from_rgb - -argb_to_hex = lambda argb: "#{:02X}{:02X}{:02X}".format(*map(round, rgba_from_argb(argb))) -hex_to_argb = lambda hex_code: argb_from_rgb(int(hex_code[1:3], 16), int(hex_code[3:5], 16), int(hex_code[5:], 16)) +from materialyoucolor.utils.color_utils import (rgba_from_argb, argb_from_rgb, argb_from_rgba) +from materialyoucolor.utils.math_utils import (sanitize_degrees_double, difference_degrees, rotation_direction) parser = argparse.ArgumentParser(description='Color generation script') parser.add_argument('--path', type=str, default=None, help='generate colorscheme from image') parser.add_argument('--size', type=int , default=128 , help='bitmap image size') parser.add_argument('--color', type=str, default=None, help='generate colorscheme from color') parser.add_argument('--mode', type=str, choices=['dark', 'light'], default='dark', help='dark or light mode') -parser.add_argument('--scheme', type=str, default=None, help='material scheme to use') -parser.add_argument('--smart', type=str, default=False, help='decide scheme type based on image color') +parser.add_argument('--scheme', type=str, default='vibrant', help='material scheme to use') +parser.add_argument('--smart', action='store_true', default=False, help='decide scheme type based on image color') parser.add_argument('--transparency', type=str, choices=['opaque', 'transparent'], default='opaque', help='enable transparency') +parser.add_argument('--termscheme', type=str, default=None, help='JSON file containg the terminal scheme for generating term colors') +parser.add_argument('--harmony', type=float , default=0.5, help='(0-1) Color hue shift towards accent') +parser.add_argument('--harmonize_threshold', type=float , default=35, help='(0-180) Max threshold angle to limit color hue shift') +parser.add_argument('--blend_bg_fg', action='store_true', default=False, help='Shift terminal background or foreground towards accent') parser.add_argument('--cache', type=str, default=None, help='file path to store the generated color') parser.add_argument('--debug', action='store_true', default=False, help='debug mode') args = parser.parse_args() -darkmode = (args.mode == 'dark') -transparent = (args.transparency == 'transparent') -print(f"$darkmode: {darkmode};") -print(f"$transparent: {transparent};") +rgba_to_hex = lambda rgba: "#{:02X}{:02X}{:02X}".format(rgba[0], rgba[1], rgba[2]) +argb_to_hex = lambda argb: "#{:02X}{:02X}{:02X}".format(*map(round, rgba_from_argb(argb))) +hex_to_argb = lambda hex_code: argb_from_rgb(int(hex_code[1:3], 16), int(hex_code[3:5], 16), int(hex_code[5:], 16)) +display_color = lambda rgba : "\x1B[38;2;{};{};{}m{}\x1B[0m".format(rgba[0], rgba[1], rgba[2], "\x1b[7m \x1b[7m") -def calculate_optimal_size (width, height, bitmap_size): +def calculate_optimal_size (width: int, height: int, bitmap_size: int) -> (int, int): image_area = width * height; bitmap_area = bitmap_size ** 2 scale = math.sqrt(bitmap_area/image_area) if image_area > bitmap_area else 1 @@ -40,6 +43,23 @@ def calculate_optimal_size (width, height, bitmap_size): new_height = 1 return new_width, new_height +def harmonize (design_color: int, source_color: int, threshold: float = 35, harmony: float = 0.5) -> int: + from_hct = Hct.from_int(design_color) + to_hct = Hct.from_int(source_color) + difference_degrees_ = difference_degrees(from_hct.hue, to_hct.hue) + rotation_degrees = min(difference_degrees_ * harmony, threshold) + output_hue = sanitize_degrees_double( + from_hct.hue + rotation_degrees * rotation_direction(from_hct.hue, to_hct.hue) + ) + return Hct.from_hct(output_hue, from_hct.chroma, from_hct.tone).to_int() + +def force_chroma_tone (argb: int, chroma: float = 0, tone: float = 0) -> int: + hct = Hct.from_int(argb) + return Hct.from_hct(hct.hue, chroma, tone).to_int() + +darkmode = (args.mode == 'dark') +transparent = (args.transparency == 'transparent') + if args.path is not None: image = Image.open(args.path) wsize, hsize = image.size @@ -62,55 +82,91 @@ elif args.color is not None: argb = hex_to_argb(args.color) hct = Hct.from_int(argb) -# Default scheme -> Tonal Spot (Android Default) -from materialyoucolor.scheme.scheme_vibrant import SchemeVibrant as Scheme -if args.scheme is not None: - if args.scheme == 'fruitsalad': - from materialyoucolor.scheme.scheme_fruit_salad import SchemeFruitSalad as Scheme - elif args.scheme == 'expressive': - from materialyoucolor.scheme.scheme_expressive import SchemeExpressive as Scheme - elif args.scheme == 'monochrome': - from materialyoucolor.scheme.scheme_monochrome import SchemeMonochrome as Scheme - elif args.scheme == 'rainbow': - from materialyoucolor.scheme.scheme_rainbow import SchemeRainbow as Scheme - elif args.scheme == 'tonalspot': - from materialyoucolor.scheme.scheme_tonal_spot import SchemeTonalSpot as Scheme - elif args.scheme == 'neutral': - from materialyoucolor.scheme.scheme_neutral import SchemeNeutral as Scheme - elif args.scheme == 'fidelity': - from materialyoucolor.scheme.scheme_fidelity import SchemeFidelity as Scheme - elif args.scheme == 'content': - from materialyoucolor.scheme.scheme_content import SchemeContent as Scheme +if args.scheme == 'fruitsalad': + from materialyoucolor.scheme.scheme_fruit_salad import SchemeFruitSalad as Scheme +elif args.scheme == 'expressive': + from materialyoucolor.scheme.scheme_expressive import SchemeExpressive as Scheme +elif args.scheme == 'monochrome': + from materialyoucolor.scheme.scheme_monochrome import SchemeMonochrome as Scheme +elif args.scheme == 'rainbow': + from materialyoucolor.scheme.scheme_rainbow import SchemeRainbow as Scheme +elif args.scheme == 'tonalspot': + from materialyoucolor.scheme.scheme_tonal_spot import SchemeTonalSpot as Scheme +elif args.scheme == 'neutral': + from materialyoucolor.scheme.scheme_neutral import SchemeNeutral as Scheme +elif args.scheme == 'fidelity': + from materialyoucolor.scheme.scheme_fidelity import SchemeFidelity as Scheme +elif args.scheme == 'content': + from materialyoucolor.scheme.scheme_content import SchemeContent as Scheme +else: + from materialyoucolor.scheme.scheme_vibrant import SchemeVibrant as Scheme # Generate scheme = Scheme(hct, darkmode, 0.0) +material_colors = {} +term_colors = {} + for color in vars(MaterialDynamicColors).keys(): color_name = getattr(MaterialDynamicColors, color) if hasattr(color_name, "get_hct"): rgba = color_name.get_hct(scheme).to_rgba() - r, g, b, a = rgba - hex_code = f"#{r:02X}{g:02X}{b:02X}" - print('$' + color + ': ' + hex_code + ';') + material_colors[color] = rgba_to_hex(rgba) -if args.debug == True: - print('---------------------') +# Extended material +if darkmode == True: + material_colors['success'] = '#B5CCBA' + material_colors['onSuccess'] = '#213528' + material_colors['successContainer'] = '#374B3E' + material_colors['onSuccessContainer'] = '#D1E9D6' +else: + material_colors['success'] = '#4F6354' + material_colors['onSuccess'] = '#FFFFFF' + material_colors['successContainer'] = '#D1E8D5' + material_colors['onSuccessContainer'] = '#0C1F13' + +# Terminal Colors +if args.termscheme is not None: + with open(args.termscheme, 'r') as f: + json_termscheme = f.read() + term_source_colors = json.loads(json_termscheme)['dark' if darkmode else 'light'] + + for color, val in term_source_colors.items(): + if args.blend_bg_fg: + tone_ovr = 10 if darkmode else 90 + if args.blend_bg_fg and color == "term0": + harmonized = force_chroma_tone(argb, 10, tone_ovr) + elif args.blend_bg_fg and color == "term15": + harmonized = force_chroma_tone(argb, 10, 100 - tone_ovr) + else: + harmonized = harmonize(hex_to_argb(val), argb, args.harmonize_threshold, args.harmony) + term_colors[color] = argb_to_hex(harmonized) + +if args.debug == False: + print(f"$darkmode: {darkmode};") + print(f"$transparent: {transparent};") + for color, code in material_colors.items(): + print(f"${color}: {code};") + for color, code in term_colors.items(): + print(f"${color}: {code};") +else: if args.path is not None: - print('Image size: {} x {}'.format(wsize, hsize)) - print('Resized image: {} x {}'.format(wsize_new, hsize_new)) - print('Hue:', hct.hue) - print('Chroma:', hct.chroma) - print('Tone:', hct.tone) - r, g, b, a = rgba_from_argb(argb) - hex_code = argb_to_hex(argb) - print('Selected Color:', "\x1B[38;2;{};{};{}m{}\x1B[0m".format(r, g, b, "\x1b[7m \x1b[7m"), hex_code) - print('Dark mode:', darkmode) - print('Scheme:', args.scheme) - print('---------------------') - for color in vars(MaterialDynamicColors).keys(): - color_name = getattr(MaterialDynamicColors, color) - if hasattr(color_name, "get_hct"): - rgba = color_name.get_hct(scheme).to_rgba() - r, g, b, a = rgba - hex_code = f"#{r:02X}{g:02X}{b:02X}" - print(color.ljust(32), "\x1B[38;2;{};{};{}m{}\x1B[0m".format(rgba[0], rgba[1], rgba[2], "\x1b[7m \x1b[7m"), hex_code) + print('\n--------------Image properties-----------------') + print(f"Image size: {wsize} x {hsize}") + print(f"Resized image: {wsize_new} x {hsize_new}") + print('\n---------------Selected color------------------') + print(f"Dark mode: {darkmode}") + print(f"Scheme: {args.scheme}") + print(f"Accent color: {display_color(rgba_from_argb(argb))} {argb_to_hex(argb)}") + print(f"HCT: {hct.hue:.2f} {hct.chroma:.2f} {hct.tone:.2f}") + print('\n---------------Material colors-----------------') + for color, code in material_colors.items(): + rgba = rgba_from_argb(hex_to_argb(code)) + print(f"{color.ljust(32)} : {display_color(rgba)} {code}") + print('\n----------Harmonize terminal colors------------') + for color, code in term_colors.items(): + rgba = rgba_from_argb(hex_to_argb(code)) + code_source = term_source_colors[color] + rgba_source = rgba_from_argb(hex_to_argb(code_source)) + print(f"{color.ljust(6)} : {display_color(rgba_source)} {code_source} --> {display_color(rgba)} {code}") + print('-----------------------------------------------') diff --git a/.config/ags/scripts/templates/terminal/sequences.txt b/.config/ags/scripts/templates/terminal/sequences.txt index 6e91959be..27fa99798 100644 --- a/.config/ags/scripts/templates/terminal/sequences.txt +++ b/.config/ags/scripts/templates/terminal/sequences.txt @@ -1 +1 @@ -]4;0;#$background #\]4;1;#$error #\]4;2;#$secondaryContainer #\]4;3;#$onSecondaryContainer #\]4;4;#$onSecondaryContainer #\]4;5;#$onSecondaryContainer #\]4;6;#$onSecondaryContainer #\]4;7;#$onSurfaceVariant #\]4;8;#$onSurfaceVariant #\]4;9;#$error #\]4;10;#$secondaryContainer #\]4;11;#$onSecondaryContainer #\]4;12;#$onSecondaryContainer #\]4;13;#$onSecondaryContainer #\]4;14;#$onSecondaryContainer #\]4;15;#$onSurfaceVariant #\]10;#$onSurfaceVariant #\]11;[$alpha]#$background #\]12;#$onSurfaceVariant #\]13;#$onSurfaceVariant #\]17;#$onSurfaceVariant #\]19;#$background #\]4;232;#$onSurfaceVariant #\]4;256;#$onSurfaceVariant #\]708;[$alpha]#$background #\ \ No newline at end of file +]4;0;#$term0 #\]4;1;#$term1 #\]4;2;#$term2 #\]4;3;#$term3 #\]4;4;#$term4 #\]4;5;#$term5 #\]4;6;#$term6 #\]4;7;#$term7 #\]4;8;#$term8 #\]4;9;#$term9 #\]4;10;#$term10 #\]4;11;#$term11 #\]4;12;#$term12 #\]4;13;#$term13 #\]4;14;#$term14 #\]4;15;#$term15 #\]10;#$term7 #\]11;[$alpha]#$term0 #\]12;#$term7 #\]13;#$term7 #\]17;#$term7 #\]19;#$term0 #\]4;232;#$term7 #\]4;256;#$term7 #\]708;[$alpha]#$term0 #\ diff --git a/.config/ags/scss/_colors.scss b/.config/ags/scss/_colors.scss index 39608b4ed..c89954719 100644 --- a/.config/ags/scss/_colors.scss +++ b/.config/ags/scss/_colors.scss @@ -1,20 +1,6 @@ $rootTransparency: 0.31; // Transparency = 1 - opacity $transparency: 0.8; -// Extended material -$success: #4f6354; -$onSuccess: #ffffff; -$successContainer: #d1e8d5; -$onSuccessContainer: #0c1f13; - -@if $darkmode == True { - // Dark variant - $success: #b5ccba; - $onSuccess: #213528; - $successContainer: #374b3e; - $onSuccessContainer: #d1e9d6; -} - // Transparent versions @if $transparent == True { $background: transparentize($background, $rootTransparency); diff --git a/.config/ags/scss/_material.scss b/.config/ags/scss/_material.scss index d7b7717dc..df41011fc 100644 --- a/.config/ags/scss/_material.scss +++ b/.config/ags/scss/_material.scss @@ -1,56 +1,76 @@ $darkmode: True; $transparent: False; -$primary_paletteKeyColor: #A504FF; -$secondary_paletteKeyColor: #8B6D8D; -$tertiary_paletteKeyColor: #9A678C; -$neutral_paletteKeyColor: #7D7480; -$neutral_variant_paletteKeyColor: #7E7382; -$background: #17111B; -$onBackground: #EBDFED; -$surface: #17111B; -$surfaceDim: #17111B; -$surfaceBright: #3E3741; -$surfaceContainerLowest: #FFFFFF; -$surfaceContainerLow: #1F1923; -$surfaceContainer: #241D27; -$surfaceContainerHigh: #2E2832; -$surfaceContainerHighest: #39323D; -$onSurface: #EBDFED; -$surfaceVariant: #4D4351; -$onSurfaceVariant: #CFC2D3; -$inverseSurface: #EBDFED; -$inverseOnSurface: #352E38; -$outline: #988D9D; -$outlineVariant: #4D4351; +$primary_paletteKeyColor: #57814C; +$secondary_paletteKeyColor: #6C7B65; +$tertiary_paletteKeyColor: #527F82; +$neutral_paletteKeyColor: #747870; +$neutral_variant_paletteKeyColor: #73796E; +$background: #11140F; +$onBackground: #E1E4DA; +$surface: #11140F; +$surfaceDim: #11140F; +$surfaceBright: #363A34; +$surfaceContainerLowest: #0C0F0A; +$surfaceContainerLow: #191D17; +$surfaceContainer: #1D211B; +$surfaceContainerHigh: #272B25; +$surfaceContainerHighest: #32362F; +$onSurface: #E1E4DA; +$surfaceVariant: #43483F; +$onSurfaceVariant: #C3C8BC; +$inverseSurface: #E1E4DA; +$inverseOnSurface: #2E322B; +$outline: #8D9387; +$outlineVariant: #43483F; $shadow: #000000; $scrim: #000000; -$surfaceTint: #E2B6FF; -$primary: #E2B6FF; -$onPrimary: #4D007B; -$primaryContainer: #6D00AC; -$onPrimaryContainer: #F3DAFF; -$inversePrimary: #9000DF; -$secondary: #DEBCDF; -$onSecondary: #402843; -$secondaryContainer: #5A405D; -$onSecondaryContainer: #FDD9FD; -$tertiary: #F0B5DE; -$onTertiary: #4B2142; -$tertiaryContainer: #B680A7; +$surfaceTint: #A5D395; +$primary: #A5D395; +$onPrimary: #11380B; +$primaryContainer: #285020; +$onPrimaryContainer: #C0EFB0; +$inversePrimary: #406836; +$secondary: #BBCBB2; +$onSecondary: #263422; +$secondaryContainer: #3C4B37; +$onSecondaryContainer: #D7E8CD; +$tertiary: #A0CFD2; +$onTertiary: #003739; +$tertiaryContainer: #6B989B; $onTertiaryContainer: #000000; $error: #FFB4AB; $onError: #690005; $errorContainer: #93000A; $onErrorContainer: #FFDAD6; -$primaryFixed: #F3DAFF; -$primaryFixedDim: #E2B6FF; -$onPrimaryFixed: #2E004D; -$onPrimaryFixedVariant: #6D00AC; -$secondaryFixed: #FCD7FB; -$secondaryFixedDim: #DEBCDF; -$onSecondaryFixed: #29132D; -$onSecondaryFixedVariant: #583E5B; -$tertiaryFixed: #FFD7F1; -$tertiaryFixedDim: #F0B5DE; -$onTertiaryFixed: #320C2C; -$onTertiaryFixedVariant: #64385A; +$primaryFixed: #C0EFB0; +$primaryFixedDim: #A5D395; +$onPrimaryFixed: #002200; +$onPrimaryFixedVariant: #285020; +$secondaryFixed: #D7E8CD; +$secondaryFixedDim: #BBCBB2; +$onSecondaryFixed: #121F0E; +$onSecondaryFixedVariant: #3C4B37; +$tertiaryFixed: #BCEBEE; +$tertiaryFixedDim: #A0CFD2; +$onTertiaryFixed: #002022; +$onTertiaryFixedVariant: #1E4D50; +$success: #B5CCBA; +$onSuccess: #213528; +$successContainer: #374B3E; +$onSuccessContainer: #D1E9D6; +$term0: #161E14; +$term1: #9D5800; +$term2: #7E9D36; +$term3: #ABA930; +$term4: #4D8671; +$term5: #B96353; +$term6: #6C9D66; +$term7: #9E9C86; +$term8: #898674; +$term9: #CB7600; +$term10: #99C246; +$term11: #C9CE46; +$term12: #88A58F; +$term13: #D7886D; +$term14: #8DC07D; +$term15: #DDE5D5;