mirror of
https://github.com/caelestia-dots/cli.git
synced 2026-06-05 23:09:27 -05:00
b00c601d0a
LSP was screaming at me so I decided to just address it to get it off my screen. + Fixed the type hints := Modified and added type hints for certain functions and variables in most of the files in the utils/ folder (and some in the subcommands/ folder) for clarity and so pyright's type checker wouldn't cry. :+ To resolve certain type issues, I had to add a bit more tiny additional code such as, additional checks if a variable is None, a tiny class in utils/material/generator.py to resolve the constructor usage mismatch between what the DynamicScheme accepts and what the code actually passes, and etc. - Renamed certain functions and variables for clarity and also for some to not collide with pre-existing definitions from well-known library imports. + PIL has reorganized their code a bit, so the code is made to reflect their new definitions. = Reorganized the single import statement for "colourfulness" in utils/wallpaper.py to be close to the top. (I think that's it) Side Effects?: Everything should work the same as no logic change was done whatsover (unless we consider the added if statements for type checking as a logic change). I've tested it, everything seems to be in urdir.
279 lines
9.9 KiB
Python
279 lines
9.9 KiB
Python
from materialyoucolor.blend import Blend
|
|
from materialyoucolor.dynamiccolor.material_dynamic_colors import MaterialDynamicColors
|
|
from materialyoucolor.hct import Hct
|
|
from materialyoucolor.scheme.scheme_content import SchemeContent
|
|
from materialyoucolor.scheme.scheme_expressive import SchemeExpressive
|
|
from materialyoucolor.scheme.scheme_fidelity import SchemeFidelity
|
|
from materialyoucolor.scheme.scheme_fruit_salad import SchemeFruitSalad
|
|
from materialyoucolor.scheme.scheme_monochrome import SchemeMonochrome
|
|
from materialyoucolor.scheme.scheme_neutral import SchemeNeutral
|
|
from materialyoucolor.scheme.scheme_rainbow import SchemeRainbow
|
|
from materialyoucolor.scheme.scheme_tonal_spot import SchemeTonalSpot
|
|
from materialyoucolor.scheme.scheme_vibrant import SchemeVibrant
|
|
from materialyoucolor.utils.math_utils import difference_degrees, rotation_direction, sanitize_degrees_double
|
|
from typing import Protocol, Any
|
|
|
|
|
|
# The base DynamicScheme class requires a 'variant' argument, but the specific
|
|
# subclasses in get_scheme() handle that internally. This Protocol tells the type
|
|
# checker to expect our specific 3-argument setup instead of the base class signature.
|
|
class SchemeConstructor(Protocol):
|
|
def __call__(self, source_color_hct: Any, is_dark: bool, contrast_level: float) -> DynamicScheme: ...
|
|
|
|
try:
|
|
from materialyoucolor.dynamiccolor.dynamic_scheme import DynamicScheme
|
|
except ImportError:
|
|
from materialyoucolor.scheme.dynamic_scheme import DynamicScheme
|
|
|
|
|
|
def hex_to_hct(hex: str) -> Hct:
|
|
return Hct.from_int(int(f"0xFF{hex}", 16))
|
|
|
|
|
|
light_gruvbox = [
|
|
hex_to_hct("FDF9F3"),
|
|
hex_to_hct("FF6188"),
|
|
hex_to_hct("A9DC76"),
|
|
hex_to_hct("FC9867"),
|
|
hex_to_hct("FFD866"),
|
|
hex_to_hct("F47FD4"),
|
|
hex_to_hct("78DCE8"),
|
|
hex_to_hct("333034"),
|
|
hex_to_hct("121212"),
|
|
hex_to_hct("FF6188"),
|
|
hex_to_hct("A9DC76"),
|
|
hex_to_hct("FC9867"),
|
|
hex_to_hct("FFD866"),
|
|
hex_to_hct("F47FD4"),
|
|
hex_to_hct("78DCE8"),
|
|
hex_to_hct("333034"),
|
|
]
|
|
|
|
dark_gruvbox = [
|
|
hex_to_hct("282828"),
|
|
hex_to_hct("CC241D"),
|
|
hex_to_hct("98971A"),
|
|
hex_to_hct("D79921"),
|
|
hex_to_hct("458588"),
|
|
hex_to_hct("B16286"),
|
|
hex_to_hct("689D6A"),
|
|
hex_to_hct("A89984"),
|
|
hex_to_hct("928374"),
|
|
hex_to_hct("FB4934"),
|
|
hex_to_hct("B8BB26"),
|
|
hex_to_hct("FABD2F"),
|
|
hex_to_hct("83A598"),
|
|
hex_to_hct("D3869B"),
|
|
hex_to_hct("8EC07C"),
|
|
hex_to_hct("EBDBB2"),
|
|
]
|
|
|
|
light_catppuccin = [
|
|
hex_to_hct("dc8a78"),
|
|
hex_to_hct("dd7878"),
|
|
hex_to_hct("ea76cb"),
|
|
hex_to_hct("8839ef"),
|
|
hex_to_hct("d20f39"),
|
|
hex_to_hct("e64553"),
|
|
hex_to_hct("fe640b"),
|
|
hex_to_hct("df8e1d"),
|
|
hex_to_hct("40a02b"),
|
|
hex_to_hct("179299"),
|
|
hex_to_hct("04a5e5"),
|
|
hex_to_hct("209fb5"),
|
|
hex_to_hct("1e66f5"),
|
|
hex_to_hct("7287fd"),
|
|
]
|
|
|
|
dark_catppuccin = [
|
|
hex_to_hct("f5e0dc"),
|
|
hex_to_hct("f2cdcd"),
|
|
hex_to_hct("f5c2e7"),
|
|
hex_to_hct("cba6f7"),
|
|
hex_to_hct("f38ba8"),
|
|
hex_to_hct("eba0ac"),
|
|
hex_to_hct("fab387"),
|
|
hex_to_hct("f9e2af"),
|
|
hex_to_hct("a6e3a1"),
|
|
hex_to_hct("94e2d5"),
|
|
hex_to_hct("89dceb"),
|
|
hex_to_hct("74c7ec"),
|
|
hex_to_hct("89b4fa"),
|
|
hex_to_hct("b4befe"),
|
|
]
|
|
|
|
kcolours = [
|
|
{"name": "klink", "hct": hex_to_hct("2980b9")},
|
|
{"name": "kvisited", "hct": hex_to_hct("9b59b6")},
|
|
{"name": "knegative", "hct": hex_to_hct("da4453")},
|
|
{"name": "kneutral", "hct": hex_to_hct("f67400")},
|
|
{"name": "kpositive", "hct": hex_to_hct("27ae60")},
|
|
]
|
|
|
|
colour_names = [
|
|
"rosewater",
|
|
"flamingo",
|
|
"pink",
|
|
"mauve",
|
|
"red",
|
|
"maroon",
|
|
"peach",
|
|
"yellow",
|
|
"green",
|
|
"teal",
|
|
"sky",
|
|
"sapphire",
|
|
"blue",
|
|
"lavender",
|
|
]
|
|
|
|
|
|
def grayscale(colour: Hct, light: bool) -> Hct:
|
|
colour = darken(colour, 0.35) if light else lighten(colour, 0.65)
|
|
colour.chroma = 0
|
|
return colour
|
|
|
|
|
|
def mix(a: Hct, b: Hct, w: float) -> Hct:
|
|
return Hct.from_int(Blend.cam16_ucs(a.to_int(), b.to_int(), w))
|
|
|
|
|
|
def harmonize(from_hct: Hct, to_hct: Hct, tone_boost: float) -> Hct:
|
|
difference_degrees_ = difference_degrees(from_hct.hue, to_hct.hue)
|
|
rotation_degrees = min(difference_degrees_ * 0.8, 100)
|
|
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 * (1 + tone_boost))
|
|
|
|
|
|
def lighten(colour: Hct, amount: float) -> Hct:
|
|
diff = (100 - colour.tone) * amount
|
|
return Hct.from_hct(colour.hue, colour.chroma + diff / 5, colour.tone + diff)
|
|
|
|
|
|
def darken(colour: Hct, amount: float) -> Hct:
|
|
diff = colour.tone * amount
|
|
return Hct.from_hct(colour.hue, colour.chroma - diff / 5, colour.tone - diff)
|
|
|
|
|
|
def get_scheme(scheme: str) -> SchemeConstructor:
|
|
if scheme == "content":
|
|
return SchemeContent
|
|
if scheme == "expressive":
|
|
return SchemeExpressive
|
|
if scheme == "fidelity":
|
|
return SchemeFidelity
|
|
if scheme == "fruitsalad":
|
|
return SchemeFruitSalad
|
|
if scheme == "monochrome":
|
|
return SchemeMonochrome
|
|
if scheme == "neutral":
|
|
return SchemeNeutral
|
|
if scheme == "rainbow":
|
|
return SchemeRainbow
|
|
if scheme == "tonalspot":
|
|
return SchemeTonalSpot
|
|
return SchemeVibrant
|
|
|
|
|
|
def gen_scheme(scheme, primary: Hct) -> dict[str, str]:
|
|
is_light = scheme.mode == "light"
|
|
|
|
colours = {}
|
|
|
|
# Material colours
|
|
primary_scheme = get_scheme(scheme.variant)(source_color_hct=primary, is_dark=not is_light, contrast_level=0.0)
|
|
if hasattr(MaterialDynamicColors, "all_colors"): # materialyoucolor-python >= 3.0.0
|
|
dyn_colours = MaterialDynamicColors()
|
|
for colour in dyn_colours.all_colors:
|
|
colours[colour.name] = colour.get_hct(primary_scheme)
|
|
else:
|
|
for colour in vars(MaterialDynamicColors).keys():
|
|
colour_name = getattr(MaterialDynamicColors, colour)
|
|
if hasattr(colour_name, "get_hct"):
|
|
colours[colour] = colour_name.get_hct(primary_scheme)
|
|
|
|
# Backwards compatibility with old colour names
|
|
if "primaryPaletteKeyColor" in colours: # materialyoucolor-python >= 3.0.0
|
|
for colour in "primary", "secondary", "tertiary", "neutral":
|
|
colours[f"{colour}_paletteKeyColor"] = colours[f"{colour}PaletteKeyColor"]
|
|
colours["neutral_variant_paletteKeyColor"] = colours["neutralVariantPaletteKeyColor"]
|
|
|
|
# Harmonize terminal colours
|
|
for i, hct in enumerate(light_gruvbox if is_light else dark_gruvbox):
|
|
if scheme.variant == "monochrome":
|
|
colours[f"term{i}"] = grayscale(hct, is_light)
|
|
else:
|
|
colours[f"term{i}"] = harmonize(
|
|
hct, colours["primary_paletteKeyColor"], (0.35 if i < 8 else 0.2) * (-1 if is_light else 1)
|
|
)
|
|
|
|
# Harmonize named colours
|
|
for i, hct in enumerate(light_catppuccin if is_light else dark_catppuccin):
|
|
if scheme.variant == "monochrome":
|
|
colours[colour_names[i]] = grayscale(hct, is_light)
|
|
else:
|
|
colours[colour_names[i]] = harmonize(hct, colours["primary_paletteKeyColor"], (-0.2 if is_light else 0.05))
|
|
|
|
# KColours
|
|
for colour in kcolours:
|
|
colours[colour["name"]] = harmonize(colour["hct"], colours["primary"], 0.1)
|
|
colours[f"{colour['name']}Selection"] = harmonize(colour["hct"], colours["onPrimaryFixedVariant"], 0.1)
|
|
if scheme.variant == "monochrome":
|
|
colours[colour["name"]] = grayscale(colours[colour["name"]], is_light)
|
|
colours[f"{colour['name']}Selection"] = grayscale(colours[f"{colour['name']}Selection"], is_light)
|
|
|
|
if scheme.variant == "neutral":
|
|
for name, hct in colours.items():
|
|
colours[name].chroma -= 15
|
|
|
|
# Darken surfaces for hard flavour
|
|
if scheme.flavour == "hard":
|
|
for colour in "background", *(k for k in colours.keys() if k.startswith("surface")):
|
|
colours[colour] = lighten(colours[colour], 0.4) if is_light else darken(colours[colour], 0.8)
|
|
colours["term0"] = lighten(colours["term0"], 0.4) if is_light else darken(colours["term0"], 0.9)
|
|
|
|
# FIXME: deprecated stuff
|
|
colours["text"] = colours["onBackground"]
|
|
colours["subtext1"] = colours["onSurfaceVariant"]
|
|
colours["subtext0"] = colours["outline"]
|
|
colours["overlay2"] = mix(colours["surface"], colours["outline"], 0.86)
|
|
colours["overlay1"] = mix(colours["surface"], colours["outline"], 0.71)
|
|
colours["overlay0"] = mix(colours["surface"], colours["outline"], 0.57)
|
|
colours["surface2"] = mix(colours["surface"], colours["outline"], 0.43)
|
|
colours["surface1"] = mix(colours["surface"], colours["outline"], 0.29)
|
|
colours["surface0"] = mix(colours["surface"], colours["outline"], 0.14)
|
|
colours["base"] = colours["surface"]
|
|
colours["mantle"] = darken(colours["surface"], 0.03)
|
|
colours["crust"] = darken(colours["surface"], 0.05)
|
|
|
|
# More darkening if hard flavour
|
|
if scheme.flavour == "hard":
|
|
for colour in "base", "mantle", "crust":
|
|
colours[colour] = lighten(colours[colour], 0.4) if is_light else darken(colours[colour], 0.9)
|
|
for i in range(3):
|
|
colours[f"overlay{i}"] = (
|
|
lighten(colours[f"overlay{i}"], 0.4) if is_light else darken(colours[f"overlay{i}"], 0.8)
|
|
)
|
|
colours[f"surface{i}"] = (
|
|
lighten(colours[f"surface{i}"], 0.4) if is_light else darken(colours[f"surface{i}"], 0.8)
|
|
)
|
|
|
|
# For debugging
|
|
# print("\n".join(["{}: \x1b[48;2;{};{};{}m \x1b[0m".format(n, *c.to_rgba()[:3]) for n, c in colours.items()]))
|
|
|
|
colours = {k: hex(v.to_int())[4:] for k, v in colours.items()}
|
|
|
|
# Extended material
|
|
if is_light:
|
|
colours["success"] = "4F6354"
|
|
colours["onSuccess"] = "FFFFFF"
|
|
colours["successContainer"] = "D1E8D5"
|
|
colours["onSuccessContainer"] = "0C1F13"
|
|
else:
|
|
colours["success"] = "B5CCBA"
|
|
colours["onSuccess"] = "213528"
|
|
colours["successContainer"] = "374B3E"
|
|
colours["onSuccessContainer"] = "D1E9D6"
|
|
|
|
return colours
|