From b09d6a0a2d9887b5560a3b49cb8a603a33ec4828 Mon Sep 17 00:00:00 2001 From: Chandler J Date: Sat, 6 Apr 2024 20:52:13 -0600 Subject: improved color picker --- src/color_engine.py | 2 -- src/get_args.py | 23 +++++++++++++++++------ src/manage_saves.py | 2 +- src/user_interface.py | 40 +++++++++++++++++++++++++--------------- 4 files changed, 43 insertions(+), 24 deletions(-) diff --git a/src/color_engine.py b/src/color_engine.py index 0e43475..c24450b 100644 --- a/src/color_engine.py +++ b/src/color_engine.py @@ -13,8 +13,6 @@ def grabColors(img_path: str, num_colors: int) -> list: # scale image down by factor of 10 to decrease computation time dim = (int(len(img[0])/10), int(len(img)/10)) img = cv.resize(img, dim, interpolation= cv.INTER_AREA) - # TODO: implement KMeans clustering from scratch to - # improve program modularity clt = KMeans(n_clusters=num_colors, n_init='auto') clt.fit(img.reshape(-1, 3)) return clt.cluster_centers_ diff --git a/src/get_args.py b/src/get_args.py index ebdf464..45f41cf 100644 --- a/src/get_args.py +++ b/src/get_args.py @@ -2,20 +2,30 @@ import user_interface import manage_saves import os from rich import print + + def get_args(args, walls_dir) -> tuple: # arguments that can be passed into program + VALID_ARGS = ['-r', '-p', '--initialize', '--reconfigure'] + initialize = False reconfigure = False color_save = None - VALID_ARGS = ['-r', '-p', '--initialize', '--reconfigure'] + + # load saved palette if '-p' in args: index = args.index('-p') - if os.path.isfile(args[index + 1]): - color_save = manage_saves.load_color_palette(args[index + 1]) - else: - print('invalid arguments. -p should be followed by a color palette save') - exit(2) + try: + if os.path.isfile(args[index + 1]): + color_save = manage_saves.load_color_palette(args[index + 1]) + else: + print(f'[bold red] Error!! invalid argument {args[index + 1]}. -p should be followed by a color palette save') + exit(2) + except IndexError: + print('[bold red]Error!! -p should be followed by location of a color palette save') + usage(args) + exit(2) if '-r' in args: img_path = user_interface.pickRandomWallpaper(walls_dir) @@ -32,6 +42,7 @@ def get_args(args, walls_dir) -> tuple: reconfigure = True return img_path, initialize, reconfigure, color_save + def usage(args) -> None: print(f"""Instant Rice - An automatic theming utilitiy diff --git a/src/manage_saves.py b/src/manage_saves.py index 988b9a2..1ada559 100644 --- a/src/manage_saves.py +++ b/src/manage_saves.py @@ -3,7 +3,7 @@ from rich import print def save_color_palette(hex_colors, hex_compliments, save_directory): - colors = [hex_colors, hex_compliments] + colors = (hex_colors, hex_compliments) with open(save_directory, 'wb') as file: pickle.dump(colors, file, pickle.HIGHEST_PROTOCOL) diff --git a/src/user_interface.py b/src/user_interface.py index 934098c..4162d1e 100644 --- a/src/user_interface.py +++ b/src/user_interface.py @@ -4,32 +4,42 @@ import color_engine from rich import print -def colorPickerUI(img_path: str, num_palettes: int) -> tuple: +def colorPickerUI(img_path: str, num_palettes: int, saved_colors = None) -> tuple: #display the selected color scheme and ask user if they like it or want to generate a new color scheme - hex_colors, hex_compliments = selectPalette(img_path, num_palettes) + if saved_colors == None: + hex_colors, hex_compliments = selectPalette(img_path, num_palettes) + else: + hex_colors, hex_compliments = saved_colors + print(f'[bold green] colors successfully loaded from file') final_colors, final_compliments = selectColorsFromPalette(hex_colors, hex_compliments) return final_colors, final_compliments +def displayColors(hex_colors: list, hex_compliments: list): + constrast_levels = color_engine.checkContrast(hex_colors, hex_compliments) + main_colors = '' + complimentary_colors = '' + + for color in hex_colors: + main_colors += f'[on {color}] [/on {color}]' + print(main_colors) + for color in hex_compliments: + complimentary_colors += f'[on {color}] [/on {color}]' + print(complimentary_colors, '\n') + for i in range(len(hex_colors)): + print(f'[{hex_compliments[i]} on {hex_colors[i]}]\tGenerated Color Scheme\t\t ({i: 3})', f'contrast: {constrast_levels[i]:.2f}') + + def selectPalette(img_path: str, num_palettes: int) -> tuple: - # + confirmed = False + hex_colors = None + hex_compliments = None while not confirmed: print() popularColors = color_engine.grabColors(img_path, num_palettes) hex_colors = color_engine.rgbToHex(popularColors) hex_compliments = color_engine.compColors(hex_colors) - constrast_levels = color_engine.checkContrast(hex_colors, hex_compliments) - main_colors = '' - complimentary_colors = '' - - for color in hex_colors: - main_colors += f'[on {color}] [/on {color}]' - print(main_colors) - for color in hex_compliments: - complimentary_colors += f'[on {color}] [/on {color}]' - print(complimentary_colors, '\n') - for i in range(len(hex_colors)): - print(f'[{hex_compliments[i]} on {hex_colors[i]}]\tGenerated Color Scheme\t\t ({i: 3})', f'contrast: {constrast_levels[i]:.2f}') + displayColors(hex_colors, hex_compliments) print('[bold](a)ccept palette (g)enerate new palette') response = input('> ') if response == 'a': -- cgit v1.2.3 From 2564189a769a5bd3de63086bb62dc3532d1b07b9 Mon Sep 17 00:00:00 2001 From: Chandler J Date: Sat, 6 Apr 2024 21:53:25 -0600 Subject: added menubutton bind for i3, refactoring --- src/color_engine.py | 18 +++++++++++++----- src/instant_rice.py | 2 +- src/load_config.py | 46 +++++++++++++++++++++++++++++----------------- src/update_i3.py | 10 ++++++---- src/user_interface.py | 8 +++++--- 5 files changed, 54 insertions(+), 30 deletions(-) diff --git a/src/color_engine.py b/src/color_engine.py index c24450b..7a177fb 100644 --- a/src/color_engine.py +++ b/src/color_engine.py @@ -50,9 +50,17 @@ def checkContrast(hex_color_list: list, hex_compliment_list: list) -> list: return contrast_values -def relativeLuminance(color: list): - - threshold = 0.03928 # this whole function is magic constants lol +def relativeLuminance(color: list) -> float: + """ + Determines the luminance of color. The luminance allows us to + compute the contrast between two colors by comparing their + relative luminance. + + The magic constants in this function are all taken from the following + description of relative luminance: + https://www.w3.org/TR/WCAG20/#relativeluminancedef + """ + threshold = 0.03928 channels = [] for channel in color: @@ -86,12 +94,12 @@ def hexToRGB(hex_value: str) -> tuple: Takes in a list of Hex values and returns a tuple of those colors as rgb values """ hex_value = hex_value.lstrip('#') - return tuple(int(hex_value[i:i+2], 16) for i in (0, 2, 4)) # Magic :DDDDDD + return tuple(int(hex_value[i:i+2], 16) for i in (0, 2, 4)) def hexToRGB_list(hex_list: list) -> list: colors = [] for color in hex_list: hex_value = color.lstrip('#') - colors.append(tuple(int(hex_value[i:i+2], 16) for i in (0, 2, 4))) # Magic :DDDDDD + colors.append(tuple(int(hex_value[i:i+2], 16) for i in (0, 2, 4))) return colors diff --git a/src/instant_rice.py b/src/instant_rice.py index e13f67b..e94dc64 100644 --- a/src/instant_rice.py +++ b/src/instant_rice.py @@ -25,6 +25,6 @@ if __name__ == '__main__': if config.rofi_config: update_rofi.updateRofiTheme(config.rofi_config, hex_colors, hex_compliments) if config.i3_config: - update_i3.updatei3Theme(config.i3_config, img_path, hex_colors, hex_compliments, config.generate_i3_lock, config.use_dmenu, config.i3_lock_image) + update_i3.updatei3Theme(config.i3_config, img_path, hex_colors, hex_compliments, config.generate_i3_lock, config.use_dmenu, config.i3_lock_image, config.menu_keybind) else: usage(sys.argv) diff --git a/src/load_config.py b/src/load_config.py index dbc0d81..e28e9c3 100644 --- a/src/load_config.py +++ b/src/load_config.py @@ -9,19 +9,21 @@ class systemConfig: file for instant rice. """ - i3_config = "" - i3_lock_image = "" - polybar_config = "" - wallpaper_directory = "" - rofi_config = "" - username = "" - rice_config = "" - #instant rice configuration settings - num_palettes = 15 - use_dmenu = False - generate_i3_lock = False - + def __init__(self): + self.i3_config = "" + self.i3_lock_image = "" + self.polybar_config = "" + self.wallpaper_directory = "" + self.rofi_config = "" + self.username = "" + self.rice_config = "" + #instant rice configuration settings + self.num_palettes = 15 + self.use_dmenu = False + self.generate_i3_lock = False + self.menu_keybind = "" + print('[bold green]Loading configuration files') #Grab username to find configuration files @@ -64,19 +66,29 @@ class systemConfig: for i, line in enumerate(data): if "use_dmenu" in line: match = line.split(' ') - self.use_dmenu = True if match[2] == 'True' else False + self.use_dmenu = True if match[2].lower() == 'true' else False + if "generate_i3_lock" in line: match = line.split(' ') - self.generate_i3_lock = True if match[2] == 'True' else False + self.generate_i3_lock = True if match[2].lower() == 'true' else False + if "wallpaper_directory" in line: match = line.strip().split(' ') if not match[2].endswith('/'): match[2] += '/' - self.wallpaper_directory = match[2] + if os.path.exists(match[2]): + self.wallpaper_directory = match[2] + else: + print(f'Invalid configuration parameter at line {i}:\n{line}Directory does not exist; Please fix error before rerunning.') + if "num_palettes" in line: match = line.strip().split(' ') if match[2].isdigit(): self.num_palettes = int(match[2]) else: - print(f'Invalid configuration parameter at line {i}:\n{line}.\nUsing default \ - configuration of 15 palettes.') + print(f'Invalid configuration parameter at line {i}:\n{line}Using default configuration of 15 palettes.') + + if "menu_keybind" in line: + match = line.strip().split(' ') + self.menu_keybind = match[2] + print(self.menu_keybind) diff --git a/src/update_i3.py b/src/update_i3.py index 1d4b792..3fc8858 100644 --- a/src/update_i3.py +++ b/src/update_i3.py @@ -12,12 +12,13 @@ def updatei3Theme( update_i3_lock: bool, dmenu: bool, lock_img_path: str, + menu_keybind: str, ) -> None: print('[bold red]Updating i3 color scheme') - update_i3_colors(config_path, colors, compliments, dmenu, img_path) + update_i3_colors(config_path, colors, compliments, dmenu, img_path, menu_keybind) if update_i3_lock: change_i3_lock_img(img_path, lock_img_path) @@ -49,7 +50,8 @@ def update_i3_colors( colors: list, compliments: list, dmenu: bool, - img_path: str + img_path: str, + menu_keybind: str, ) -> None: data = '' with open(config_path, 'r') as file: @@ -72,10 +74,10 @@ def update_i3_colors( if "set $bgimage" in line: data[i] = 'set $bgimage ' + img_path + '\n' # update i3 lock image - if "bindsym $mod+d exec --no-startup-id dmenu_run" in line: + if f"bindsym {menu_keybind} exec --no-startup-id dmenu_run" in line: if dmenu: print('[bold red]Updating Dmenu color scheme') - data[i] = f"bindsym $mod+d exec --no-startup-id dmenu_run -nb '{colors[0]}' -sf '{compliments[0]}' -sb '{colors[1]}' -nf '{compliments[1]}'\n" + data[i] = f"bindsym {menu_keybind} exec --no-startup-id dmenu_run -nb '{colors[0]}' -sf '{compliments[0]}' -sb '{colors[1]}' -nf '{compliments[1]}'\n" with open(config_path, 'w') as file: diff --git a/src/user_interface.py b/src/user_interface.py index 4162d1e..0adc765 100644 --- a/src/user_interface.py +++ b/src/user_interface.py @@ -50,7 +50,8 @@ def selectPalette(img_path: str, num_palettes: int) -> tuple: return hex_colors, hex_compliments -def selectColorsFromPalette(hex_colors, hex_compliments): +def selectColorsFromPalette(hex_colors: list, hex_compliments: list) -> tuple: + selectedColors = [] selected = False while not selected: print('[bold blue]Select top 3 colors from list in order Primary, Secondary, Accent (IE, "4 10 6")') @@ -62,7 +63,7 @@ def selectColorsFromPalette(hex_colors, hex_compliments): else: print('[bold red]Invalid selection. Use positive integers corresponding to color pair to select.') continue - + selectedColors = [int(i) for i in selectedColors] final_colors = [] final_compliments = [] @@ -73,10 +74,11 @@ def selectColorsFromPalette(hex_colors, hex_compliments): return final_colors, final_compliments -def pickRandomWallpaper(walls_dir) -> str: +def pickRandomWallpaper(walls_dir: str) -> str: confirmed = False history = [] num_wallpapers = len(os.listdir(walls_dir)) + wallpaper = '' while not confirmed: if len(history) == num_wallpapers: print('[bold blue] Wallpapers exhausted. Resetting history...') -- cgit v1.2.3