# HG changeset patch # User Brad Greco # Date 1617064029 14400 # Node ID eb2aa09653bd7b56a57336d81f13feba180737f2 # Parent 091a1f59a79c4225dc296a1ef78d0fc232173885 beginnings of CPU colors, daemon diff -r 091a1f59a79c -r eb2aa09653bd daemon.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/daemon.py Mon Mar 29 20:27:09 2021 -0400 @@ -0,0 +1,46 @@ +from keyboard_colors.color_profile import ProfileManager, Color +from threading import Event +import keyboard_colors +import keyboard_colors.psutilx.psutilx +import signal + + +class KeyboardColorDaemon: + + transition_wait_time = 100 + + def __init__(self): + signal.signal(signal.SIGINT, self.signal_handler) + self.profile_manager = ProfileManager() + # self.run(keyboard_colors.custom.custom.ColorProfile()) + self.run(keyboard_colors.psutilx.psutilx.ColorProfile()) + + def run(self, profile): + # color = profile.color + color = Color.from_hex('#FF3300') + wait_time = profile.frequency_time - profile.transition_time + transition_steps = int(profile.transition_time / self.transition_wait_time) + + # print(Color.get_step_color(color, profile.next_color(), .3)) + # return + + self.break_event = Event() + while not self.break_event.is_set(): + next_color = profile.next_color() + step_colors = Color.get_steps(color, next_color, transition_steps) + + for step_color in step_colors: + print(step_color) + with open('/sys/devices/platform/system76/leds/system76::kbd_backlight/color_left', 'w') as f: + f.write(step_color.to_hex()) + self.break_event.wait(self.transition_wait_time / 1000) + + color = next_color + self.break_event.wait(wait_time / 1000) + + def signal_handler(self, signal, frame): + self.break_event.set() + + +if __name__ == "__main__": + KeyboardColorDaemon() diff -r 091a1f59a79c -r eb2aa09653bd keyboard_colors/color_profile.py --- a/keyboard_colors/color_profile.py Tue Mar 02 20:17:36 2021 -0500 +++ b/keyboard_colors/color_profile.py Mon Mar 29 20:27:09 2021 -0400 @@ -1,8 +1,10 @@ +import colorsys import gi import importlib import json import os import pathlib +import re import sys import types import uuid @@ -19,6 +21,25 @@ 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') @@ -84,3 +105,84 @@ 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() diff -r 091a1f59a79c -r eb2aa09653bd keyboard_colors/custom/#custom.glade# --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/keyboard_colors/custom/#custom.glade# Mon Mar 29 20:27:09 2021 -0400 @@ -0,0 +1,55 @@ + + + + + + True + False + vertical + + + True + False + + + True + True + True + + + 0 + 0 + + + + + checkbutton + True + True + False + True + + + 0 + 1 + + + + + True + True + + + 0 + 2 + + + + + False + True + 0 + + + + diff -r 091a1f59a79c -r eb2aa09653bd keyboard_colors/custom/custom.glade --- a/keyboard_colors/custom/custom.glade Tue Mar 02 20:17:36 2021 -0500 +++ b/keyboard_colors/custom/custom.glade Mon Mar 29 20:27:09 2021 -0400 @@ -7,10 +7,44 @@ False vertical - + True False - label + + + True + True + True + + + 0 + 0 + + + + + + + + + + + + + + + + + + + + + + + + + + False @@ -18,11 +52,5 @@ 0 - - - - - - diff -r 091a1f59a79c -r eb2aa09653bd keyboard_colors/custom/custom.py --- a/keyboard_colors/custom/custom.py Tue Mar 02 20:17:36 2021 -0500 +++ b/keyboard_colors/custom/custom.py Mon Mar 29 20:27:09 2021 -0400 @@ -1,4 +1,4 @@ -from keyboard_colors.color_profile import ColorProfileBase +from keyboard_colors.color_profile import ColorProfileBase, Color class ColorProfile(ColorProfileBase): @@ -7,3 +7,7 @@ def __init__(self): super().__init__() + self.color = Color.from_hex('#FF3300') + + def next_color(self): + return Color.from_hex('#FF0033') diff -r 091a1f59a79c -r eb2aa09653bd keyboard_colors/psutilx/__init__.py diff -r 091a1f59a79c -r eb2aa09653bd keyboard_colors/psutilx/psutilx.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/keyboard_colors/psutilx/psutilx.py Mon Mar 29 20:27:09 2021 -0400 @@ -0,0 +1,17 @@ +import psutil +from keyboard_colors.color_profile import ColorProfileBase, Color + + +class ColorProfile(ColorProfileBase): + + type_name = 'Custom colors' + color_scale = { + 0: Color.from_hex('#00FF00'), + 100: Color.from_hex('#FF0000'), + } + + def __init__(self): + super().__init__() + + def next_color(self): + return self.color_scale_value(psutil.cpu_percent()) diff -r 091a1f59a79c -r eb2aa09653bd main.py --- a/main.py Tue Mar 02 20:17:36 2021 -0500 +++ b/main.py Mon Mar 29 20:27:09 2021 -0400 @@ -1,7 +1,9 @@ from ui.main_window import MainWindow + def main(): MainWindow().init() + if __name__ == "__main__": main() diff -r 091a1f59a79c -r eb2aa09653bd ui/main_window.py --- a/ui/main_window.py Tue Mar 02 20:17:36 2021 -0500 +++ b/ui/main_window.py Mon Mar 29 20:27:09 2021 -0400 @@ -1,3 +1,4 @@ +import itertools import gi import os from keyboard_colors.color_profile import ProfileManager @@ -50,6 +51,10 @@ window.show_all() Gtk.main() + def load_color_profiles(self): + for profile in self.profile_manager.get_profiles().values(): + self.color_profile_list_store.append([profile.id, profile.name]) + def create_profile(self, widget, profile_type): # todo move to profile manager profile = profile_type() @@ -61,7 +66,8 @@ self.builder.get_object('edit_profile_name_entry').grab_focus() def edit_profile(self, profile): - self.builder.get_object('edit_profile_box').show() + edit_profile_box = self.builder.get_object('edit_profile_box') + edit_profile_box.show() self.builder.get_object('edit_profile_type_name_label').set_text(profile.type_name) self.builder.get_object('edit_profile_name_entry').set_text(profile.name) @@ -71,6 +77,22 @@ edit_profile_details_box.remove(child) edit_profile_details_box.add(profile.build_settings_ui()) + edit_profile_entries = self.find_descendents(edit_profile_box, Gtk.Entry) + pass + + def find_descendents(self, widget, type): + if isinstance(widget, type): + return [widget] + + try: + matches = [] + for child in widget.get_children(): + matches = matches + self.find_descendents(child, type) + return matches + except AttributeError: + return [] + + def profile_tree_view_selection_changed(self, selection): (model, tree_iter) = selection.get_selected() profile_id = model.get_value(tree_iter, 0) @@ -85,10 +107,6 @@ def edit_profile_name_entry_focus_out(self, entry, event): pass - def load_color_profiles(self): - for profile in self.profile_manager.get_profiles().values(): - self.color_profile_list_store.append([profile.id, profile.name]) - class KeyboardSection(Gtk.Grid): def __init__(self, model):