From 8a8c6c064cc6d097b1b34a5c42b4001367e545a6 Mon Sep 17 00:00:00 2001 From: Alfredo Monclus Date: Tue, 11 Jan 2022 02:39:42 -0300 Subject: [PATCH] Graph in temp panel, combine preheat and temp (#393) * Graph in temp panel, combine preheat and temp * Fix target not working properly * Fix initial preselect * Add the ability to change in delta temps * Make the label translatable * Add Unit to the label * Add de/select button to popover * Warn the user if nothing was selected * Fix templabel * Fix to comply with pep8 * Fix colors, thanks Jordan * Fix popover selection * Update docs image * Gain horizontal space * Gain even more horizontal space (remove target) * Fix temperature_fan * Add icon and style to temperature_fan * List preheat deprecation in breaking changes * Use the printer maximum temperature * Cleanup target and fix popover select * Fix codestyle * Add extra preheat presets * Change Class name * Update docs image * Improve Maximum temperature handling and Temperature fans --- docs/Configuration.md | 2 + docs/changelog.md | 5 + docs/img/preheat.png | Bin 9644 -> 0 bytes docs/img/temperature.png | Bin 11458 -> 17512 bytes docs/panels.md | 7 +- ks_includes/KlippyGcodes.py | 2 - ks_includes/config.py | 1 + ks_includes/defaults.conf | 19 +- ks_includes/screen_panel.py | 2 +- panels/preheat.py | 153 ---------- panels/temperature.py | 498 ++++++++++++++++++++++++------- styles/base.css | 4 + styles/material-darker/style.css | 1 + styles/z-bolt/style.css | 1 + 14 files changed, 414 insertions(+), 281 deletions(-) delete mode 100644 docs/img/preheat.png delete mode 100644 panels/preheat.py diff --git a/docs/Configuration.md b/docs/Configuration.md index 4ee91e52..366cbd6a 100644 --- a/docs/Configuration.md +++ b/docs/Configuration.md @@ -69,6 +69,8 @@ bed: 40 extruder: 195 # Temperature for generic heaters heater_generic: 40 +# Temperature controlled fans (temperature_fan in klipper config) +temperature_fan: 40 # optional GCode to run when the option is selected gcode: MY_HEATSOAK_MACRO ``` diff --git a/docs/changelog.md b/docs/changelog.md index ac007b71..40e97b42 100644 --- a/docs/changelog.md +++ b/docs/changelog.md @@ -2,6 +2,11 @@ Breaking changes will be listed here. +#### 2022 01 09 +* The Preheat panel has been deprecated in favor of an all in one Temperature panel + +Remove preheat panel from your Klipperscreen.conf or replace the occurrences of preheat with temperature + #### 2021 05 20 * Default configuration is not merged if a user configuration is set for a specific option diff --git a/docs/img/preheat.png b/docs/img/preheat.png deleted file mode 100644 index 1d36587e7ee4f4a2369b14a9fb3b5cfa1f4667da..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 9644 zcmb_?cQ{*p_;*^=R-^XbTC=U%qfvX-Dy5=YMU5z8#p)A9Q4~e(C~C*vLW@>W6}v{L z9V52J_B%Yk^{(SC}$cKhn)D&zKAP|UJM_b(l1iJDE_`6Sb z6*#h1EGGth5P7NTn30i@P0ktt=LGF_)WK$c6ZlMVzlkU8uSJD!L5#O4)HT#eo?SKm zr||86zwYbv2+=aUCGRADcJ=l@AMfj{>#LgqFW@lW#R&`GboN13;?QT_kdwMxJbJCw zQchkzKVoTV_JoUL#2Eyth~Rig0s@h-fk3p#JJb5&^s3H&?KTLH#m>zFYSmS+8YX;zB&eG}7k`ZZxE^mY0 zs&bCC_PKI=?d|iK4Bgij0#5OnEK(eC1?L7N^6v{0EP0*c9ri@i`W#v}$JnVe<<8`j z)3t_He7v76KhUZQQ&pRH3#zt|JGkTL$5Gf7yyMsMWaDsb1=5@#m)*ZO(CFj4uRvh( zH`-6^Zj`t{QaUEy7)xjxO$^-IHmfbk(0Py(yb=lG>fCZlz#+ zCbgHzLJal{kU)oMJUo)r;@ICI5m#B=Kel7(kzDUQU*I8opd)5#K3~J@n>p->?_>#L z_n$$lW9X+H?(`n>Hf{cen~W*a!Zs>b-9K%4bB#HKIQ&ZDC*2|Nb{+X(&%8IPkt4@^ zZJV{CvZ2Q1s`R8S%vy4fgyyk4^di|33W+v8Q%n77B~ zWLD|WodCWhLE}6cfyEV*Q*6*Ri2SEI3b3AtI6X&P7rWMHXo;Y21Cj=nG1{Drm%|g> zdg~@Le?^7m*%nY_Y?6p~HN!KHC2$9p(@#zv%i0!yu#3y;DIsT)ZI!5 zyqyrx-BOV!l#lu(k|4`h32CaiM{ILgtQ#^qCo0x^(_f%k;7GPL*!pf8<#Zt1hv-dy zUQXWbNnU5B=K^-0;97HrlKyc!1n;A>pd>_=7zMnl7@04#n4pfSKFFTB-d+C@+tU7( z=eWU&*5*KA(IJ_+2x_z4F6#8n(ClNZ`QliLq)uesAmUMctlitC&ey4hrYLjnj^$fB zNs|xm;OOtI|`fE2(58h@xR$1UH1r&14Rgf#iRx6DZjmKqzcmp_EO3;e=FGj;PA7IvDWj{)hM zJuc7GMo{Lw>XZX2ATjl8=bq7Z5D08xH@r6Y1V6LwH+6{V zHu^_7N?66G30paB@Khy5++wsU ze%#(DuatDq+%@Ki)};&2t8a4!^jjS>k(2tBJu;KD!_I*$vu^ibS+1?XTkXylL+WLb zDpf!c<{ARFcb$M*=eY6vP$WzA$y zTC9lHGe>W{(}#s@!-Cnk_p%_+Q#Y_y+b7udoXulKABZl#^9Pw#(wXQS5G211FGIflz5H_A>1hW@!Ts5J+)NAdp2n#j8erRMeY(nljB$4fLAxdbMbDZl9Ow z=4-~&DD~zSmMJnF>mX1aW6cX@BQxU%S;9R7cmke8%hqxZH=dmu)EIa~&R`A#$uPsd znQeYQt@-dMU|=BGvnFj7?P?S984lQ*7iZ-r#qt6Fj|q!biTV2_uiNhXy58{0yq^kO zK)Vk|#?C1LPUI@2$QrNabj)8VVEviR?8 zIk*%@RF6fa*YbmiEmqJ|Qp6)`h(U2(i!Mjmy6fYS{GwQ`x|XY;-;v0;IqJp|*%(Hx z>sq<_KF|!A&*zmd#em2q7MDYb-riXt*gvoD34{O9vPYu2e9^f}uZF$r9D zKk3Pb=s1^OwW4Q?lquv*r#bUMgwI1o_MfL^N;-1=#^L4>>KIT(@sqiEd%Z@rMnJ

#%>J3gi3~PbfJKxuin=T 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 literal 11458 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 diff --git a/docs/panels.md b/docs/panels.md index ca068323..899610f5 100644 --- a/docs/panels.md +++ b/docs/panels.md @@ -68,11 +68,6 @@ type: power ![Power](img/power.png) -### Preheat -type: preheat - -![Preheat Panel](img/preheat.png) - ### Print type: print @@ -89,7 +84,7 @@ type: system ![System Panel](img/system.png) ### Temperature -type: temperature theme:material-light +type: temperature theme:custom ![Temperature](img/temperature.png) diff --git a/ks_includes/KlippyGcodes.py b/ks_includes/KlippyGcodes.py index 43a4b910..21b19e23 100644 --- a/ks_includes/KlippyGcodes.py +++ b/ks_includes/KlippyGcodes.py @@ -16,10 +16,8 @@ class KlippyGcodes: EXTRUDE_REL = "M83" SET_EXT_TEMP = "M104" - MAX_EXT_TEMP = 450 SET_BED_TEMP = "M140" - MAX_BED_TEMP = 150 SET_EXT_FACTOR = "M221" SET_FAN_SPEED = "M106" diff --git a/ks_includes/config.py b/ks_includes/config.py index ca192988..2c3145dc 100644 --- a/ks_includes/config.py +++ b/ks_includes/config.py @@ -419,6 +419,7 @@ class KlipperScreenConfig: "extruder": cfg.getint("extruder", 0), "bed": cfg.getint("bed", 0), "heater_generic": cfg.getint("heater_generic", 0), + "temperature_fan": cfg.getint("temperature_fan", 0), "gcode": cfg.get("gcode", None) } return item diff --git a/ks_includes/defaults.conf b/ks_includes/defaults.conf index a00faa7c..587f6c84 100644 --- a/ks_includes/defaults.conf +++ b/ks_includes/defaults.conf @@ -10,6 +10,14 @@ extruder = 195 bed = 90 extruder = 220 +[preheat PETG] +bed = 80 +extruder = 240 + +[preheat FLEX] +bed = 0 +extruder = 210 + [menu __main] name: {{ gettext('Main Menu') }} @@ -17,10 +25,10 @@ name: {{ gettext('Main Menu') }} name: {{ gettext('Homing') }} icon: home -[menu __main preheat] -name: {{ gettext('Preheat') }} +[menu __main temperature] +name: {{ gettext('Temperature') }} icon: heat-up -panel: preheat +panel: temperature [menu __main actions] name: {{ gettext('Actions') }} @@ -95,11 +103,6 @@ name: {{ gettext('Fan') }} icon: fan panel: fan -[menu __main actions temperature] -name: {{ gettext('Temperature') }} -icon: heat-up -panel: temperature - [menu __main actions macros] name: {{ gettext('Macros') }} icon: custom-script diff --git a/ks_includes/screen_panel.py b/ks_includes/screen_panel.py index 016e423e..0d577408 100644 --- a/ks_includes/screen_panel.py +++ b/ks_includes/screen_panel.py @@ -44,7 +44,7 @@ class ScreenPanel: if temp <= 0: return "" else: - return self.format_temp(temp, 0) + return ("(%s)" % str(int(temp))) def format_temp(self, temp, places=1): if places == 0: diff --git a/panels/preheat.py b/panels/preheat.py deleted file mode 100644 index 5213adbe..00000000 --- a/panels/preheat.py +++ /dev/null @@ -1,153 +0,0 @@ -import gi -import logging - -gi.require_version("Gtk", "3.0") -from gi.repository import Gtk, Gdk, GLib - -from ks_includes.screen_panel import ScreenPanel - -def create_panel(*args): - return PreheatPanel(*args) - -class PreheatPanel(ScreenPanel): - active_heaters = [] - - def initialize(self, panel_name): - _ = self.lang.gettext - self.preheat_options = self._screen._config.get_preheat_options() - logging.debug("Preheat options: %s" % self.preheat_options) - - grid = self._gtk.HomogeneousGrid() - - eq_grid = Gtk.Grid() - eq_grid.set_hexpand(True) - eq_grid.set_vexpand(True) - - self.heaters = [] - i = 0 - for x in self._printer.get_tools(): - if i == 0: - primary_tool = x - self.labels[x] = self._gtk.ToggleButtonImage("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.startswith("temperature_sensor "): - continue - 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) - - i = 0 - cols = 3 if len(self.heaters) > 4 else (1 if len(self.heaters) <= 2 else 2) - for h in self.heaters: - self.labels[h].connect('clicked', self.select_heater, h) - eq_grid.attach(self.labels[h], i % cols, int(i/cols), 1, 1) - i += 1 - - - self.labels["control_grid"] = self._gtk.HomogeneousGrid() - - i = 0 - for option in self.preheat_options: - self.labels[option] = self._gtk.Button(option, "color%d" % ((i % 4)+1)) - self.labels[option].connect("clicked", self.set_temperature, option) - self.labels['control_grid'].attach( - self.labels[option], - i % 2, int(i/2), 1, 1) - i += 1 - - - cooldown = self._gtk.ButtonImage('cool-down', _('Cooldown'), "color%d" % ((i % 4)+1)) - cooldown.connect("clicked", self.set_temperature, "cooldown") - - row = int(i/2) if i % 2 == 0 else int(i/2)+1 - self.labels["control_grid"].attach(cooldown, i % 2, int(i/2), 1, 1) - - i += 1 - temperature = self._gtk.ButtonImage('heat-up', _('Temperature'), "color%d" % ((i % 4)+1)) - temperature.connect("clicked", self.menu_item_clicked, "temperature", { - "name": "Temperature", - "panel": "temperature" - }) - self.labels["control_grid"].attach(temperature, i % 2, int(i/2), 1, 1) - - grid.attach(eq_grid, 0, 0, 1, 1) - grid.attach(self.labels["control_grid"], 1, 0, 1, 1) - - self.content.add(grid) - - def activate(self): - for x in self._printer.get_tools(): - if x not in self.active_heaters: - self.select_heater(None, x) - - for h in self._printer.get_heaters(): - if h.startswith("temperature_sensor "): - continue - if h not in self.active_heaters: - self.select_heater(None, h) - - def select_heater(self, widget, heater): - if heater in self.active_heaters: - self.active_heaters.pop(self.active_heaters.index(heater)) - self.labels[heater].get_style_context().remove_class('button_active') - return - - self.active_heaters.append(heater) - self.labels[heater].get_style_context().add_class('button_active') - - def set_temperature(self, widget, setting): - if setting == "cooldown": - for heater in self.active_heaters: - logging.info("Setting %s to %d" % (heater, 0)) - if heater.startswith('heater_generic '): - self._screen._ws.klippy.set_heater_temp(" ".join(heater.split(" ")[1:]), 0) - elif heater.startswith('heater_bed'): - self._screen._ws.klippy.set_bed_temp(0) - self._printer.set_dev_stat(heater, "target", 0) - else: - self._screen._ws.klippy.set_tool_temp(self._printer.get_tool_number(heater), 0) - self._printer.set_dev_stat(heater, "target", 0) - return - - for heater in self.active_heaters: - if heater.startswith('heater_generic '): - logging.info("Setting %s to %d" % (heater, self.preheat_options[setting]['heater_generic'])) - self._screen._ws.klippy.set_heater_temp(" ".join(heater.split(" ")[1:]), - self.preheat_options[setting]["heater_generic"]) - elif heater.startswith('heater_bed'): - logging.info("Setting %s to %d" % (heater, self.preheat_options[setting]['bed'])) - self._screen._ws.klippy.set_bed_temp(self.preheat_options[setting]["bed"]) - self._printer.set_dev_stat(heater, "target", int(self.preheat_options[setting]["bed"])) - else: - logging.info("Setting %s to %d" % (heater, self.preheat_options[setting]['extruder'])) - self._screen._ws.klippy.set_tool_temp(self._printer.get_tool_number(heater), - self.preheat_options[setting]["extruder"]) - self._printer.set_dev_stat(heater, "target", int(self.preheat_options[setting]["extruder"])) - - if self.preheat_options[setting]['gcode']: - self._screen._ws.klippy.gcode_script(self.preheat_options[setting]['gcode']) - - def process_update(self, action, data): - if action != "notify_status_update": - return - - for x in self._printer.get_tools(): - self.update_temp( - x, - self._printer.get_dev_stat(x, "temperature"), - self._printer.get_dev_stat(x, "target") - ) - for h in self._printer.get_heaters(): - self.update_temp( - h, - self._printer.get_dev_stat(h, "temperature"), - self._printer.get_dev_stat(h, "target"), - None if h == "heater_bed" else " ".join(h.split(" ")[1:]) - ) diff --git a/panels/temperature.py b/panels/temperature.py index eff478ad..6cbaa7b2 100644 --- a/panels/temperature.py +++ b/panels/temperature.py @@ -1,69 +1,85 @@ -# -*- coding: utf-8 -*- +import datetime import gi +import math import logging gi.require_version("Gtk", "3.0") -from gi.repository import Gtk, Gdk, GLib +from gi.repository import Gtk, Gdk, GLib, Pango -from ks_includes.KlippyGcodes import KlippyGcodes from ks_includes.screen_panel import ScreenPanel +from ks_includes.KlippyGcodes import KlippyGcodes +from ks_includes.widgets.graph import HeaterGraph from ks_includes.widgets.keypad import Keypad def create_panel(*args): return TemperaturePanel(*args) class TemperaturePanel(ScreenPanel): - active_heater = "extruder" - tempdeltas = ["1", "5", "10", "25"] - tempdelta = "10" + active_heaters = [] + devices = {} + graph_update = None + active_heater = None def initialize(self, panel_name): + self.preheat_options = self._screen._config.get_preheat_options() + logging.debug("Preheat options: %s" % self.preheat_options) + self.show_preheat = True + self._gtk.reset_temp_color() + self.grid = self._gtk.HomogeneousGrid() + self.grid.attach(self.create_left_panel(), 0, 0, 1, 1) + self.grid.attach(self.create_right_panel(), 1, 0, 1, 1) + self.content.add(self.grid) + self.layout.show_all() + + def create_right_panel(self): _ = self.lang.gettext - grid = self._gtk.HomogeneousGrid() + cooldown = self._gtk.ButtonImage('cool-down', _('Cooldown'), "color4", 1, 1, Gtk.PositionType.LEFT, False) + adjust = self._gtk.ButtonImage('fine-tune', '', "color3", 1, 1, Gtk.PositionType.LEFT, False) - eq_grid = Gtk.Grid() - eq_grid.set_hexpand(True) - eq_grid.set_vexpand(True) + right = self._gtk.HomogeneousGrid() + right.attach(cooldown, 0, 0, 2, 1) + right.attach(adjust, 2, 0, 1, 1) + if self.show_preheat: + right.attach(self.preheat(), 0, 1, 3, 4) + else: + right.attach(self.delta_adjust(), 0, 1, 3, 4) - self.heaters = [] - i = 0 - tools = self._printer.get_tools() - for x in tools: - self.labels[x] = self._gtk.ToggleButtonImage("extruder-"+str(i), self._gtk.formatTemperatureString(0, 0)) - if i == 0: - self.labels[x].set_active(True) - self.heaters.append(x) - i += 1 + cooldown.connect("clicked", self.set_temperature, "cooldown") + adjust.connect("clicked", self.switch_preheat_adjust) - if len(tools) > 0: - self.labels[tools[0]].get_style_context().add_class('button_active') + return right - 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) + def switch_preheat_adjust(self, widget): + self.show_preheat ^= True + self.grid.remove_column(1) + self.grid.attach(self.create_right_panel(), 1, 0, 1, 1) + self.grid.show_all() - i = 0 - cols = 3 if len(self.heaters) > 4 else (1 if len(self.heaters) <= 2 else 2) - for h in self.heaters: - if not (h.startswith("temperature_sensor")): - self.labels[h].connect('clicked', self.select_heater, h) - eq_grid.attach(self.labels[h], i % cols, int(i/cols), 1, 1) - i += 1 + def preheat(self): + self.labels["preheat_grid"] = self._gtk.HomogeneousGrid() + for i, option in enumerate(self.preheat_options): + self.labels[option] = self._gtk.Button(option, "color%d" % ((i % 4)+1)) + self.labels[option].connect("clicked", self.set_temperature, option) + self.labels['preheat_grid'].attach(self.labels[option], (i % 2), int(i/2), 1, 1) + scroll = Gtk.ScrolledWindow() + scroll.set_property("overlay-scrolling", False) + scroll.set_hexpand(True) + scroll.set_vexpand(True) + scroll.set_policy(Gtk.PolicyType.NEVER, Gtk.PolicyType.AUTOMATIC) + scroll.add(self.labels["preheat_grid"]) + return scroll - self.labels["control_grid"] = self._gtk.HomogeneousGrid() + def delta_adjust(self): + _ = self.lang.gettext + self.tempdeltas = ["1", "5", "10", "25"] + self.tempdelta = "10" + deltagrid = self._gtk.HomogeneousGrid() self.labels["increase"] = self._gtk.ButtonImage("increase", _("Increase"), "color1") self.labels["increase"].connect("clicked", self.change_target_temp_incremental, "+") self.labels["decrease"] = self._gtk.ButtonImage("decrease", _("Decrease"), "color3") self.labels["decrease"].connect("clicked", self.change_target_temp_incremental, "-") - self.labels["npad"] = self._gtk.ButtonImage("hashtag", _("Number Pad"), "color2") - self.labels["npad"].connect("clicked", self.show_numpad) tempgrid = Gtk.Grid() j = 0 @@ -72,34 +88,26 @@ class TemperaturePanel(ScreenPanel): self.labels['deg' + i].connect("clicked", self.change_temp_delta, i) ctx = self.labels['deg' + i].get_style_context() if j == 0: - ctx.add_class("tempbutton_top") + ctx.add_class("distbutton_top") elif j == len(self.tempdeltas)-1: - ctx.add_class("tempbutton_bottom") + ctx.add_class("distbutton_bottom") else: - ctx.add_class("tempbutton") + ctx.add_class("distbutton") if i == "10": ctx.add_class("distbutton_active") - tempgrid.attach(self.labels['deg' + i], 0, j, 1, 1) + tempgrid.attach(self.labels['deg' + i], j, 0, 1, 1) j += 1 self.labels["deg" + self.tempdelta].set_active(True) vbox = Gtk.VBox() - vbox.pack_start(Gtk.Label("Temp °C"), False, False, 4) - vbox.pack_end(tempgrid, True, True, 0) + vbox.pack_start(Gtk.Label(_("Temperature") + " (°C)"), False, False, 8) + vbox.pack_end(tempgrid, True, True, 2) - self.labels["control_grid"].attach(vbox, 2, 0, 1, 3) - self.labels["control_grid"].attach(self.labels["increase"], 3, 0, 1, 1) - self.labels["control_grid"].attach(self.labels["decrease"], 3, 1, 1, 1) - self.labels["control_grid"].attach(self.labels["npad"], 3, 2, 1, 1) - - grid.attach(eq_grid, 0, 0, 1, 1) - grid.attach(self.labels["control_grid"], 1, 0, 1, 1) - - self.grid = grid - self.content.add(grid) - - self.update_temp("heater_bed", 35, 40) + deltagrid.attach(vbox, 0, 3, 2, 2) + deltagrid.attach(self.labels["decrease"], 0, 0, 1, 3) + deltagrid.attach(self.labels["increase"], 1, 0, 1, 3) + return deltagrid def change_temp_delta(self, widget, tempdelta): if self.tempdelta == tempdelta: @@ -117,35 +125,306 @@ class TemperaturePanel(ScreenPanel): continue self.labels["deg" + str(i)].set_active(False) - def show_numpad(self, widget): + def change_target_temp_incremental(self, widget, dir): + _ = self.lang.gettext + if len(self.active_heaters) == 0: + self._screen.show_popup_message(_("Nothing selected")) + else: + for heater in self.active_heaters: + target = self._printer.get_dev_stat(heater, "target") + if dir == "+": + target += int(self.tempdelta) + MAX_TEMP = int(self._printer.get_config_section(heater)['max_temp']) + if target > MAX_TEMP: + target = MAX_TEMP + self._screen.show_popup_message(_("Can't set above the maximum:") + (" %s" % MAX_TEMP)) + else: + target -= int(self.tempdelta) + if target < 0: + target = 0 + if heater.startswith('extruder'): + self._screen._ws.klippy.set_tool_temp(self._printer.get_tool_number(heater), target) + elif heater.startswith('heater_bed'): + self._screen._ws.klippy.set_bed_temp(target) + elif heater.startswith('heater_generic '): + self._screen._ws.klippy.set_heater_temp(" ".join(heater.split(" ")[1:]), target) + elif heater.startswith("temperature_fan "): + self._screen._ws.klippy.set_temp_fan_temp(" ".join(heater.split(" ")[1:]), target) + else: + logging.info("Unknown heater: %s" % heater) + self._screen.show_popup_message(_("Unknown Heater ") + heater) + self._printer.set_dev_stat(heater, "target", int(target)) + logging.info("Setting %s to %d" % (heater, target)) + + def activate(self): + if self.graph_update is None: + self.graph_update = GLib.timeout_add_seconds(1, self.update_graph) + for x in self._printer.get_tools(): + if x not in self.active_heaters: + self.select_heater(None, x) + for h in self._printer.get_heaters(): + if h.startswith("temperature_sensor "): + continue + if h not in self.active_heaters: + self.select_heater(None, h) + + def deactivate(self): + if self.graph_update is not None: + GLib.source_remove(self.graph_update) + self.graph_update = None + + def select_heater(self, widget, device): _ = self.lang.gettext - if "keypad" not in self.labels: - self.labels["keypad"] = Keypad(self._screen, self.change_target_temp, self.hide_numpad) - self.labels["keypad"].clear() + if self.devices[device]["can_target"]: + if device in self.active_heaters: + self.active_heaters.pop(self.active_heaters.index(device)) + self.devices[device]['name'].get_style_context().remove_class("active_device") + self.devices[device]['select'].set_label(_("Select")) + return + self.active_heaters.append(device) + self.devices[device]['name'].get_style_context().add_class("active_device") + self.devices[device]['select'].set_label(_("Deselect")) + return - self.grid.remove_column(1) - self.grid.attach(self.labels["keypad"], 1, 0, 1, 1) - self.grid.show_all() + def set_temperature(self, widget, setting): + _ = self.lang.gettext + if len(self.active_heaters) == 0: + self._screen.show_popup_message(_("Nothing selected")) + else: + if setting == "cooldown": + for heater in self.active_heaters: + if heater.startswith('extruder'): + self._screen._ws.klippy.set_tool_temp(self._printer.get_tool_number(heater), 0) + elif heater.startswith('heater_bed'): + self._screen._ws.klippy.set_bed_temp(0) + elif heater.startswith('heater_generic '): + self._screen._ws.klippy.set_heater_temp(" ".join(heater.split(" ")[1:]), 0) + logging.info("Setting %s to %d" % (heater, 0)) + self._printer.set_dev_stat(heater, "target", 0) + return - def hide_numpad(self, widget): - self.grid.remove_column(1) - self.grid.attach(self.labels["control_grid"], 1, 0, 1, 1) - self.grid.show_all() + for heater in self.active_heaters: + if heater.startswith('extruder'): + target = self.preheat_options[setting]["extruder"] + self._screen._ws.klippy.set_tool_temp(self._printer.get_tool_number(heater), target) + elif heater.startswith('heater_bed'): + target = self.preheat_options[setting]["bed"] + self._screen._ws.klippy.set_bed_temp(target) + elif heater.startswith('heater_generic '): + target = self.preheat_options[setting]["heater_generic"] + self._screen._ws.klippy.set_heater_temp(" ".join(heater.split(" ")[1:]), target) + elif heater.startswith('temperature_fan '): + target = self.preheat_options[setting]["temperature_fan"] + self._screen._ws.klippy.set_temp_fan_temp(" ".join(heater.split(" ")[1:]), target) + else: + logging.info("Unknown heater: %s" % heater) + self._screen.show_popup_message(_("Unknown Heater") + heater) + self._printer.set_dev_stat(heater, "target", int(target)) + logging.info("Setting %s to %d" % (heater, target)) + if self.preheat_options[setting]['gcode']: + self._screen._ws.klippy.gcode_script(self.preheat_options[setting]['gcode']) + def add_device(self, device): + _ = self.lang.gettext + logging.info("Adding device: %s" % device) - def select_heater(self, widget, heater): - if self.active_heater == heater: + temperature = self._printer.get_dev_stat(device, "temperature") + if temperature is None: return + if not (device.startswith("extruder") or device.startswith("heater_bed")): + devname = " ".join(device.split(" ")[1:]) + else: + devname = device - self.labels[self.active_heater].get_style_context().remove_class('button_active') - self.active_heater = heater - self.labels[heater].get_style_context().add_class("button_active") + if device.startswith("extruder"): + i = 0 + for d in self.devices: + if d.startswith('extruder'): + i += 1 + image = "extruder-%s" % i + class_name = "graph_label_%s" % device + type = "extruder" + elif device == "heater_bed": + image = "bed" + devname = "Heater Bed" + class_name = "graph_label_heater_bed" + type = "bed" + elif device.startswith("temperature_fan"): + f = 1 + for d in self.devices: + if "temperature_fan" in d: + f += 1 + image = "fan" + class_name = "graph_label_fan_%s" % f + type = "fan" + else: + s = 1 + for d in self.devices: + if "sensor" in d: + s += 1 + image = "heat-up" + class_name = "graph_label_sensor_%s" % s + type = "sensor" - if "entry" in self.labels: - self.labels['entry'].set_text("") - logging.info("### Active heater " + self.active_heater) + rgb, color = self._gtk.get_temp_color(type) + + 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.connect('clicked', self.on_popover_clicked, device) + name.set_alignment(0, .5) + name.get_style_context().add_class(class_name) + child = name.get_children()[0].get_children()[0].get_children()[1] + child.set_ellipsize(True) + child.set_ellipsize(Pango.EllipsizeMode.END) + + temp = self._gtk.Button("") + temp.connect('clicked', self.select_heater, device) + + labels = Gtk.Box(orientation=Gtk.Orientation.VERTICAL) + + dev = Gtk.Box(orientation=Gtk.Orientation.HORIZONTAL, spacing=5) + dev.set_hexpand(True) + dev.set_vexpand(False) + dev.add(labels) + + self.devices[device] = { + "class": class_name, + "type": type, + "name": name, + "temp": temp, + "can_target": can_target + } + + if self.devices[device]["can_target"]: + temp.get_child().set_label("%.1f %s" % + (temperature, self.format_target(self._printer.get_dev_stat(device, "target")))) + self.devices[device]['select'] = self._gtk.Button(label=_("Select")) + self.devices[device]['select'].connect('clicked', self.select_heater, device) + else: + temp.get_child().set_label("%.1f" % temperature) + + devices = sorted(self.devices) + pos = devices.index(device) + 1 + + self.labels['devices'].insert_row(pos) + self.labels['devices'].attach(name, 0, pos, 1, 1) + self.labels['devices'].attach(temp, 1, pos, 1, 1) + self.labels['devices'].show_all() + + def change_target_temp(self, temp): + _ = self.lang.gettext + + MAX_TEMP = int(self._printer.get_config_section(self.active_heater)['max_temp']) + if temp > MAX_TEMP: + self._screen.show_popup_message(_("Can't set above the maximum:") + (" %s" % MAX_TEMP)) + return + temp = 0 if temp < 0 else temp + + if self.active_heater.startswith('extruder '): + self._screen._ws.klippy.set_tool_temp(self._printer.get_tool_number(self.active_heater), temp) + elif self.active_heater == "heater_bed": + self._screen._ws.klippy.set_bed_temp(temp) + elif self.active_heater.startswith('heater_generic '): + self._screen._ws.klippy.set_heater_temp(" ".join(self.active_heater.split(" ")[1:]), temp) + elif self.active_heater.startswith('temperature_fan '): + self._screen._ws.klippy.set_temp_fan_temp(" ".join(self.active_heater.split(" ")[1:]), temp) + else: + logging.info("Unknown heater: %s" % self.active_heater) + self._screen.show_popup_message(_("Unknown Heater ") + self.active_heater) + self._printer.set_dev_stat(self.active_heater, "target", temp) + + def create_left_panel(self): + _ = self.lang.gettext + + self.labels['devices'] = Gtk.Grid() + self.labels['devices'].get_style_context().add_class('heater-grid') + self.labels['devices'].set_vexpand(False) + + name = Gtk.Label("") + temp = Gtk.Label(_("Temp (°C)")) + temp.set_size_request(round(self._gtk.get_font_size() * 5.5), 0) + + self.labels['devices'].attach(name, 0, 0, 1, 1) + self.labels['devices'].attach(temp, 1, 0, 1, 1) + + da = HeaterGraph(self._printer) + da.set_vexpand(True) + self.labels['da'] = da + + box = Gtk.Box(orientation=Gtk.Orientation.VERTICAL, spacing=0) + box.set_vexpand(True) + box.add(self.labels['devices']) + box.add(da) + + + self.labels['graph_settemp'] = self._gtk.Button(label=_("Set Temp")) + self.labels['graph_settemp'].connect("clicked", self.show_numpad) + 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() + 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 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) + if show: + self.devices[self.popover_device]['name'].get_style_context().remove_class("graph_label_hidden") + self.devices[self.popover_device]['name'].get_style_context().add_class( + self.devices[self.popover_device]['class']) + else: + self.devices[self.popover_device]['name'].get_style_context().remove_class( + self.devices[self.popover_device]['class']) + self.devices[self.popover_device]['name'].get_style_context().add_class("graph_label_hidden") + self.labels['da'].queue_draw() + self.popover_populate_menu() + self.labels['popover'].show_all() + + def hide_numpad(self, widget): + self.devices[self.active_heater]['name'].get_style_context().remove_class("button_active") + self.active_heater = None + + self.grid.remove_column(1) + self.grid.attach(self.create_right_panel(), 1, 0, 1, 1) + self.grid.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) + if self.devices[self.popover_device]["can_target"]: + pobox.pack_start(self.labels['graph_settemp'], True, True, 5) + pobox.pack_end(self.devices[self.popover_device]['select'], True, True, 5) def process_update(self, action, data): if action != "notify_status_update": @@ -161,41 +440,38 @@ class TemperaturePanel(ScreenPanel): self.update_temp( h, self._printer.get_dev_stat(h, "temperature"), - self._printer.get_dev_stat(h, "target"), - None if h == "heater_bed" else " ".join(h.split(" ")[1:]) + self._printer.get_dev_stat(h, "target") ) - return - def change_target_temp(self, temp): - if self.active_heater.startswith('heater_generic '): - self._screen._ws.klippy.set_heater_temp(" ".join(self.active_heater.split(" ")[1:]), temp) - elif self.active_heater == "heater_bed": - temp = 0 if temp < 0 or temp > KlippyGcodes.MAX_BED_TEMP else temp - self._screen._ws.klippy.set_bed_temp(temp) + def show_numpad(self, widget): + _ = self.lang.gettext + + if self.active_heater is not None: + self.devices[self.active_heater]['name'].get_style_context().remove_class("button_active") + self.active_heater = self.popover_device + self.devices[self.active_heater]['name'].get_style_context().add_class("button_active") + + if "keypad" not in self.labels: + self.labels["keypad"] = Keypad(self._screen, self.change_target_temp, self.hide_numpad) + self.labels["keypad"].clear() + + self.grid.remove_column(1) + self.grid.attach(self.labels["keypad"], 1, 0, 1, 1) + self.grid.show_all() + + self.labels['popover'].popdown() + + def update_graph(self): + self.labels['da'].queue_draw() + alloc = self.labels['devices'].get_allocation() + alloc = self.labels['da'].get_allocation() + return True + + def update_temp(self, device, temp, target): + if device not in self.devices: + return + + if self.devices[device]["can_target"]: + self.devices[device]["temp"].get_child().set_label("%.1f %s" % (temp, self.format_target(target))) else: - temp = 0 if temp < 0 or temp > KlippyGcodes.MAX_EXT_TEMP else temp - self._screen._ws.klippy.set_tool_temp(self._printer.get_tool_number(self.active_heater), temp) - self._printer.set_dev_stat(self.active_heater, "target", temp) - - def change_target_temp_incremental(self, widget, dir): - logging.debug("Dev stats %s: %s" % (self.active_heater, self._printer.get_dev_stats(self.active_heater))) - target = self._printer.get_dev_stat(self.active_heater, "target") - if dir == "+": - target += int(self.tempdelta) - if target > KlippyGcodes.MAX_EXT_TEMP: - target = KlippyGcodes.MAX_EXT_TEMP - else: - target -= int(self.tempdelta) - if target < 0: - target = 0 - - self._printer.set_dev_stat(self.active_heater, "target", target) - - if self.active_heater.startswith("heater_generic "): - self._screen._ws.klippy.set_heater_temp(" ".join(self.active_heater.split(" ")[1:]), target) - elif self.active_heater == "heater_bed": - self._screen._ws.klippy.set_bed_temp(target) - elif self.active_heater.startswith("temperature_fan "): - self._screen._ws.klippy.set_temp_fan_temp(" ".join(self.active_heater.split(" ")[1:]), target) - else: - self._screen._ws.klippy.set_tool_temp(self._printer.get_tool_number(self.active_heater), target) + self.devices[device]["temp"].get_child().set_label("%.1f" % temp) diff --git a/styles/base.css b/styles/base.css index f839cba5..d4fdbaba 100644 --- a/styles/base.css +++ b/styles/base.css @@ -32,21 +32,25 @@ button:active { button.color1 { border-bottom: .4em solid #ED6500; margin: .3em; + min-height: 3em; } button.color2 { border-bottom: .4em solid #B10080; margin: .3em; + min-height: 3em; } button.color3 { border-bottom: .4em solid #009384; margin: .3em; + min-height: 3em; } button.color4 { border-bottom: .4em solid #A7E100; margin: .3em; + min-height: 3em; } button.active { diff --git a/styles/material-darker/style.css b/styles/material-darker/style.css index ffa3fe86..f73432ee 100644 --- a/styles/material-darker/style.css +++ b/styles/material-darker/style.css @@ -23,6 +23,7 @@ button:active { border-style: solid; border-width: .25em; background-color: rgba(0,0,0,0.5); + border-radius: 1em; } button.color1, button.color2, button.color3, button.color4 { diff --git a/styles/z-bolt/style.css b/styles/z-bolt/style.css index 0e281120..9489b8ae 100644 --- a/styles/z-bolt/style.css +++ b/styles/z-bolt/style.css @@ -16,6 +16,7 @@ button:active { .button_active { background-color: #20303D; + border-radius: 1em; } button.color1 {