From 139115a0e9da75ca37816323912982fd5511ca2e Mon Sep 17 00:00:00 2001 From: Jordan Date: Tue, 28 Sep 2021 22:53:00 -0400 Subject: [PATCH] Updates to graphing. Modify heaters to show only ones available in the temp store. Add ability to hide/show heaters. --- ks_includes/KlippyGtk.py | 70 ++++++++++++++++++++++- ks_includes/graph.py | 20 ++++++- ks_includes/printer.py | 28 ++++----- panels/main_menu.py | 119 +++++++++++++++++++++++++-------------- styles/base.css | 22 ++++++++ 5 files changed, 200 insertions(+), 59 deletions(-) diff --git a/ks_includes/KlippyGtk.py b/ks_includes/KlippyGtk.py index 883ab147..a8aad754 100644 --- a/ks_includes/KlippyGtk.py +++ b/ks_includes/KlippyGtk.py @@ -36,6 +36,32 @@ class KlippyGtk: self.header_image_scale_height = 1.4 self.cursor = cursor + self.color_list = { + "extruder": { + "base": 'ff5252', + "hsplit": int('20', 16), + "state": 0 + }, + "bed": { + "base": '1fb0ff', + "hsplit": int('20', 16), + "state": 0 + }, + "fan": { + "colors": ['3DC25A', '58FC7C', '10EB40', '7EF297'], + "state": 0 + }, + "sensor": { + "colors": ['D67600', '830EE3', 'B366F2', 'E06573', 'E38819'], + "state": 0 + } + } + + for key in self.color_list: + if "base" in self.color_list[key]: + rgb = [int(self.color_list[key]['base'][i:i+2], 16) for i in range(0, 6, 2)] + self.color_list[key]['rgb'] = rgb + logging.debug("img width: %s height: %s" % (self.img_width, self.img_height)) def get_action_bar_width(self): @@ -65,6 +91,29 @@ class KlippyGtk: def get_keyboard_height(self): return (self.width - self.get_action_bar_width()) * self.keyboard_ratio + def get_temp_color(self, device): + if device not in self.color_list: + return False, False + + if 'base' in self.color_list[device]: + rgb = self.color_list[device]['rgb'].copy() + if self.color_list[device]['state'] > 0: + rgb[1] = rgb[1] + self.color_list[device]['hsplit'] * self.color_list[device]['state'] + self.color_list[device]['state'] += 1 + color = '{:02X}{:02X}{:02X}'.format(rgb[0], rgb[1], rgb[2]) + rgb = [x/255 for x in rgb] + else: + colors = self.color_list[device]['colors'] + color = colors[self.color_list[device]['state'] % len(colors)] + rgb = [int(color[i:i+2], 16)/255 for i in range(0, 6, 2)] + + return rgb, color + + def reset_temp_color(self): + for key in self.color_list: + self.color_list[key]['state'] = 0 + + def Label(self, label, style=None): la = Gtk.Label(label) if style is not None and style is not False: @@ -80,7 +129,7 @@ class KlippyGtk: image = Gtk.Image.new_from_pixbuf(pixbuf) label = Gtk.Label() - label.set_text(text) + label.set_markup(text) box1.add(image) box1.add(label) @@ -90,6 +139,25 @@ class KlippyGtk: return {"l": label, "b": box1} + def ImageMenuButton(self, image_name, text, size=20, style=False, width_scale=.32, height_scale=.32, popover=False): + box1 = Gtk.Box(orientation=Gtk.Orientation.HORIZONTAL, spacing=15) + pixbuf = GdkPixbuf.Pixbuf.new_from_file_at_scale( + "%s/styles/%s/images/%s.svg" % (klipperscreendir, self.theme, str(image_name)), + int(round(self.img_width * width_scale)), int(round(self.img_height * height_scale)), True) + + image = Gtk.Image.new_from_pixbuf(pixbuf) + + mb = Gtk.MenuButton(label="", popover=popover) + label = mb.get_label() + box1.add(image) + box1.add(mb) + + if style is not False: + ctx = box1.get_style_context() + ctx.add_class(style) + + return {"l": label, "mb": mb, "b": box1} + def Image(self, image_name, style=False, width_scale=1, height_scale=1): pixbuf = GdkPixbuf.Pixbuf.new_from_file_at_scale( "%s/styles/%s/images/%s" % (klipperscreendir, self.theme, str(image_name)), diff --git a/ks_includes/graph.py b/ks_includes/graph.py index 9cb08e8f..0616f03f 100644 --- a/ks_includes/graph.py +++ b/ks_includes/graph.py @@ -20,7 +20,7 @@ class HeaterGraph(Gtk.DrawingArea): def add_object(self, name, type, rgb=[0, 0, 0], dashed=False, fill=False): if name not in self.store: - self.store.update({name: {}}) + self.store.update({name: {"show": True}}) self.store[name].update({type: { "dashed": dashed, "fill": fill, @@ -32,6 +32,8 @@ class HeaterGraph(Gtk.DrawingArea): mnum = [] for x in self.store: for t in self.store[x]: + if t == "show": + continue mnum.append(max(self.printer.get_temp_store(x, t, data_points))) return max(mnum) @@ -63,8 +65,10 @@ class HeaterGraph(Gtk.DrawingArea): [g_width, g_height] ] - points_per_pixel = 2 + + points_per_pixel = self.max_length / (gsize[1][0]-gsize[0][0]) data_points = (gsize[1][0]-gsize[0][0]) * points_per_pixel + logging.info("aa: %s %s" % (points_per_pixel, data_points)) max_num = math.ceil(self.get_max_num(data_points) * 1.1 / 10) * 10 d_width = 1 / points_per_pixel @@ -72,6 +76,8 @@ class HeaterGraph(Gtk.DrawingArea): self.graph_time(ctx, gsize, points_per_pixel) for name in self.store: + if not self.store[name]['show']: + continue for type in self.store[name]: d = self.printer.get_temp_store(name, type, data_points) if d is False: @@ -163,3 +169,13 @@ class HeaterGraph(Gtk.DrawingArea): ctx.show_text("%02d:%02d" % (hour, min)) ctx.stroke() i += 1 + + def is_showing(self, device): + if device not in self.store: + return False + return self.store[device]['show'] + + def set_showing(self, device, show=True): + if device not in self.store: + return + self.store[device]['show'] = show diff --git a/ks_includes/printer.py b/ks_includes/printer.py index 5d0cd4d3..9569eded 100644 --- a/ks_includes/printer.py +++ b/ks_includes/printer.py @@ -53,10 +53,6 @@ class Printer: "temperature": 0, "target": 0 } - self.tempstore[x] = { - "temperatures": [0 for x in range(1200)], - "targets": [0 for x in range(1200)] - } self.tools.append(x) self.tools = sorted(self.tools) self.toolcount += 1 @@ -69,10 +65,6 @@ class Printer: "temperature": 0, "target": 0 } - self.tempstore[x] = { - "temperatures": [0 for x in range(1200)], - "targets": [0 for x in range(1200)] - } if x.startswith('bed_mesh '): r = self.config[x] r['x_count'] = int(r['x_count']) @@ -282,6 +274,15 @@ class Printer: def get_extruder_count(self): return self.extrudercount + def get_temp_store_devices(self): + return list(self.tempstore) + + def get_temp_store_device_has_target(self, device): + if device in self.tempstore: + if "targets" in self.tempstore[device]: + return True + return False + def get_temp_store(self, device, section=False, results=0): if device not in self.tempstore: return False @@ -312,11 +313,12 @@ class Printer: def init_temp_store(self, result): for dev in result: - if dev in self.tempstore: - if "targets" in result[dev]: - self.tempstore[dev]["targets"] = result[dev]["targets"] - if "temperatures" in result[dev]: - self.tempstore[dev]["temperatures"] = result[dev]["temperatures"] + self.tempstore[dev] = {} + if "targets" in result[dev]: + self.tempstore[dev]["targets"] = result[dev]["targets"] + if "temperatures" in result[dev]: + self.tempstore[dev]["temperatures"] = result[dev]["temperatures"] + logging.info("Temp store: %s" % list(self.tempstore)) def section_exists(self, section): if section in self.get_config_section_list(): diff --git a/panels/main_menu.py b/panels/main_menu.py index a3de604a..375abf0e 100644 --- a/panels/main_menu.py +++ b/panels/main_menu.py @@ -64,19 +64,45 @@ class MainPanel(MenuPanel): if d.startswith('extruder'): i += 1 image = "extruder-%s" % i + class_name = "graph_label_%s" % device + rgb, color = self._gtk.get_temp_color("extruder") elif device == "heater_bed": image = "bed" devname = "Heater Bed" + class_name = "graph_label_heater_bed" + rgb = [1, 0, 0] + rgb, color = self._gtk.get_temp_color("bed") else: + s = 1 + for d in self.devices: + if "sensor" in d: + s += 1 image = "heat-up" + class_name = "graph_label_sensor_%s" % s + rgb = [1, 0, 0] + rgb, color = self._gtk.get_temp_color("sensor") + + + can_target = self._printer.get_temp_store_device_has_target(device) + self.labels['da'].add_object(device, "temperatures", rgb, False, True) + if can_target: + self.labels['da'].add_object(device, "targets", rgb, True, False) + + text = "%s" % (color, devname.capitalize()) + name = self._gtk.ButtonImage(image, devname.capitalize(), None, .5, .5, Gtk.PositionType.LEFT, False) + # name['b'].set_hexpand(True) + name.connect('clicked', self.on_popover_clicked, device) + name.set_alignment(0, .5) + name.get_style_context().add_class(class_name) + logging.info("DClass %s %s" % (device, class_name)) - name = self._gtk.ImageLabel(image, devname.capitalize(), 20, False, .5, .5) - name['b'].set_hexpand(True) temp = Gtk.Label("") temp.set_markup(self.format_temp(self._printer.get_dev_stat(device, "temperature"))) - target = Gtk.Label("") - target.set_markup(self.format_target(self._printer.get_dev_stat(device, "target"))) + + if can_target: + target = Gtk.Label("") + target.set_markup(self.format_target(self._printer.get_dev_stat(device, "target"))) labels = Gtk.Box(orientation=Gtk.Orientation.VERTICAL) @@ -87,20 +113,45 @@ class MainPanel(MenuPanel): self.devices[device] = { "name": name, - "target": target, - "temp": temp, - + "temp": temp } + if can_target: + self.devices[device]["target"] = target devices = sorted(self.devices) pos = devices.index(device) + 1 self.labels['devices'].insert_row(pos) - self.labels['devices'].attach(name['b'], 0, pos, 1, 1) + # self.labels['devices'].attach(name['b'], 0, pos, 1, 1) + self.labels['devices'].attach(name, 0, pos, 1, 1) self.labels['devices'].attach(temp, 1, pos, 1, 1) - self.labels['devices'].attach(target, 2, pos, 1, 1) + if can_target: + self.labels['devices'].attach(target, 2, pos, 1, 1) self.labels['devices'].show_all() + def on_popover_clicked(self, widget, device): + self.popover_device = device + po = self.labels['popover'] + po.set_relative_to(widget) + self.popover_populate_menu() + po.show_all() + + def popover_populate_menu(self): + pobox = self.labels['popover_vbox'] + for child in pobox.get_children(): + pobox.remove(child) + if self.labels['da'].is_showing(self.popover_device): + pobox.pack_start(self.labels['graph_hide'], True, True, 5) + else: + pobox.pack_start(self.labels['graph_show'], True, True, 5) + + def graph_show_device(self, widget, show=True): + logging.info("Graph show: %s %s" % (self.popover_device, show)) + self.labels['da'].set_showing(self.popover_device, show) + self.labels['da'].queue_draw() + self.popover_populate_menu() + self.labels['popover'].show_all() + def create_left_panel(self): _ = self.lang.gettext @@ -117,19 +168,8 @@ class MainPanel(MenuPanel): self.labels['devices'].attach(temp, 1, 0, 1, 1) self.labels['devices'].attach(target, 2, 0, 1, 1) - rgbs = [ - [0, 1, 0], - [1, 0, 0], - [0, 0, 1] - ] - heaters = ['heater_bed', 'extruder'] - i = 0 da = HeaterGraph(self._printer) da.set_vexpand(True) - for h in heaters: - da.add_object(h, "temperatures", rgbs[i], False, True) - da.add_object(h, "targets", rgbs[i], True, False) - i += 1 self.labels['da'] = da box = Gtk.Box(orientation=Gtk.Orientation.VERTICAL, spacing=0) @@ -137,32 +177,25 @@ class MainPanel(MenuPanel): box.add(self.labels['devices']) box.add(da) - self.load_devices() + + self.labels['graph_hide'] = self._gtk.Button(label="Hide") + self.labels['graph_hide'].connect("clicked", self.graph_show_device, False) + self.labels['graph_show'] = self._gtk.Button(label="Show") + self.labels['graph_show'].connect("clicked", self.graph_show_device) + + popover = Gtk.Popover() + self.labels['popover_vbox'] = Gtk.VBox() + # vbox.pack_start(Gtk.Button(label="Hide"), False, True, 10) + # vbox.pack_start(Gtk.Label(label="Item 2"), False, True, 10) + popover.add(self.labels['popover_vbox']) + popover.set_position(Gtk.PositionType.BOTTOM) + self.labels['popover'] = popover + + for d in self._printer.get_temp_store_devices(): + self.add_device(d) return box - def load_devices(self): - self.heaters = [] - - i = 0 - for x in self._printer.get_tools(): - self.labels[x] = self._gtk.ButtonImage("extruder-"+str(i), self._gtk.formatTemperatureString(0, 0)) - self.heaters.append(x) - i += 1 - - add_heaters = self._printer.get_heaters() - for h in add_heaters: - if h == "heater_bed": - self.labels[h] = self._gtk.ButtonImage("bed", self._gtk.formatTemperatureString(0, 0)) - else: - name = " ".join(h.split(" ")[1:]) - self.labels[h] = self._gtk.ButtonImage("heat-up", name) - self.heaters.append(h) - - for d in self.heaters: - self.add_device(d) - logging.info("Heaters: %s" % self.heaters) - def process_update(self, action, data): if action != "notify_status_update": return diff --git a/styles/base.css b/styles/base.css index 361bf1e8..448fa1be 100644 --- a/styles/base.css +++ b/styles/base.css @@ -430,3 +430,25 @@ trough { .error { background-color: rgba(204, 30, 30, 0.7); } + +popover { + background-color: #222; +} + +popover button { + background-color: #222; +} + +/* Hardcoded values until creation of dynamic CSS updates */ +.graph_label_extruder {border-left: .4em solid #ff5252;} +.graph_label_extruder2 {border-left: .4em solid #ff7252;} +.graph_label_heater_bed {border-left: .4em solid #1fb0ff;} +.graph_label_fan_1 {border-left: .4em solid #3DC25A;} +.graph_label_fan_2 {border-left: .4em solid #58FC7C;} +.graph_label_fan_3 {border-left: .4em solid #10EB40;} +.graph_label_fan_4 {border-left: .4em solid #7EF297;} +.graph_label_sensor_1 {border-left: .4em solid #D67600;} +.graph_label_sensor_2 {border-left: .4em solid #830EE3;} +.graph_label_sensor_3 {border-left: .4em solid #B366F2;} +.graph_label_sensor_4 {border-left: .4em solid #E06573;} +.graph_label_sensor_5 {border-left: .4em solid #E38819;}