import logging import gi gi.require_version("Gtk", "3.0") from gi.repository import Gtk, GLib from math import pi from ks_includes.KlippyGcodes import KlippyGcodes from ks_includes.screen_panel import ScreenPanel class Panel(ScreenPanel): def __init__(self, screen, title): super().__init__(screen, title) self.da_size = self._gtk.img_scale * 2 self.preview = Gtk.DrawingArea(width_request=self.da_size, height_request=self.da_size) self.preview.set_size_request(-1, self.da_size * 2) self.preview.connect("draw", self.on_draw) self.preview_label = Gtk.Label(label='') self.preset_list = self._gtk.HomogeneousGrid() self.color_data = [0, 0, 0, 0] self.color_order = 'RGBW' self.presets = { "on": [1.0, 1.0, 1.0, 1.0], "off": [0.0, 0.0, 0.0, 0.0] } self.scales = {} self.buttons = [] self.leds = self._printer.get_leds() self.current_led = self.leds[0] if len(self.leds) == 1 else None self.open_selector(None, self.current_led) def color_available(self, idx): return ( (idx == 0 and 'R' in self.color_order) or (idx == 1 and 'G' in self.color_order) or (idx == 2 and 'B' in self.color_order) or (idx == 3 and 'W' in self.color_order) ) def activate(self): if self.current_led is not None: self.set_title(f"{self.current_led}") def set_title(self, title): self._screen.base_panel.set_title(self.prettify(title)) def back(self): if len(self.leds) > 1 and self.current_led: self.set_title(self._screen.panels[self._screen._cur_panels[-1]].title) self.open_selector(led=None) return True return False def open_selector(self, widget=None, led=None): for child in self.content.get_children(): self.content.remove(child) if led is None: self.content.add(self.led_selector()) else: self.content.add(self.color_selector(led)) self.content.show_all() def led_selector(self): self.current_led = None columns = 3 if self._screen.vertical_mode else 4 grid = self._gtk.HomogeneousGrid() for i, led in enumerate(self.leds): name = led.split()[1] if len(led.split()) > 1 else led button = self._gtk.Button(None, name.upper(), style=f"color{(i % 4) + 1}") button.connect("clicked", self.open_selector, led) grid.attach(button, (i % columns), int(i / columns), 1, 1) scroll = self._gtk.ScrolledWindow() scroll.add(grid) return scroll def color_selector(self, led): logging.info(led) self.current_led = led self.set_title(f"{self.current_led}") grid = self._gtk.HomogeneousGrid() self.color_order = self._printer.get_led_color_order(led) if self.color_order is None: self.back() return scale_grid = self._gtk.HomogeneousGrid() for idx, col_value in enumerate(self.color_data): if not self.color_available(idx): continue color = [0, 0, 0, 0] color[idx] = 1 button = self._gtk.Button() preview = Gtk.DrawingArea(width_request=self.da_size, height_request=self.da_size) preview.connect("draw", self.on_draw, color) button.set_image(preview) button.connect("clicked", self.apply_preset, color) button.set_hexpand(False) scale = Gtk.Scale.new_with_range(orientation=Gtk.Orientation.HORIZONTAL, min=0, max=255, step=1) scale.set_value(round(col_value * 255)) scale.set_digits(0) scale.set_hexpand(True) scale.set_has_origin(True) scale.get_style_context().add_class("fan_slider") scale.connect("button-release-event", self.apply_scales) scale.connect("value_changed", self.update_preview) self.scales[idx] = scale scale_grid.attach(button, 0, idx, 1, 1) scale_grid.attach(scale, 1, idx, 3, 1) grid.attach(scale_grid, 0, 0, 3, 1) columns = 3 if self._screen.vertical_mode else 2 data_misc = self._screen.apiclient.send_request( "server/database/item?namespace=mainsail&key=miscellaneous.entries") if data_misc: presets_data = data_misc['result']['value'][next(iter(data_misc["result"]["value"]))]['presets'] if presets_data: self.presets.update(self.parse_presets(presets_data)) for i, key in enumerate(self.presets): logging.info(f'Adding preset: {key}') preview = Gtk.DrawingArea(width_request=self.da_size, height_request=self.da_size) preview.connect("draw", self.on_draw, self.presets[key]) button = self._gtk.Button() button.set_image(preview) button.connect("clicked", self.apply_preset, self.presets[key]) self.preset_list.attach(button, i % columns, int(i / columns) + 1, 1, 1) scroll = self._gtk.ScrolledWindow() scroll.add(self.preset_list) preview_box = Gtk.Box(orientation=Gtk.Orientation.HORIZONTAL) preview_box.add(self.preview_label) preview_box.add(self.preview) preview_box.set_homogeneous(True) box = Gtk.Box(orientation=Gtk.Orientation.VERTICAL) box.add(preview_box) box.add(scroll) if self._screen.vertical_mode: grid.attach(box, 0, 1, 3, 1) else: grid.attach(box, 3, 0, 2, 1) return grid def on_draw(self, da, ctx, color=None): if color is None: color = self.color_data ctx.set_source_rgb(color[0], color[1], color[2]) # Set the size of the rectangle width = height = da.get_allocated_width() * .9 x = da.get_allocated_width() * .05 # Set the radius of the corners radius = width / 2 * 0.2 ctx.arc(x + radius, radius, radius, pi, 3 * pi / 2) ctx.arc(x + width - radius, radius, radius, 3 * pi / 2, 0) ctx.arc(x + width - radius, height - radius, radius, 0, pi / 2) ctx.arc(x + radius, height - radius, radius, pi / 2, pi) ctx.close_path() ctx.fill() def update_preview(self, args): self.update_color_data() self.preview.queue_draw() self.preview_label.set_label(self.rgbw_to_hex(self.color_data)) def process_update(self, action, data): if action != 'notify_status_update': return if self.current_led in data and "color_data" in data[self.current_led]: self.update_scales(data[self.current_led]["color_data"][0]) self.preview.queue_draw() def update_scales(self, color_data): for idx in self.scales: self.scales[idx].set_value(int(color_data[idx] * 255)) self.color_data[idx] = color_data[idx] def update_color_data(self): for idx in self.scales: self.color_data[idx] = round(self.scales[idx].get_value() / 255, 4) def apply_preset(self, widget, color_data): self.update_scales(color_data) self.apply_scales() def apply_scales(self, *args): self.update_color_data() self.set_led_color(self.color_data) def set_led_color(self, color_data): name = self.current_led.split()[1] if len(self.current_led.split()) > 1 else self.current_led self._screen._send_action(None, "printer.gcode.script", {"script": KlippyGcodes.set_led_color(name, color_data)}) @staticmethod def parse_presets(presets_data) -> {}: parsed = {} for i, preset in enumerate(presets_data.values()): name = i if preset["name"] == '' else preset["name"].lower() parsed[name] = [] for color in ["red", "green", "blue", "white"]: if color not in preset or preset[color] is None: parsed[name].append(0) continue parsed[name].append(round(preset[color] / 255, 4)) return parsed @staticmethod def rgbw_to_hex(color): hex_color = '#' for value in color[:3]: int_value = round(value * 255) hex_color += hex(int_value)[2:].zfill(2) alpha = round(color[3] * 255) hex_color += hex(alpha)[2:].zfill(2) return hex_color.upper()