Browse Source

[+] Dynamically set lightness based on light_dark

Azalea (on HyDEV-Daisy) 3 years ago
parent
commit
887f766464
5 changed files with 67 additions and 28 deletions
  1. 17 6
      hyfetch/color_util.py
  2. 5 0
      hyfetch/constants.py
  3. 16 15
      hyfetch/main.py
  4. 2 2
      hyfetch/models.py
  5. 27 5
      hyfetch/presets.py

+ 17 - 6
hyfetch/color_util.py

@@ -1,13 +1,14 @@
 from __future__ import annotations
 
 import colorsys
-from typing import NamedTuple
+from typing import NamedTuple, Callable, Optional
 
 from typing_extensions import Literal
 
 from .constants import GLOBAL_CFG
 
 AnsiMode = Literal['default', 'ansi', '8bit', 'rgb']
+LightDark = Literal['light', 'dark']
 
 
 MINECRAFT_COLORS = ["&0/\033[0;30m", "&1/\033[0;34m", "&2/\033[0;32m", "&3/\033[0;36m", "&4/\033[0;31m",
@@ -176,16 +177,26 @@ class RGB(NamedTuple):
         """
         return RGB(*redistribute_rgb(*[v * multiplier for v in self]))
 
-    def set_light(self, light: float) -> 'RGB':
+    def set_light(self, light: float, at_least: bool | None = None, at_most: bool | None = None) -> 'RGB':
         """
         Set HSL lightness value
 
         :param light: Lightness value (0-1)
+        :param at_least: Set the lightness to at least this value (no change if greater)
+        :param at_most: Set the lightness to at most this value (no change if lesser)
         :return: New color (original isn't modified)
         """
+        # Convert to HSL
         h, l, s = colorsys.rgb_to_hls(*[v / 255.0 for v in self])
-        return RGB(*[round(v * 255.0) for v in colorsys.hls_to_rgb(h, light, s)])
 
-    def set_min_light(self, light: float) -> 'RGB':
-        h, l, s = colorsys.rgb_to_hls(*[v / 255.0 for v in self])
-        return RGB(*[round(v * 255.0) for v in colorsys.hls_to_rgb(h, max(l, light), s)])
+        # Modify light value
+        if at_least is None and at_most is None:
+            l = light
+        else:
+            if at_most:
+                l = min(l, light)
+            if at_least:
+                l = max(l, light)
+
+        # Convert back to RGB
+        return RGB(*[round(v * 255.0) for v in colorsys.hls_to_rgb(h, l, s)])

+ 5 - 0
hyfetch/constants.py

@@ -4,6 +4,8 @@ import os
 from dataclasses import dataclass
 from pathlib import Path
 
+from typing_extensions import Literal
+
 CONFIG_PATH = Path.home() / '.config/hyfetch.json'
 VERSION = '1.0.7'
 
@@ -37,5 +39,8 @@ class GlobalConfig:
     debug: bool
     is_light: bool
 
+    def light_dark(self) -> Literal['light', 'dark']:
+        return 'light' if self.is_light else 'dark'
+
 
 GLOBAL_CFG = GlobalConfig(color_mode='8bit', override_distro=None, debug=False, is_light=False)

+ 16 - 15
hyfetch/main.py

@@ -10,7 +10,7 @@ from typing import Iterable
 
 from hyfetch import presets
 
-from .color_util import printc, color, clear_screen
+from .color_util import printc, color, clear_screen, LightDark
 from .constants import CONFIG_PATH, VERSION, TERM_LEN, TEST_ASCII_WIDTH, TEST_ASCII, GLOBAL_CFG
 from .models import Config
 from .neofetch_util import run_neofetch, get_distro_ascii, ColorAlignment, ascii_size, color_alignments
@@ -98,7 +98,16 @@ def create_config() -> Config:
     title += f'\n&e1. Selected color mode: &r{color_system}'
 
     ##############################
-    # 2. Choose preset
+    # 2. Select light/dark mode
+    clear_screen(title)
+    light_dark = literal_input(f'2. Is your terminal in &gf(#85e7e9)light mode&r or &gf(#c471ed)dark mode&r?',
+                               ['light', 'dark'], 'dark')
+    is_light = light_dark == 'light'
+    GLOBAL_CFG.is_light = is_light
+    title += f'\n&e3. Light/Dark:          &r{light_dark}'
+
+    ##############################
+    # 3. Choose preset
     clear_screen(title)
     printc('&a2. Let\'s choose a flag!')
     printc('Available flag presets:')
@@ -122,19 +131,10 @@ def create_config() -> Config:
         print()
 
     print()
-    tmp = PRESETS['rainbow'].set_light(.7).color_text('preset')
+    tmp = PRESETS['rainbow'].set_light_dl_def(light_dark).color_text('preset')
     preset = literal_input(f'Which {tmp} do you want to use?', PRESETS.keys(), 'rainbow', show_ops=False)
     _prs = PRESETS[preset]
-    title += f'\n&e2. Selected flag:       &r{_prs.color_text(preset)}'
-
-    ##############################
-    # 3. Select light/dark mode
-    clear_screen(title)
-    light_dark = literal_input(f'3. Is your terminal in &gf(#85e7e9)light mode&r or &gf(#c471ed)dark mode&r?',
-                               ['light', 'dark'], 'dark')
-    is_light = light_dark == 'light'
-    GLOBAL_CFG.is_light = is_light
-    title += f'\n&e3. Light/Dark:          &r{light_dark}'
+    title += f'\n&e3. Selected flag:       &r{_prs.color_text(preset)}'
 
     #############################
     # 4. Dim/lighten colors
@@ -148,7 +148,7 @@ def create_config() -> Config:
     ratios = [col / (num_cols - 1) for col in range(num_cols)]
     ratios = [r * 0.6 + 0.2 for r in ratios]
     lines = [ColorAlignment('horizontal').recolor_ascii(TEST_ASCII.replace(
-        '{txt}', f'{r * 100:.0f}%'.center(5)), _prs.set_light(r)).split('\n') for r in ratios]
+        '{txt}', f'{r * 100:.0f}%'.center(5)), _prs.set_light_dl(r, light_dark)).split('\n') for r in ratios]
     [printc('  '.join(line)) for line in zip(*lines)]
 
     while True:
@@ -170,11 +170,12 @@ def create_config() -> Config:
             printc('&cUnable to parse lightness value, please input it as a decimal or percentage (e.g. 0.5 or 50%)')
 
     if lightness:
-        _prs = _prs.set_light(lightness)
+        _prs = _prs.set_light_dl(lightness, light_dark)
     title += f'\n&e4. Brightness:          &r{f"{lightness:.2f}" if lightness else "unset"}'
 
     #############################
     # 5. Color arrangement
+    color_alignment = None
     while True:
         clear_screen(title)
         printc(f'&a5. Let\'s choose a color arrangement!')

+ 2 - 2
hyfetch/models.py

@@ -4,7 +4,7 @@ from dataclasses import dataclass
 
 from typing_extensions import Literal
 
-from .color_util import AnsiMode
+from .color_util import AnsiMode, LightDark
 from .constants import CONFIG_PATH
 from .neofetch_util import ColorAlignment
 from .serializer import json_stringify, from_dict
@@ -14,7 +14,7 @@ from .serializer import json_stringify, from_dict
 class Config:
     preset: str
     mode: AnsiMode
-    light_dark: Literal['light', 'dark'] = 'dark'
+    light_dark: LightDark = 'dark'
     lightness: float | None = None
     color_align: ColorAlignment = ColorAlignment('horizontal')
 

+ 27 - 5
hyfetch/presets.py

@@ -4,7 +4,8 @@ from typing import Iterable
 
 from typing_extensions import Literal
 
-from .color_util import RGB
+from .color_util import RGB, LightDark
+from .constants import GLOBAL_CFG
 
 
 def remove_duplicates(seq: Iterable) -> list:
@@ -100,17 +101,38 @@ class ColorProfile:
         """
         return ColorProfile([c.lighten(multiplier) for c in self.colors])
 
-    def set_light(self, light: float):
+    def set_light_raw(self, light: float, at_least: bool | None = None, at_most: bool | None = None) -> 'ColorProfile':
         """
         Set HSL lightness value
 
         :param light: Lightness value (0-1)
+        :param at_least: Set the lightness to at least this value (no change if greater)
+        :param at_most: Set the lightness to at most this value (no change if lesser)
         :return: New color profile (original isn't modified)
         """
-        return ColorProfile([c.set_light(light) for c in self.colors])
+        return ColorProfile([c.set_light(light, at_least, at_most) for c in self.colors])
 
-    def set_min_light(self, light: float):
-        return ColorProfile([c.set_min_light(light) for c in self.colors])
+    def set_light_dl(self, light: float, term: LightDark = GLOBAL_CFG.light_dark()):
+        """
+        Set HSL lightness value with respect to dark/light terminals
+
+        :param light: Lightness value (0-1)
+        :param term: Terminal color (can be "dark" or "light")
+        :return: New color profile (original isn't modified)
+        """
+        assert term.lower() in ['light', 'dark']
+        at_least, at_most = (True, None) if term.lower() == 'dark' else (None, True)
+        return self.set_light_raw(light, at_least, at_most)
+
+    def set_light_dl_def(self, term: LightDark = GLOBAL_CFG.light_dark()):
+        """
+        Set default lightness with respect to dark/light terminals
+
+        :param term: Terminal color (can be "dark" or "light")
+        :return: New color profile (original isn't modified)
+        """
+        light = 0.65 if term.lower() == 'dark' else 0.4
+        return self.set_light_dl(light, term)
 
     def unique_colors(self) -> ColorProfile:
         """