Mercurial > system76-keyboard-colors
view keyboard_colors/color_profile.py @ 3:eb2aa09653bd default tip
beginnings of CPU colors, daemon
author | Brad Greco <brad@bgreco.net> |
---|---|
date | Mon, 29 Mar 2021 20:27:09 -0400 |
parents | 091a1f59a79c |
children |
line wrap: on
line source
import colorsys import gi import importlib import json import os import pathlib import re import sys import types import uuid from types import SimpleNamespace gi.require_version("Gtk", "3.0") from gi.repository import Gtk # noqa: E402 from gi.repository import GLib # noqa: E402 class ColorProfileBase: type_name = '(no name)' def __init__(self): self.name = '' self.id = str(uuid.uuid4()) self.transition_time = 1000 self.frequency_time = 1000 def color_scale_value(self, value): if value in self.color_scale: return self.color_scale[value] thresholds = self.color_scale.keys() thresholds_below = (i for i in thresholds if i < value) thresholds_above = (i for i in thresholds if i > value) threshold_below = max(thresholds_below, default=min(thresholds)) threshold_above = min(thresholds_above, default=max(thresholds)) percent = value / (threshold_above - threshold_below) return Color.get_step_color( self.color_scale[threshold_below], self.color_scale[threshold_above], percent ) def build_settings_ui(self): glade_file = sys.modules[self.__module__].__file__.replace('.py', '.glade') builder = Gtk.Builder() builder.add_from_file(glade_file) return builder.get_object('edit_profile_container') def serialize(self): properties = self.__dict__ properties['module'] = self.__class__.__module__ return properties @staticmethod def unserialize(data): profile_module = importlib.import_module(data['module']) profile_class = getattr(profile_module, 'ColorProfile') profile = profile_class() profile.__dict__.update(data) return profile class ProfileManager: def __init__(self): profile_list = self.load_profiles() self.profiles = {p.id: p for p in profile_list} def get_types(self): types = [] profile_directory = os.path.dirname(os.path.realpath(__file__)) (_, dirnames, _) = next(os.walk(profile_directory)) for dirname in dirnames: module_file = os.path.join(profile_directory, dirname, dirname + '.py') if os.path.isfile(module_file): module_name = 'keyboard_colors.' + dirname + '.' + dirname profile_module = importlib.import_module(module_name) profile_class = getattr(profile_module, 'ColorProfile') types.append(profile_class) return types def config_path(self): dir = GLib.get_user_config_dir() if not os.path.isdir(dir): os.mkdir(dir) return os.path.join(dir, 'keyboard-color-profiles.conf') def load_profiles(self): if os.path.isfile(self.config_path()): data = pathlib.Path(self.config_path()).read_text('utf-8') try: return json.loads(data, object_hook=lambda d: ColorProfileBase.unserialize(d)) except json.decoder.JSONDecodeError: return [] else: return [] def save_profiles(self): data = json.dumps(self.profiles, default=lambda o: o.serialize()) pathlib.Path(self.config_path()).write_text(data, 'utf-8') def get_profiles(self): return self.profiles def get_profile(self, profile_id): return self.get_profiles()[profile_id] class Color: def __init__(self, r, g, b): self.r = r self.g = g self.b = b @staticmethod def from_hsv(h, s, v): return Color(*colorsys.hsv_to_rgb(h, s, v)) def to_hsv(self): return colorsys.rgb_to_hsv(self.r, self.g, self.b) @staticmethod def from_hex(hex): hex = hex.strip().strip('#').lower() if not re.match('[0-9a-f]{6}', hex): raise ValueError('Invalid hex color string: ' + hex) r = int(hex[0:2], 16) / 255 g = int(hex[2:4], 16) / 255 b = int(hex[4:6], 16) / 255 return Color(r, g, b) def to_hex(self): return format(int(self.r * 255), '02x') \ + format(int(self.g * 255), '02x') \ + format(int(self.b * 255), '02x') @staticmethod def get_steps(start_color, end_color, step_count): # (start_h, start_s, start_v) = start_color.to_hsv() # (end_h, end_s, end_v) = end_color.to_hsv() # # Find the shortest distance between the two hues. # if abs(start_h - end_h) < 0.5: # h_step = (end_h - start_h) / step_count # else: # h_step = (1 - abs(end_h - start_h)) / step_count # if (start_h < end_h): # h_step = h_step * -1 # steps = [] # for i in range(0, step_count): # h = (start_h + h_step * i) % 1 # s = start_s + (end_s - start_s) / step_count * i # v = start_v + (end_v - start_v) / step_count * i # steps.append(Color.from_hsv(h, s, v)) steps = [] for i in range(0, step_count): percent = i / step_count steps.append(Color.get_step_color(start_color, end_color, percent)) return steps @staticmethod def get_step_color(start_color, end_color, percent): (start_h, start_s, start_v) = start_color.to_hsv() (end_h, end_s, end_v) = end_color.to_hsv() # Find the shortest distance between the two hues. if abs(start_h - end_h) < 0.5: h_diff = end_h - start_h else: h_diff = 1 - abs(end_h - start_h) if (start_h < end_h): h_diff = h_diff * -1 h = (start_h + h_diff * percent) % 1 s = start_s + (end_s - start_s) * percent v = start_v + (end_v - start_v) * percent return Color.from_hsv(h, s, v) def __repr__(self): return 'Color #' + self.to_hex()