diff --git a/ks_includes/KlippyGcodes.py b/ks_includes/KlippyGcodes.py index 0cbcbb6f..c0aa0bf5 100644 --- a/ks_includes/KlippyGcodes.py +++ b/ks_includes/KlippyGcodes.py @@ -34,32 +34,31 @@ class KlippyGcodes: @staticmethod def set_bed_temp(temp): - return "%s S%s" % (KlippyGcodes.SET_BED_TEMP, str(temp)) + return f"{KlippyGcodes.SET_BED_TEMP} S{temp}" @staticmethod def set_ext_temp(temp, tool=0): - return "%s T%s S%s" % (KlippyGcodes.SET_EXT_TEMP, str(tool), str(temp)) + return f"{KlippyGcodes.SET_EXT_TEMP} T{tool} S{temp}" @staticmethod def set_heater_temp(heater, temp): - return 'SET_HEATER_TEMPERATURE heater="%s" target=%s' % (heater, str(temp)) + return f'SET_HEATER_TEMPERATURE heater="{heater}" target={temp}' @staticmethod def set_temp_fan_temp(temp_fan, temp): - return 'SET_TEMPERATURE_FAN_TARGET temperature_fan="%s" target=%s' % (temp_fan, str(temp)) + return f'SET_TEMPERATURE_FAN_TARGET temperature_fan="{temp_fan}" target={temp}' @staticmethod def set_fan_speed(speed): - speed = str(int(float(int(speed) % 101) / 100 * 255)) - return "%s S%s" % (KlippyGcodes.SET_FAN_SPEED, speed) + return f"{KlippyGcodes.SET_FAN_SPEED} S{speed * 2.55:.0f}" @staticmethod def set_extrusion_rate(rate): - return "%s S%s" % (KlippyGcodes.SET_EXT_FACTOR, rate) + return f"{KlippyGcodes.SET_EXT_FACTOR} S{rate}" @staticmethod def set_speed_rate(rate): - return "%s S%s" % (KlippyGcodes.SET_SPD_FACTOR, rate) + return f"{KlippyGcodes.SET_SPD_FACTOR} S{rate}" @staticmethod def testz_move(dist): @@ -67,16 +66,16 @@ class KlippyGcodes: @staticmethod def extrude(dist, speed=500): - return "%s E%s F%s" % (KlippyGcodes.MOVE, dist, speed) + return f"{KlippyGcodes.MOVE} E{dist} F{speed}" @staticmethod def bed_mesh_load(profile): - return "BED_MESH_PROFILE LOAD='%s'" % profile + return f"BED_MESH_PROFILE LOAD='{profile}'" @staticmethod def bed_mesh_remove(profile): - return "BED_MESH_PROFILE REMOVE='%s'" % profile + return f"BED_MESH_PROFILE REMOVE='{profile}'" @staticmethod def bed_mesh_save(profile): - return "BED_MESH_PROFILE SAVE='%s'" % profile + return f"BED_MESH_PROFILE SAVE='{profile}'" diff --git a/ks_includes/KlippyGtk.py b/ks_includes/KlippyGtk.py index 667faccc..59a5f4ba 100644 --- a/ks_includes/KlippyGtk.py +++ b/ks_includes/KlippyGtk.py @@ -1,4 +1,5 @@ # -*- coding: utf-8 -*- +import contextlib import gi import logging import os @@ -19,10 +20,7 @@ class KlippyGtk: self.height = height self.themedir = os.path.join(pathlib.Path(__file__).parent.resolve().parent, "styles", theme, "images") - if self.screen.vertical_mode: - self.font_ratio = [33, 49] - else: - self.font_ratio = [43, 29] + self.font_ratio = [33, 49] if self.screen.vertical_mode else [43, 29] self.font_size = int(min( self.width / self.font_ratio[0], self.height / self.font_ratio[1] @@ -50,7 +48,7 @@ class KlippyGtk: 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)) + logging.debug(f"img width: {self.img_width} height: {self.img_height}") def get_action_bar_width(self): return self.action_bar_width @@ -99,9 +97,8 @@ class KlippyGtk: 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] - # logging.debug("Assigning color: %s %s %s" % (device, rgb, color)) + # logging.debug(f"Assigning color: {device} {rgb}") else: colors = self.color_list[device]['colors'] if self.color_list[device]['state'] >= len(colors): @@ -109,22 +106,22 @@ class KlippyGtk: color = colors[self.color_list[device]['state'] % len(colors)] rgb = [int(color[i:i + 2], 16) / 255 for i in range(0, 6, 2)] self.color_list[device]['state'] += 1 - # logging.debug("Assigning color: %s %s %s" % (device, rgb, color)) - - return rgb, color + # logging.debug(f"Assigning color: {device} {rgb} {color}") + return rgb def reset_temp_color(self): for key in self.color_list: self.color_list[key]['state'] = 0 - def Label(self, label, style=None): + @staticmethod + def Label(label, style=None): la = Gtk.Label(label) if style is not None: la.get_style_context().add_class(style) return la def Image(self, image_name, scale=1.0): - filename = os.path.join(self.themedir, str(image_name) + ".svg") + filename = os.path.join(self.themedir, f"{image_name}.svg") if os.path.exists(filename): pixbuf = GdkPixbuf.Pixbuf.new_from_file_at_scale(filename, int(round(self.img_width * scale)), @@ -132,35 +129,28 @@ class KlippyGtk: True) return Gtk.Image.new_from_pixbuf(pixbuf) else: - logging.error("Unable to find image %s", filename) + logging.error(f"Unable to find image {filename}") return Gtk.Image() def PixbufFromFile(self, filename, width_scale=1, height_scale=1): - pixbuf = GdkPixbuf.Pixbuf.new_from_file_at_scale(filename, - int(round(self.img_width * width_scale)), - int(round(self.img_height * height_scale)), - True) - return pixbuf + return GdkPixbuf.Pixbuf.new_from_file_at_scale( + filename, + int(round(self.img_width * width_scale)), + int(round(self.img_height * height_scale)), + True + ) def PixbufFromHttp(self, resource, width_scale=1, height_scale=1): response = self.screen.apiclient.get_thumbnail_stream(resource) if response is False: return None stream = Gio.MemoryInputStream.new_from_data(response, None) - pixbuf = GdkPixbuf.Pixbuf.new_from_stream_at_scale(stream, - int(round(self.img_width * width_scale)), - int(round(self.img_height * height_scale)), - True) - return pixbuf - - def ProgressBar(self, style=None): - bar = Gtk.ProgressBar() - - if style is not None: - ctx = bar.get_style_context() - ctx.add_class(style) - - return bar + return GdkPixbuf.Pixbuf.new_from_stream_at_scale( + stream, + int(round(self.img_width * width_scale)), + int(round(self.img_height * height_scale)), + True + ) def Button(self, label=None, style=None): b = Gtk.Button(label=label) @@ -187,14 +177,11 @@ class KlippyGtk: b.set_always_show_image(True) if word_wrap is True: - try: + with contextlib.suppress(Exception): # Get the label object child = b.get_children()[0].get_children()[0].get_children()[1] child.set_line_wrap_mode(Pango.WrapMode.WORD_CHAR) child.set_line_wrap(True) - except Exception: - pass - if style is not None: b.get_style_context().add_class(style) b.connect("clicked", self.screen.reset_screensaver_timeout) @@ -250,7 +237,8 @@ class KlippyGtk: b.connect("clicked", self.screen.reset_screensaver_timeout) return b - def HomogeneousGrid(self, width=None, height=None): + @staticmethod + def HomogeneousGrid(width=None, height=None): g = Gtk.Grid() g.set_row_homogeneous(True) g.set_column_homogeneous(True) @@ -266,40 +254,11 @@ class KlippyGtk: b.connect("clicked", self.screen.reset_screensaver_timeout) return b - def ScrolledWindow(self): + @staticmethod + def ScrolledWindow(): scroll = Gtk.ScrolledWindow() scroll.set_property("overlay-scrolling", False) scroll.set_vexpand(True) scroll.add_events(Gdk.EventMask.TOUCH_MASK) scroll.add_events(Gdk.EventMask.BUTTON_PRESS_MASK) return scroll - - def formatFileName(self, name): - name = name.split('/')[-1] if "/" in name else name - name = name.split('.gcod')[0] if ".gcode" in name else name - if len(name) > 25: - return name[0:25] + "\n" + name[25:50] - return name - - def formatTimeString(self, seconds): - time = int(seconds) - text = "" - if int(time / 86400) != 0: - text += str(int(time / 86400)) + "d " - if int(time / 3600) != 0: - text += str(int(time / 3600) % 24) + "h " - if int(time / 60) != 0: - text += str(int(time / 60) % 60) + "m " - else: - text = str(time % 60) + "s" - return text - - def formatTemperatureString(self, temp, target): - if temp is None: - logging.debug("Temp is none") - return - if target is None: - target = 0 - if (temp - 2 < target < temp + 2) or round(target, 0) == 0: - return str(round(temp, 1)) + "°C" # °C →" - return str(round(temp)) + " °C\n(" + str(round(target)) + ")" diff --git a/ks_includes/KlippyRest.py b/ks_includes/KlippyRest.py index eca7d69c..08211316 100644 --- a/ks_includes/KlippyRest.py +++ b/ks_includes/KlippyRest.py @@ -22,7 +22,7 @@ class KlippyRest: return self.send_request("printer/info") def get_thumbnail_stream(self, thumbnail): - url = "http://%s:%s/server/files/gcodes/%s" % (self.ip, self.port, thumbnail) + url = f"http://{self.ip}:{self.port}/server/files/gcodes/{thumbnail}" response = requests.get(url, stream=True) if response.status_code == 200: response.raw.decode_content = True @@ -30,8 +30,8 @@ class KlippyRest: return False def send_request(self, method): - url = "http://%s:%s/%s" % (self.ip, self.port, method) - logging.debug("Sending request to %s" % url) + url = f"http://{self.ip}:{self.port}/{method}" + logging.debug(f"Sending request to {url}") headers = {} if self.api_key is False else {"x-api-key": self.api_key} try: r = requests.get(url, headers=headers) @@ -46,7 +46,7 @@ class KlippyRest: data = json.loads(r.content) except Exception as e: logging.critical(e, exc_info=True) - logging.exception("Unable to parse response from moonraker:\n %s" % r.content) + logging.exception(f"Unable to parse response from moonraker:\n {r.content}") return False return data diff --git a/ks_includes/KlippyWebsocket.py b/ks_includes/KlippyWebsocket.py index fe58ca3c..cb6d13ab 100644 --- a/ks_includes/KlippyWebsocket.py +++ b/ks_includes/KlippyWebsocket.py @@ -36,13 +36,15 @@ class KlippyWebsocket(threading.Thread): def __init__(self, screen, callback, host, port): threading.Thread.__init__(self) + self._wst = None + self.ws_url = None self._screen = screen self._callback = callback self.klippy = MoonrakerApi(self) self.closing = False self.ws = None - self._url = "%s:%s" % (host, port) + self._url = f"{host}:{port}" def initial_connect(self): # Enable a timeout so that way if moonraker is not running, it will attempt to reconnect @@ -70,9 +72,10 @@ class KlippyWebsocket(threading.Thread): if state is False: if self.reconnect_count > 3: self._screen.panels['splash_screen'].update_text( - _("Cannot connect to Moonraker") + - "\n\n%s\n\n" % self._url + - _("Retry #%s") % self.reconnect_count) + _("Cannot connect to Moonraker") + + f'\n\n{self._url}\n\n' + + _("Retrying") + f' #{self.reconnect_count}' + ) return False token = self._screen.apiclient.get_oneshot_token() except Exception as e: @@ -80,7 +83,7 @@ class KlippyWebsocket(threading.Thread): logging.debug("Unable to get oneshot token") return False - self.ws_url = "ws://%s/websocket?token=%s" % (self._url, token) + self.ws_url = f"ws://{self._url}/websocket?token={token}" self.ws = websocket.WebSocketApp( self.ws_url, on_close=ws_on_close, on_error=ws_on_error, on_message=ws_on_message, on_open=ws_on_open) @@ -102,18 +105,17 @@ class KlippyWebsocket(threading.Thread): def on_message(self, ws, message): response = json.loads(message) - if "id" in response: - if response['id'] in self.callback_table: - Gdk.threads_add_idle( - GLib.PRIORITY_HIGH_IDLE, - self.callback_table[response['id']][0], - response, - self.callback_table[response['id']][1], - self.callback_table[response['id']][2], - *self.callback_table[response['id']][3] - ) - self.callback_table.pop(response['id']) - return + if "id" in response and response['id'] in self.callback_table: + Gdk.threads_add_idle( + GLib.PRIORITY_HIGH_IDLE, + self.callback_table[response['id']][0], + response, + self.callback_table[response['id']][1], + self.callback_table[response['id']][2], + *self.callback_table[response['id']][3] + ) + self.callback_table.pop(response['id']) + return if "method" in response and "on_message" in self._callback: Gdk.threads_add_idle( @@ -124,7 +126,9 @@ class KlippyWebsocket(threading.Thread): ) return - def send_method(self, method, params={}, callback=None, *args): + def send_method(self, method, params=None, callback=None, *args): + if params is None: + params = {} if self.is_connected() is False: return False @@ -143,7 +147,7 @@ class KlippyWebsocket(threading.Thread): def on_open(self, ws): logging.info("Moonraker Websocket Open") - logging.info("Self.connected = %s" % self.is_connected()) + logging.info(f"Self.connected = {self.is_connected()}") self.connected = True self.reconnect_count = 0 if self.reconnect_timeout is not None: @@ -173,7 +177,7 @@ class KlippyWebsocket(threading.Thread): logging.info("Moonraker Websocket Closed") self.connected = False if self.reconnect_timeout is None: - self.reconnect_timeout = GLib.timeout_add_seconds(3, self.reconnect) + self.reconnect_timeout = GLib.timeout_add_seconds(9, self.reconnect) if "on_close" in self._callback: Gdk.threads_add_idle( @@ -193,8 +197,9 @@ class KlippyWebsocket(threading.Thread): self.connect() return True - def on_error(self, ws, error): - logging.debug("Websocket error: %s" % error) + @staticmethod + def on_error(ws, error): + logging.debug(f"Websocket error: {error}") class MoonrakerApi: @@ -208,7 +213,7 @@ class MoonrakerApi: ) def gcode_script(self, script, callback=None, *args): - logging.debug("Sending printer.gcode.script: %s", script) + logging.debug(f"Sending printer.gcode.script: {script}") return self._ws.send_method( "printer.gcode.script", {"script": script}, @@ -243,14 +248,14 @@ class MoonrakerApi: ) def object_subscription(self, updates): - logging.debug("Sending printer.objects.subscribe: %s", str(updates)) + logging.debug(f"Sending printer.objects.subscribe: {updates}") return self._ws.send_method( "printer.objects.subscribe", updates ) def power_device_off(self, device, callback=None, *args): - logging.debug("Sending machine.device_power.off: %s" % device) + logging.debug(f"Sending machine.device_power.off: {device}") return self._ws.send_method( "machine.device_power.off", {device: False}, @@ -259,7 +264,7 @@ class MoonrakerApi: ) def power_device_on(self, device, callback=None, *args): - logging.debug("Sending machine.device_power.on %s" % device) + logging.debug("Sending machine.device_power.on {device}") return self._ws.send_method( "machine.device_power.on", {device: False}, @@ -307,7 +312,7 @@ class MoonrakerApi: def temperature_set(self, heater, target, callback=None, *args): if heater == "heater_bed": - logging.debug("Sending printer.gcode.script: %s", KlippyGcodes.set_bed_temp(target)) + logging.debug(f"Sending printer.gcode.script: {KlippyGcodes.set_bed_temp(target)}") return self._ws.send_method( "printer.gcode.script", { @@ -318,8 +323,7 @@ class MoonrakerApi: ) else: logging.debug( - "Sending printer.gcode.script: %s", - KlippyGcodes.set_ext_temp(target, heater.replace("tool", ""))) + f'Sending printer.gcode.script: {KlippyGcodes.set_ext_temp(target, heater.replace("tool", ""))}') # TODO: Add max/min limits return self._ws.send_method( "printer.gcode.script", @@ -331,7 +335,7 @@ class MoonrakerApi: ) def set_bed_temp(self, target, callback=None, *args): - logging.debug("Sending set_bed_temp: %s", KlippyGcodes.set_bed_temp(target)) + logging.debug(f"Sending set_bed_temp: {KlippyGcodes.set_bed_temp(target)}") return self._ws.send_method( "printer.gcode.script", { @@ -342,7 +346,7 @@ class MoonrakerApi: ) def set_heater_temp(self, heater, target, callback=None, *args): - logging.debug("Sending heater %s to temp: %s", heater, target) + logging.debug(f"Sending heater {heater} to temp: {target}") return self._ws.send_method( "printer.gcode.script", { @@ -353,7 +357,7 @@ class MoonrakerApi: ) def set_temp_fan_temp(self, temp_fan, target, callback=None, *args): - logging.debug("Sending temperature fan %s to temp: %s", temp_fan, target) + logging.debug(f"Sending temperature fan {temp_fan} to temp: {target}") return self._ws.send_method( "printer.gcode.script", { @@ -364,7 +368,7 @@ class MoonrakerApi: ) def set_tool_temp(self, tool, target, callback=None, *args): - logging.debug("Sending set_tool_temp: %s", KlippyGcodes.set_ext_temp(target, tool)) + logging.debug(f"Sending set_tool_temp: {KlippyGcodes.set_ext_temp(target, tool)}") return self._ws.send_method( "printer.gcode.script", { diff --git a/ks_includes/config.py b/ks_includes/config.py index 33e1ea91..22412af8 100644 --- a/ks_includes/config.py +++ b/ks_includes/config.py @@ -12,12 +12,12 @@ from io import StringIO from os import path SCREEN_BLANKING_OPTIONS = [ - "300", # 5 Minutes - "900", # 15 Minutes - "1800", # 30 Minutes - "3600", # 1 Hour - "7200", # 2 Hours - "14400", # 4 Hours + 300, # 5 Minutes + 900, # 15 Minutes + 1800, # 30 Minutes + 3600, # 1 Hour + 7200, # 2 Hours + 14400, # 4 Hours ] klipperscreendir = pathlib.Path(__file__).parent.resolve().parent @@ -37,7 +37,7 @@ class KlipperScreenConfig: self.default_config_path = os.path.join(klipperscreendir, "ks_includes", "defaults.conf") self.config = configparser.ConfigParser() self.config_path = self.get_config_file_location(configfile) - logging.debug("Config path location: %s" % self.config_path) + logging.debug(f"Config path location: {self.config_path}") self.defined_config = None try: @@ -57,24 +57,22 @@ class KlipperScreenConfig: self.config.read_string(user_def) if saved_def is not None: self.config.read_string(saved_def) - logging.info("====== Saved Def ======\n%s\n=======================" % saved_def) + logging.info(f"====== Saved Def ======\n{saved_def}\n=======================") # This is the final config # self.log_config(self.config) - except KeyError: - raise ConfigError(f"Error reading config: {self.config_path}") + except KeyError as e: + raise ConfigError(f"Error reading config: {self.config_path}") from e except Exception: logging.exception("Unknown error with config") printers = sorted([i for i in self.config.sections() if i.startswith("printer ")]) - self.printers = [] - for printer in printers: - self.printers.append({ - printer[8:]: { - "moonraker_host": self.config.get(printer, "moonraker_host", fallback="127.0.0.1"), - "moonraker_port": self.config.get(printer, "moonraker_port", fallback="7125"), - "moonraker_api_key": self.config.get(printer, "moonraker_api_key", fallback=False) - } - }) + self.printers = [ + {printer[8:]: { + "moonraker_host": self.config.get(printer, "moonraker_host", fallback="127.0.0.1"), + "moonraker_port": self.config.get(printer, "moonraker_port", fallback="7125"), + "moonraker_api_key": self.config.get(printer, "moonraker_api_key", fallback=False) + }} for printer in printers] + if len(printers) <= 0: self.printers.append({ "Printer": { @@ -90,11 +88,11 @@ class KlipperScreenConfig: item = conf_printers_debug[conf_printers_debug.index(printer)] if item[name]['moonraker_api_key'] != "": item[name]['moonraker_api_key'] = "redacted" - logging.debug("Configured printers: %s" % json.dumps(conf_printers_debug, indent=2)) + logging.debug(f"Configured printers: {json.dumps(conf_printers_debug, indent=2)}") lang = self.get_main_config().get("language", None) lang = [lang] if lang is not None and lang != "default" else None - logging.info("Detected language: %s" % lang) + logging.info(f"Detected language: {lang}") self.lang = gettext.translation('KlipperScreen', localedir='ks_includes/locales', languages=lang, fallback=True) self.lang.install(names=['gettext', 'ngettext']) @@ -178,14 +176,14 @@ class KlipperScreenConfig: index = self.configurable_options.index( [i for i in self.configurable_options if list(i)[0] == "screen_blanking"][0]) for num in SCREEN_BLANKING_OPTIONS: - hour = int(int(num) / 3600) + hour = num // 3600 if hour > 0: - name = str(hour) + " " + ngettext("hour", "hours", hour) + name = f'{hour} ' + ngettext("hour", "hours", hour) else: - name = str(int(int(num) / 60)) + " " + _("minutes") + name = f'{num / 60:.0f} ' + _("minutes") self.configurable_options[index]['screen_blanking']['options'].append({ "name": name, - "value": num + "value": f"{num}" }) for item in self.configurable_options: @@ -200,9 +198,7 @@ class KlipperScreenConfig: exclude_list = ['preheat'] if not self.defined_config.getboolean('main', "use_default_menu", fallback=True): logging.info("Using custom menu, removing default menu entries.") - exclude_list.append('menu __main') - exclude_list.append('menu __print') - exclude_list.append('menu __splashscreen') + exclude_list.extend(('menu __main', 'menu __print', 'menu __splashscreen')) for i in exclude_list: for j in config.sections(): if j.startswith(i): @@ -210,28 +206,27 @@ class KlipperScreenConfig: if k.startswith(i): del self.config[k] - def _include_config(self, dir, path): - full_path = path if path[0] == "/" else "%s/%s" % (dir, path) + def _include_config(self, directory, filepath): + full_path = filepath if filepath[0] == "/" else f"{directory}/{filepath}" parse_files = [] if "*" in full_path: parent_dir = "/".join(full_path.split("/")[:-1]) file = full_path.split("/")[-1] if not os.path.exists(parent_dir): - logging.info("Config Error: Directory %s does not exist" % parent_dir) + logging.info(f"Config Error: Directory {parent_dir} does not exist") return files = os.listdir(parent_dir) - regex = "^%s$" % file.replace('*', '.*') - for file in files: - if re.match(regex, file): - parse_files.append(os.path.join(parent_dir, file)) + regex = f"^{file.replace('*', '.*')}$" + parse_files.extend(os.path.join(parent_dir, file) for file in files if re.match(regex, file)) + else: if not os.path.exists(os.path.join(full_path)): - logging.info("Config Error: %s does not exist" % full_path) + logging.info(f"Config Error: {full_path} does not exist") return parse_files.append(full_path) - logging.info("Parsing files: %s" % parse_files) + logging.info(f"Parsing files: {parse_files}") for file in parse_files: config = configparser.ConfigParser() config.read(file) @@ -244,7 +239,7 @@ class KlipperScreenConfig: def separate_saved_config(self, config_path): user_def = [] - saved_def = None + saved_def = [] found_saved = False if not path.exists(config_path): return [None, None] @@ -257,13 +252,12 @@ class KlipperScreenConfig: continue if found_saved is False: user_def.append(line.replace('\n', '')) - else: - if line.startswith(self.do_not_edit_prefix): - saved_def.append(line[(len(self.do_not_edit_prefix) + 1):]) + elif line.startswith(self.do_not_edit_prefix): + saved_def.append(line[(len(self.do_not_edit_prefix) + 1):]) return ["\n".join(user_def), None if saved_def is None else "\n".join(saved_def)] def get_config_file_location(self, file): - logging.info("Passed config file: %s" % file) + logging.info(f"Passed config file: {file}") if not path.exists(file): file = os.path.join(klipperscreendir, self.configfile_name) if not path.exists(file): @@ -276,7 +270,7 @@ class KlipperScreenConfig: if not path.exists(file): file = self.default_config_path - logging.info("Found configuration file at: %s" % file) + logging.info(f"Found configuration file at: {file}") return file def get_config(self): @@ -293,8 +287,8 @@ class KlipperScreenConfig: def get_menu_items(self, menu="__main", subsection=""): if subsection != "": - subsection = subsection + " " - index = "menu %s %s" % (menu, subsection) + subsection = f"{subsection} " + index = f"menu {menu} {subsection}" items = [i[len(index):] for i in self.config.sections() if i.startswith(index)] menu_items = [] for item in items: @@ -305,7 +299,7 @@ class KlipperScreenConfig: return menu_items def get_menu_name(self, menu="__main", subsection=""): - name = ("menu %s %s" % (menu, subsection)) if subsection != "" else ("menu %s" % menu) + name = f"menu {menu} {subsection}" if subsection != "" else f"menu {menu}" if name not in self.config: return False return self.config[name].get('name') @@ -314,15 +308,11 @@ class KlipperScreenConfig: index = "preheat " items = [i[len(index):] for i in self.config.sections() if i.startswith(index)] - preheat_options = {} - for item in items: - preheat_options[item] = self._build_preheat_item(index + item) - - return preheat_options + return {item: self._build_preheat_item(index + item) for item in items} def get_printer_config(self, name): if not name.startswith("printer "): - name = "printer %s" % name + name = f"printer {name}" if name not in self.config: return None @@ -334,10 +324,6 @@ class KlipperScreenConfig: def get_printers(self): return self.printers - def get_user_saved_config(self): - if self.config_path != self.default_config_path: - print("Get") - def save_user_config_options(self): save_config = configparser.ConfigParser() for item in self.configurable_options: @@ -365,7 +351,7 @@ class KlipperScreenConfig: save_output = self._build_config_string(save_config).split("\n") for i in range(len(save_output)): - save_output[i] = "%s %s" % (self.do_not_edit_prefix, save_output[i]) + save_output[i] = f"{self.do_not_edit_prefix} {save_output[i]}" if self.config_path == self.default_config_path: user_def = "" @@ -379,21 +365,20 @@ class KlipperScreenConfig: self.do_not_edit_prefix) if self.config_path != self.default_config_path: - path = self.config_path + filepath = self.config_path else: - path = os.path.expanduser("~/") - klipper_config = os.path.join(path, "klipper_config") + filepath = os.path.expanduser("~/") + klipper_config = os.path.join(filepath, "klipper_config") if os.path.exists(klipper_config): - path = os.path.join(klipper_config, "KlipperScreen.conf") + filepath = os.path.join(klipper_config, "KlipperScreen.conf") else: - path = os.path.join(path, "KlipperScreen.conf") + filepath = os.path.join(filepath, "KlipperScreen.conf") try: - file = open(path, 'w') - file.write(contents) - file.close() + with open(filepath, 'w') as file: + file.write(contents) except Exception: - logging.error("Error writing configuration file in %s" % path) + logging.error(f"Error writing configuration file in {filepath}") def set(self, section, name, value): self.config.set(section, name, value) @@ -411,7 +396,8 @@ class KlipperScreenConfig: ] logging.info("\n".join(lines)) - def _build_config_string(self, config): + @staticmethod + def _build_config_string(config): sfile = StringIO() config.write(sfile) sfile.seek(0) @@ -433,7 +419,7 @@ class KlipperScreenConfig: try: item["params"] = json.loads(cfg.get("params", "{}")) except Exception: - logging.debug("Unable to parse parameters for [%s]" % name) + logging.debug(f"Unable to parse parameters for [{name}]") item["params"] = {} return {name[(len(menu) + 6):]: item} @@ -442,11 +428,10 @@ class KlipperScreenConfig: if name not in self.config: return False cfg = self.config[name] - item = { + return { "extruder": cfg.getint("extruder", None), "bed": cfg.getint("bed", None), "heater_generic": cfg.getint("heater_generic", None), "temperature_fan": cfg.getint("temperature_fan", None), "gcode": cfg.get("gcode", None) } - return item diff --git a/ks_includes/files.py b/ks_includes/files.py index bce3a4a3..4133bc6f 100644 --- a/ks_includes/files.py +++ b/ks_includes/files.py @@ -21,7 +21,7 @@ class KlippyFiles: vsd = self._screen.printer.get_config_section("virtual_sdcard") if "path" in vsd: self.gcodes_path = os.path.expanduser(vsd['path']) - logging.info("Gcodes path: %s" % self.gcodes_path) + logging.info(f"Gcodes path: {self.gcodes_path}") def reset(self): self.run_callbacks() @@ -44,7 +44,7 @@ class KlippyFiles: newfiles.append(file) self.add_file(item, False) - if len(newfiles) > 0 or len(deletedfiles) > 0: + if newfiles or len(deletedfiles) > 0: self.run_callbacks(newfiles, deletedfiles) if len(deletedfiles) > 0: @@ -52,27 +52,27 @@ class KlippyFiles: self.remove_file(file) elif method == "server.files.directory": if "result" in result: - dir = params['path'][7:] if params['path'].startswith('gcodes/') else params['path'] - if dir[-1] == '/': - dir = dir[:-1] + directory = params['path'][7:] if params['path'].startswith('gcodes/') else params['path'] + if directory[-1] == '/': + directory = directory[:-1] newfiles = [] for file in result['result']['files']: - fullpath = "%s/%s" % (dir, file['filename']) + fullpath = f"{directory}/{file['filename']}" if fullpath not in self.filelist: newfiles.append(fullpath) - if len(newfiles) > 0: + if newfiles: self.run_callbacks(newfiles) elif method == "server.files.metadata": if "error" in result.keys(): - logging.debug("Error in getting metadata for %s. Retrying in 6 seconds" % (params['filename'])) + logging.debug(f"Error in getting metadata for {params['filename']}. Retrying in 6 seconds") return for x in result['result']: self.files[params['filename']][x] = result['result'][x] if "thumbnails" in self.files[params['filename']]: - self.files[params['filename']]['thumbnails'].sort(key=lambda x: x['size'], reverse=True) + self.files[params['filename']]['thumbnails'].sort(key=lambda y: y['size'], reverse=True) for thumbnail in self.files[params['filename']]['thumbnails']: thumbnail['local'] = False @@ -90,12 +90,12 @@ class KlippyFiles: def add_file(self, item, notify=True): if 'filename' not in item and 'path' not in item: - logging.info("Error adding item, unknown filename or path: %s" % item) + logging.info(f"Error adding item, unknown filename or path: {item}") return filename = item['path'] if "path" in item else item['filename'] if filename in self.filelist: - logging.info("File already exists: %s" % filename) + logging.info(f"File already exists: {filename}") self.request_metadata(filename) GLib.timeout_add_seconds(1, self.run_callbacks, mods=[filename]) return @@ -113,14 +113,14 @@ class KlippyFiles: try: self.callbacks.append(callback) except Exception: - logging.debug("Callback not found: %s" % callback) + logging.debug(f"Callback not found: {callback}") def process_update(self, data): if 'item' in data and data['item']['root'] != 'gcodes': return if data['action'] == "create_dir": - self._screen._ws.klippy.get_file_dir("gcodes/%s" % data['item']['path'], self._callback) + self._screen._ws.klippy.get_file_dir(f"gcodes/{data['item']['path']}", self._callback) elif data['action'] == "create_file": self.add_file(data['item']) elif data['action'] == "delete_file": @@ -137,7 +137,7 @@ class KlippyFiles: self.callbacks.pop(self.callbacks.index(callback)) def file_exists(self, filename): - return True if filename in self.filelist else False + return filename in self.filelist def file_metadata_exists(self, filename): if not self.file_exists(filename): @@ -147,10 +147,11 @@ class KlippyFiles: return False def get_thumbnail_location(self, filename, small=False): - thumb = self.files[filename]['thumbnails'][0] - if small and len(self.files[filename]['thumbnails']) > 1: - if self.files[filename]['thumbnails'][0]['width'] > self.files[filename]['thumbnails'][1]['width']: - thumb = self.files[filename]['thumbnails'][1] + if small and len(self.files[filename]['thumbnails']) > 1 \ + and self.files[filename]['thumbnails'][0]['width'] > self.files[filename]['thumbnails'][1]['width']: + thumb = self.files[filename]['thumbnails'][1] + else: + thumb = self.files[filename]['thumbnails'][0] if thumb['local'] is False: return ['http', thumb['path']] return ['file', thumb['path']] @@ -179,10 +180,16 @@ class KlippyFiles: self.run_callbacks(deletedfiles=[filename]) def ret_file_data(self, filename): - print("Getting file info for %s" % filename) + logging.info(f"Getting file info for {filename}") self._screen._ws.klippy.get_file_metadata(filename, self._callback) - def run_callbacks(self, newfiles=[], deletedfiles=[], mods=[]): + def run_callbacks(self, newfiles=None, deletedfiles=None, mods=None): + if mods is None: + mods = [] + if deletedfiles is None: + deletedfiles = [] + if newfiles is None: + newfiles = [] if len(self.callbacks) <= 0: return False for cb in self.callbacks: diff --git a/ks_includes/functions.py b/ks_includes/functions.py index 50c7d00e..6c619f1b 100644 --- a/ks_includes/functions.py +++ b/ks_includes/functions.py @@ -78,7 +78,7 @@ def get_wireless_interfaces(): for line in result: match = re.search('^(\\S+)\\s+.*$', line) if match: - interfaces.append(match.group(1)) + interfaces.append(match[1]) return interfaces @@ -174,9 +174,11 @@ def setup_logging(log_file, software_version): queue, stdout_hdlr) listener.start() - def logging_exception_handler(type, value, tb, thread_identifier=None): + def logging_exception_handler(ex_type, value, tb, thread_identifier=None): logging.exception( - "Uncaught exception %s: %s\nTraceback: %s" % (type, value, "\n".join(traceback.format_tb(tb)))) + f'Uncaught exception {ex_type}: {value}\n' + f'Traceback: {traceback.format_tb(tb)}' + ) sys.excepthook = logging_exception_handler logging.captureWarnings(True) diff --git a/ks_includes/locales/KlipperScreen.pot b/ks_includes/locales/KlipperScreen.pot index 6915e07f..db17c588 100644 --- a/ks_includes/locales/KlipperScreen.pot +++ b/ks_includes/locales/KlipperScreen.pot @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: PACKAGE VERSION\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2022-07-02 13:43-0300\n" +"POT-Creation-Date: 2022-07-12 22:17-0300\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" @@ -451,6 +451,9 @@ msgid_plural "Packages will be updated" msgstr[0] "" msgstr[1] "" +msgid "Part Fan" +msgstr "" + msgid "Password saved" msgstr "" @@ -463,6 +466,9 @@ msgstr "" msgid "Perform a full upgrade?" msgstr "" +msgid "Pins" +msgstr "" + msgid "Please recompile and flash the micro-controller." msgstr "" @@ -536,6 +542,9 @@ msgstr "" msgid "Retry #%s" msgstr "" +msgid "Retrying" +msgstr "" + msgid "Save" msgstr "" diff --git a/ks_includes/locales/da/LC_MESSAGES/KlipperScreen.po b/ks_includes/locales/da/LC_MESSAGES/KlipperScreen.po index 0c6a5eee..c7f5f2f0 100644 --- a/ks_includes/locales/da/LC_MESSAGES/KlipperScreen.po +++ b/ks_includes/locales/da/LC_MESSAGES/KlipperScreen.po @@ -2,7 +2,7 @@ msgid "" msgstr "" "Project-Id-Version: KlipperScreen\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2022-07-02 13:43-0300\n" +"POT-Creation-Date: 2022-07-12 22:17-0300\n" "PO-Revision-Date: \n" "Last-Translator: SRBJ\n" "Language-Team: \n" @@ -454,6 +454,9 @@ msgid_plural "Packages will be updated" msgstr[0] "Pakken vil blive opdateret" msgstr[1] "Pakker vil blive opdateret" +msgid "Part Fan" +msgstr "" + msgid "Password saved" msgstr "Adgangskode gemt" @@ -466,6 +469,9 @@ msgstr "På pause" msgid "Perform a full upgrade?" msgstr "Vil du udføre en fuld opgradering?" +msgid "Pins" +msgstr "" + msgid "Please recompile and flash the micro-controller." msgstr "Genkompilér og flash mikrocontrolleren." @@ -539,6 +545,9 @@ msgstr "" msgid "Retry #%s" msgstr "Prøv igen #%s" +msgid "Retrying" +msgstr "" + msgid "Save" msgstr "Gem" diff --git a/ks_includes/locales/de_DE/LC_MESSAGES/KlipperScreen.po b/ks_includes/locales/de_DE/LC_MESSAGES/KlipperScreen.po index b305f742..a7d517bb 100644 --- a/ks_includes/locales/de_DE/LC_MESSAGES/KlipperScreen.po +++ b/ks_includes/locales/de_DE/LC_MESSAGES/KlipperScreen.po @@ -7,7 +7,7 @@ msgid "" msgstr "" "Project-Id-Version: KlipperScreen\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2022-07-02 13:43-0300\n" +"POT-Creation-Date: 2022-07-12 22:17-0300\n" "PO-Revision-Date: 2022-03-31 10:43-0300\n" "Last-Translator: \n" "Language-Team: \n" @@ -469,6 +469,9 @@ msgid_plural "Packages will be updated" msgstr[0] "Paket wird aktualisiert" msgstr[1] "Pakete werden aktualisiert" +msgid "Part Fan" +msgstr "" + msgid "Password saved" msgstr "Passwort gespeichert" @@ -481,6 +484,9 @@ msgstr "Pausiert" msgid "Perform a full upgrade?" msgstr "Vollständiges Upgrade durchführen?" +msgid "Pins" +msgstr "" + msgid "Please recompile and flash the micro-controller." msgstr "Please recompile and flash the micro-controller." @@ -554,6 +560,9 @@ msgstr "Rückzugsgeschwindigkeit" msgid "Retry #%s" msgstr "Wiederholen #%s" +msgid "Retrying" +msgstr "" + msgid "Save" msgstr "Speichern" diff --git a/ks_includes/locales/en/LC_MESSAGES/KlipperScreen.po b/ks_includes/locales/en/LC_MESSAGES/KlipperScreen.po index a3293837..bd10bff2 100644 --- a/ks_includes/locales/en/LC_MESSAGES/KlipperScreen.po +++ b/ks_includes/locales/en/LC_MESSAGES/KlipperScreen.po @@ -2,7 +2,7 @@ msgid "" msgstr "" "Project-Id-Version: KlipperScreen\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2022-07-02 13:43-0300\n" +"POT-Creation-Date: 2022-07-12 22:17-0300\n" "PO-Revision-Date: \n" "Last-Translator: \n" "Language-Team: \n" @@ -446,6 +446,9 @@ msgid_plural "Packages will be updated" msgstr[0] "" msgstr[1] "" +msgid "Part Fan" +msgstr "" + msgid "Password saved" msgstr "" @@ -458,6 +461,9 @@ msgstr "" msgid "Perform a full upgrade?" msgstr "" +msgid "Pins" +msgstr "" + msgid "Please recompile and flash the micro-controller." msgstr "" @@ -531,6 +537,9 @@ msgstr "" msgid "Retry #%s" msgstr "" +msgid "Retrying" +msgstr "" + msgid "Save" msgstr "" diff --git a/ks_includes/locales/es/LC_MESSAGES/KlipperScreen.po b/ks_includes/locales/es/LC_MESSAGES/KlipperScreen.po index 501d5a5f..1a972c05 100644 --- a/ks_includes/locales/es/LC_MESSAGES/KlipperScreen.po +++ b/ks_includes/locales/es/LC_MESSAGES/KlipperScreen.po @@ -7,7 +7,7 @@ msgid "" msgstr "" "Project-Id-Version: KlipperScreen\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2022-07-02 13:43-0300\n" +"POT-Creation-Date: 2022-07-12 22:17-0300\n" "PO-Revision-Date: 2022-06-02 13:54-0300\n" "Last-Translator: alfrix\n" "Language-Team: \n" @@ -459,6 +459,9 @@ msgid_plural "Packages will be updated" msgstr[0] "Paquete será actualizado" msgstr[1] "Paquetes serán actualizados" +msgid "Part Fan" +msgstr "" + msgid "Password saved" msgstr "Contraseña guardada" @@ -471,6 +474,9 @@ msgstr "Pausado" msgid "Perform a full upgrade?" msgstr "¿Actualizar Todo?" +msgid "Pins" +msgstr "" + msgid "Please recompile and flash the micro-controller." msgstr "Por favor recompile y flashee el micro-controlador." @@ -544,6 +550,9 @@ msgstr "Velocidad de Retracción" msgid "Retry #%s" msgstr "Intento #%s" +msgid "Retrying" +msgstr "" + msgid "Save" msgstr "Guardar" diff --git a/ks_includes/locales/fr_FR/LC_MESSAGES/KlipperScreen.po b/ks_includes/locales/fr_FR/LC_MESSAGES/KlipperScreen.po index 99e8dc7d..b9c399ae 100644 --- a/ks_includes/locales/fr_FR/LC_MESSAGES/KlipperScreen.po +++ b/ks_includes/locales/fr_FR/LC_MESSAGES/KlipperScreen.po @@ -7,7 +7,7 @@ msgid "" msgstr "" "Project-Id-Version: KlipperScreen\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2022-07-02 13:43-0300\n" +"POT-Creation-Date: 2022-07-12 22:17-0300\n" "PO-Revision-Date: 2022-03-31 10:50-0300\n" "Last-Translator: O. Robardet\n" "Language-Team: \n" @@ -459,6 +459,9 @@ msgid_plural "Packages will be updated" msgstr[0] "Le paquet sera mis à jour" msgstr[1] "Forfaits seront mis à jour" +msgid "Part Fan" +msgstr "" + msgid "Password saved" msgstr "Mot de passe enregistré" @@ -471,6 +474,9 @@ msgstr "En pause" msgid "Perform a full upgrade?" msgstr "Effectuer une mise à jour complète ?" +msgid "Pins" +msgstr "" + msgid "Please recompile and flash the micro-controller." msgstr "Veuillez recompiler et flasher le microcontrôleur." @@ -544,6 +550,9 @@ msgstr "Vitesse de rétraction" msgid "Retry #%s" msgstr "Réessayez #%s" +msgid "Retrying" +msgstr "" + msgid "Save" msgstr "Enregistrer" diff --git a/ks_includes/locales/he_IL/LC_MESSAGES/KlipperScreen.po b/ks_includes/locales/he_IL/LC_MESSAGES/KlipperScreen.po index 99372e8f..30339052 100644 --- a/ks_includes/locales/he_IL/LC_MESSAGES/KlipperScreen.po +++ b/ks_includes/locales/he_IL/LC_MESSAGES/KlipperScreen.po @@ -7,7 +7,7 @@ msgid "" msgstr "" "Project-Id-Version: Klipperscreen\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2022-07-02 13:43-0300\n" +"POT-Creation-Date: 2022-07-12 22:17-0300\n" "PO-Revision-Date: 2022-03-31 10:54-0300\n" "Last-Translator: Emanuel Sharvit \n" "Language-Team: \n" @@ -464,6 +464,9 @@ msgstr[1] "חבילות יעודכנו" msgstr[2] "חבילות יעודכנו" msgstr[3] "חבילות יעודכנו" +msgid "Part Fan" +msgstr "" + msgid "Password saved" msgstr "הסיסמה נשמרה" @@ -476,6 +479,9 @@ msgstr "מושהה" msgid "Perform a full upgrade?" msgstr "לבצע שדרוג מלא?" +msgid "Pins" +msgstr "" + msgid "Please recompile and flash the micro-controller." msgstr "אנא הידור מחדש והבזק את המיקרו-בקר." @@ -549,6 +555,9 @@ msgstr "" msgid "Retry #%s" msgstr "נסה שוב #%s" +msgid "Retrying" +msgstr "" + msgid "Save" msgstr "להציל" diff --git a/ks_includes/locales/hu_HU/LC_MESSAGES/KlipperScreen.po b/ks_includes/locales/hu_HU/LC_MESSAGES/KlipperScreen.po index 05802f9d..cefe9da5 100644 --- a/ks_includes/locales/hu_HU/LC_MESSAGES/KlipperScreen.po +++ b/ks_includes/locales/hu_HU/LC_MESSAGES/KlipperScreen.po @@ -454,6 +454,9 @@ msgid_plural "Packages will be updated" msgstr[0] "A csomag frissítésre kerül" msgstr[1] "Csomag frissül" +msgid "Part Fan" +msgstr "" + msgid "Password saved" msgstr "Jelszó mentve" @@ -466,6 +469,9 @@ msgstr "Szüneteltetve" msgid "Perform a full upgrade?" msgstr "Teljes frissítést hajt végre?" +msgid "Pins" +msgstr "" + msgid "Please recompile and flash the micro-controller." msgstr "Fordítsa újra és frissítse a mikrovezérlőt." @@ -539,6 +545,9 @@ msgstr "Visszahúzási sebesség" msgid "Retry #%s" msgstr "Újra #%s" +msgid "Retrying" +msgstr "" + msgid "Save" msgstr "Mentés" diff --git a/ks_includes/locales/it/LC_MESSAGES/KlipperScreen.po b/ks_includes/locales/it/LC_MESSAGES/KlipperScreen.po index 9c05408c..c2081893 100644 --- a/ks_includes/locales/it/LC_MESSAGES/KlipperScreen.po +++ b/ks_includes/locales/it/LC_MESSAGES/KlipperScreen.po @@ -2,7 +2,7 @@ msgid "" msgstr "" "Project-Id-Version: KlipperScreen\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2022-07-02 13:43-0300\n" +"POT-Creation-Date: 2022-07-12 22:17-0300\n" "PO-Revision-Date: \n" "Last-Translator: pappicio\n" "Language-Team: \n" @@ -454,6 +454,9 @@ msgid_plural "Packages will be updated" msgstr[0] "Pacchetto verrà aggiornato" msgstr[1] "I pacchetti verranno aggiornati" +msgid "Part Fan" +msgstr "" + msgid "Password saved" msgstr "Password salvata" @@ -466,6 +469,9 @@ msgstr "In Pausa" msgid "Perform a full upgrade?" msgstr "Eseguire un aggiornamento completo?" +msgid "Pins" +msgstr "" + msgid "Please recompile and flash the micro-controller." msgstr "Si prega di ricompilare e flashare il microcontrollore." @@ -539,6 +545,9 @@ msgstr "" msgid "Retry #%s" msgstr "Riprova #%s" +msgid "Retrying" +msgstr "" + msgid "Save" msgstr "Salva" diff --git a/ks_includes/locales/ko_KR/LC_MESSAGES/KlipperScreen.po b/ks_includes/locales/ko_KR/LC_MESSAGES/KlipperScreen.po index 9f066bea..2723a75f 100644 --- a/ks_includes/locales/ko_KR/LC_MESSAGES/KlipperScreen.po +++ b/ks_includes/locales/ko_KR/LC_MESSAGES/KlipperScreen.po @@ -2,7 +2,7 @@ msgid "" msgstr "" "Project-Id-Version: KlipperScreen\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2022-07-02 13:43-0300\n" +"POT-Creation-Date: 2022-07-12 22:17-0300\n" "PO-Revision-Date: \n" "Last-Translator: NSteven\n" "Language-Team: NSteven\n" @@ -453,6 +453,9 @@ msgid "Package will be updated" msgid_plural "Packages will be updated" msgstr[0] "패키지가 업데이트 됩니다" +msgid "Part Fan" +msgstr "" + msgid "Password saved" msgstr "비밀번호 저장됨" @@ -465,6 +468,9 @@ msgstr "일시정지됨" msgid "Perform a full upgrade?" msgstr "전체 업그레이드를 실행합니까?" +msgid "Pins" +msgstr "" + msgid "Please recompile and flash the micro-controller." msgstr "MCU 펌웨어를 다시 컴파일 한 다음 플래싱 해주세요" @@ -538,6 +544,9 @@ msgstr "퇴출 속도" msgid "Retry #%s" msgstr "재시도 #%s" +msgid "Retrying" +msgstr "" + msgid "Save" msgstr "저장" diff --git a/ks_includes/locales/pl_PL/LC_MESSAGES/KlipperScreen.po b/ks_includes/locales/pl_PL/LC_MESSAGES/KlipperScreen.po index 219a477d..447ed699 100644 --- a/ks_includes/locales/pl_PL/LC_MESSAGES/KlipperScreen.po +++ b/ks_includes/locales/pl_PL/LC_MESSAGES/KlipperScreen.po @@ -7,7 +7,7 @@ msgid "" msgstr "" "Project-Id-Version: KlipperScreen\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2022-07-02 13:43-0300\n" +"POT-Creation-Date: 2022-07-12 22:17-0300\n" "PO-Revision-Date: 2022-03-31 11:06-0300\n" "Last-Translator: \n" "Language-Team: \n" @@ -457,6 +457,9 @@ msgstr[0] "Pakiet zostanie zaktualizowany" msgstr[1] "Pakiety zostaną zaktualizowane" msgstr[2] "Pakiety zostaną zaktualizowane" +msgid "Part Fan" +msgstr "" + msgid "Password saved" msgstr "Hasło zostało zapisane" @@ -469,6 +472,9 @@ msgstr "Zapauzowane" msgid "Perform a full upgrade?" msgstr "Przeprowadzić pełną aktualizację?" +msgid "Pins" +msgstr "" + msgid "Please recompile and flash the micro-controller." msgstr "Proszę przekompilować i sflashować mikrokontroler." @@ -542,6 +548,9 @@ msgstr "" msgid "Retry #%s" msgstr "Spróbuj ponownie #%s" +msgid "Retrying" +msgstr "" + msgid "Save" msgstr "Zapisz" diff --git a/ks_includes/locales/ru_RU/LC_MESSAGES/KlipperScreen.po b/ks_includes/locales/ru_RU/LC_MESSAGES/KlipperScreen.po index 9bdd4d78..7ad12929 100644 --- a/ks_includes/locales/ru_RU/LC_MESSAGES/KlipperScreen.po +++ b/ks_includes/locales/ru_RU/LC_MESSAGES/KlipperScreen.po @@ -6,7 +6,7 @@ msgid "" msgstr "" "Project-Id-Version: KlipperScreen\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2022-07-02 13:43-0300\n" +"POT-Creation-Date: 2022-07-12 22:17-0300\n" "PO-Revision-Date: 2022-06-03 20:25-0500\n" "Last-Translator: Jakob Kais \n" "Language-Team: \n" @@ -461,6 +461,9 @@ msgstr[0] "Пакет будет обновлен" msgstr[1] "Пакеты будут обновляться" msgstr[2] "Пакеты будут обновляться" +msgid "Part Fan" +msgstr "" + msgid "Password saved" msgstr "Пароль сохранен" @@ -473,6 +476,9 @@ msgstr "Приостановлено" msgid "Perform a full upgrade?" msgstr "Выполнить полное обновление?" +msgid "Pins" +msgstr "" + msgid "Please recompile and flash the micro-controller." msgstr "Пожалуйста, перекомпилируйте и прошейте микроконтроллер." @@ -546,6 +552,9 @@ msgstr "" msgid "Retry #%s" msgstr "Повторить #%s" +msgid "Retrying" +msgstr "" + msgid "Save" msgstr "Сохранить" diff --git a/ks_includes/locales/sv_SE/LC_MESSAGES/KlipperScreen.po b/ks_includes/locales/sv_SE/LC_MESSAGES/KlipperScreen.po index 475b3433..9082de19 100644 --- a/ks_includes/locales/sv_SE/LC_MESSAGES/KlipperScreen.po +++ b/ks_includes/locales/sv_SE/LC_MESSAGES/KlipperScreen.po @@ -7,7 +7,7 @@ msgid "" msgstr "" "Project-Id-Version: \n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2022-07-02 13:43-0300\n" +"POT-Creation-Date: 2022-07-12 22:17-0300\n" "PO-Revision-Date: 2022-04-15 17:25+0200\n" "Last-Translator: \n" "Language-Team: \n" @@ -459,6 +459,9 @@ msgid_plural "Packages will be updated" msgstr[0] "Paketet kommer att uppdateras" msgstr[1] "Paketen kommer att uppdateras" +msgid "Part Fan" +msgstr "" + msgid "Password saved" msgstr "Lösenordet har sparats" @@ -471,6 +474,9 @@ msgstr "Pausad" msgid "Perform a full upgrade?" msgstr "Utför en fullständig uppgradering?" +msgid "Pins" +msgstr "" + msgid "Please recompile and flash the micro-controller." msgstr "Vänligen kompilera om och flasha mikrokontrollern." @@ -544,6 +550,9 @@ msgstr "" msgid "Retry #%s" msgstr "" +msgid "Retrying" +msgstr "" + msgid "Save" msgstr "Spara" diff --git a/ks_includes/locales/tr_TR/LC_MESSAGES/KlipperScreen.po b/ks_includes/locales/tr_TR/LC_MESSAGES/KlipperScreen.po index cda217ae..f76334e5 100644 --- a/ks_includes/locales/tr_TR/LC_MESSAGES/KlipperScreen.po +++ b/ks_includes/locales/tr_TR/LC_MESSAGES/KlipperScreen.po @@ -459,6 +459,9 @@ msgid_plural "Packages will be updated" msgstr[0] "Paket yükseltilecek" msgstr[1] "Paketler yükseltilecek" +msgid "Part Fan" +msgstr "" + msgid "Password saved" msgstr "Şifre kaydedildi" @@ -471,6 +474,9 @@ msgstr "Duraklatıldı" msgid "Perform a full upgrade?" msgstr "Tam yükseltme yap?" +msgid "Pins" +msgstr "" + msgid "Please recompile and flash the micro-controller." msgstr "Lütfen mikro denetleyiciyi yeniden derleyin ve flaşlayın." @@ -544,6 +550,9 @@ msgstr "Geri Çekme Hızı" msgid "Retry #%s" msgstr "Yeniden Dene #%s" +msgid "Retrying" +msgstr "" + msgid "Save" msgstr "Kaydet" diff --git a/ks_includes/locales/uk_UA/LC_MESSAGES/KlipperScreen.po b/ks_includes/locales/uk_UA/LC_MESSAGES/KlipperScreen.po index 58f06bab..027f5a57 100644 --- a/ks_includes/locales/uk_UA/LC_MESSAGES/KlipperScreen.po +++ b/ks_includes/locales/uk_UA/LC_MESSAGES/KlipperScreen.po @@ -7,7 +7,7 @@ msgid "" msgstr "" "Project-Id-Version: 2022-06-02 14:53-0300\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2022-07-02 13:43-0300\n" +"POT-Creation-Date: 2022-07-12 22:17-0300\n" "PO-Revision-Date: 2022-06-03 10:02+0300\n" "Last-Translator: \n" "Language-Team: Andrii Komarovskyi\n" @@ -462,6 +462,9 @@ msgstr[0] "Пакет буде оновлено" msgstr[1] "Пакет оновлено" msgstr[2] "Пакет оновлено" +msgid "Part Fan" +msgstr "" + msgid "Password saved" msgstr "Пароль збережено" @@ -474,6 +477,9 @@ msgstr "ПАУЗА" msgid "Perform a full upgrade?" msgstr "Виконати повне оновлення?" +msgid "Pins" +msgstr "" + msgid "Please recompile and flash the micro-controller." msgstr "Будь ласка, перекомпілюйте та перепрошійте мікроконтролер." @@ -547,6 +553,9 @@ msgstr "Швидкість втягування" msgid "Retry #%s" msgstr "Повторіть #%s" +msgid "Retrying" +msgstr "" + msgid "Save" msgstr "Зберегти" diff --git a/ks_includes/locales/zh_CN/LC_MESSAGES/KlipperScreen.po b/ks_includes/locales/zh_CN/LC_MESSAGES/KlipperScreen.po index ad42db2e..16db059f 100644 --- a/ks_includes/locales/zh_CN/LC_MESSAGES/KlipperScreen.po +++ b/ks_includes/locales/zh_CN/LC_MESSAGES/KlipperScreen.po @@ -458,6 +458,9 @@ msgid "Package will be updated" msgid_plural "Packages will be updated" msgstr[0] "包将被更新" +msgid "Part Fan" +msgstr "" + msgid "Password saved" msgstr "密码已保存" @@ -470,6 +473,9 @@ msgstr "已暂停" msgid "Perform a full upgrade?" msgstr "是否全部升级?" +msgid "Pins" +msgstr "" + msgid "Please recompile and flash the micro-controller." msgstr "请重新编译并烧录微控制器。" @@ -543,6 +549,9 @@ msgstr "回抽速度" msgid "Retry #%s" msgstr "重试 #%s" +msgid "Retrying" +msgstr "" + msgid "Save" msgstr "保存" diff --git a/ks_includes/locales/zh_TW/LC_MESSAGES/KlipperScreen.po b/ks_includes/locales/zh_TW/LC_MESSAGES/KlipperScreen.po index 920d96f8..3c4b19d1 100644 --- a/ks_includes/locales/zh_TW/LC_MESSAGES/KlipperScreen.po +++ b/ks_includes/locales/zh_TW/LC_MESSAGES/KlipperScreen.po @@ -7,7 +7,7 @@ msgid "" msgstr "" "Project-Id-Version: KlipperScreen\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2022-07-02 13:43-0300\n" +"POT-Creation-Date: 2022-07-12 22:17-0300\n" "PO-Revision-Date: 2022-03-31 11:25-0300\n" "Last-Translator: \n" "Language-Team: \n" @@ -458,6 +458,9 @@ msgid "Package will be updated" msgid_plural "Packages will be updated" msgstr[0] "包將被更新" +msgid "Part Fan" +msgstr "" + msgid "Password saved" msgstr "密碼已保存" @@ -470,6 +473,9 @@ msgstr "已暫停" msgid "Perform a full upgrade?" msgstr "執行全面升級?" +msgid "Pins" +msgstr "" + msgid "Please recompile and flash the micro-controller." msgstr "請重新編譯並刷寫微控制器。" @@ -543,6 +549,9 @@ msgstr "" msgid "Retry #%s" msgstr "重試 #%s" +msgid "Retrying" +msgstr "" + msgid "Save" msgstr "儲存" diff --git a/ks_includes/printer.py b/ks_includes/printer.py index 6f4a4551..89dda631 100644 --- a/ks_includes/printer.py +++ b/ks_includes/printer.py @@ -6,30 +6,34 @@ from gi.repository import Gdk, GLib class Printer: - data = {} - devices = {} - power_devices = {} - state_callbacks = { - "disconnected": None, - "error": None, - "paused": None, - "printing": None, - "ready": None, - "startup": None, - "shutdown": None - } - tools = [] - extrudercount = 0 - tempdevcount = 0 - fancount = 0 - def __init__(self, printer_info, data, state_execute_cb): + self.klipper = {"version": printer_info['software_version']} + self.tempstore = None + self.config = None self.state = "disconnected" self.state_cb = state_execute_cb self.power_devices = {} self.store_timeout = False + self.data = data + self.devices = {} + self.power_devices = {} + self.state_callbacks = { + "disconnected": None, + "error": None, + "paused": None, + "printing": None, + "ready": None, + "startup": None, + "shutdown": None + } + self.tools = [] + self.extrudercount = 0 + self.tempdevcount = 0 + self.fancount = 0 def reset(self): + GLib.source_remove(self.store_timeout) + self.store_timeout = None self.state = None self.state_cb = None self.data = None @@ -40,14 +44,12 @@ class Printer: self.extrudercount = None self.tempdevcount = None self.fancount = None - GLib.source_remove(self.store_timeout) - self.store_timeout = None self.config = None self.klipper = None self.tempstore = None def reinit(self, printer_info, data): - logging.debug("Moonraker object status: %s" % data) + logging.debug(f"Moonraker object status: {data}") self.config = data['configfile']['config'] self.extrudercount = 0 self.tempdevcount = 0 @@ -57,7 +59,7 @@ class Printer: self.data = data self.klipper = {} self.tempstore = {} - if self.store_timeout is False: + if not self.store_timeout: self.store_timeout = GLib.timeout_add_seconds(1, self._update_temp_store) self.klipper = { @@ -65,7 +67,7 @@ class Printer: } for x in self.config.keys(): - if x[0:8] == "extruder": + if x[:8] == "extruder": self.tools.append(x) self.tools = sorted(self.tools) self.extrudercount += 1 @@ -75,16 +77,24 @@ class Printer: "temperature": 0, "target": 0 } - if x == 'heater_bed' or x.startswith('heater_generic ') or x.startswith('temperature_sensor ') \ + if x == 'heater_bed' \ + or x.startswith('heater_generic ') \ + or x.startswith('temperature_sensor ') \ or x.startswith('temperature_fan '): self.devices[x] = { "temperature": 0, "target": 0 } - self.tempdevcount += 1 - if x == 'fan' or x.startswith('controller_fan ') or x.startswith('heater_fan ') \ + # Support for hiding devices by name + if not " ".join(x.split(" ")[1:]).startswith("_"): + self.tempdevcount += 1 + if x == 'fan' \ + or x.startswith('controller_fan ') \ + or x.startswith('heater_fan ') \ or x.startswith('fan_generic '): - self.fancount += 1 + # Support for hiding devices by name + if not " ".join(x.split(" ")[1:]).startswith("_"): + self.fancount += 1 if x.startswith('bed_mesh '): r = self.config[x] r['x_count'] = int(r['x_count']) @@ -96,27 +106,12 @@ class Printer: r['points'] = [[float(j.strip()) for j in i.split(",")] for i in r['points'].strip().split("\n")] self.process_update(data) - logging.info("Klipper version: %s", self.klipper['version']) - logging.info("# Extruders: %s", str(self.extrudercount)) - logging.info("# Temperature devices: %s", str(self.tempdevcount)) - logging.info("# Fans: %s", str(self.fancount)) + logging.info(f"Klipper version: {self.klipper['version']}") + logging.info(f"# Extruders: {self.extrudercount}") + logging.info(f"# Temperature devices: {self.tempdevcount}") + logging.info(f"# Fans: {self.fancount}") def process_update(self, data): - keys = [ - 'bed_mesh', - 'display_status', - 'fan', - 'gcode_move', - 'idle_timeout', - 'pause_resume', - 'print_stats', - 'toolhead', - 'virtual_sdcard', - 'webhooks', - 'fimware_retraction', - 'motion_report' - ] - for x in (self.get_tools() + self.get_heaters() + self.get_filament_sensors()): if x in data: for i in data[x]: @@ -171,11 +166,11 @@ class Printer: if state == self.state or state not in list(self.state_callbacks): return - logging.debug("Changing state from '%s' to '%s'" % (self.state, state)) + logging.debug(f"Changing state from '{self.state}' to '{state}'") prev_state = self.state self.state = state if self.state_callbacks[state] is not None: - logging.debug("Adding callback for state: %s" % state) + logging.debug(f"Adding callback for state: {state}") Gdk.threads_add_idle( GLib.PRIORITY_HIGH_IDLE, self.state_cb, @@ -186,22 +181,18 @@ class Printer: def configure_power_devices(self, data): self.power_devices = {} - logging.debug("Processing power devices: %s" % data) + logging.debug(f"Processing power devices: {data}") for x in data['devices']: self.power_devices[x['device']] = { "status": "on" if x['status'] == "on" else "off" } - logging.debug("Power devices: %s" % self.power_devices) + logging.debug(f"Power devices: {self.power_devices}") def get_config_section_list(self, search=""): - if not hasattr(self, "config"): - return [] - return [i for i in list(self.config) if i.startswith(search)] + return [i for i in list(self.config) if i.startswith(search)] if hasattr(self, "config") else [] def get_config_section(self, section): - if section in self.config: - return self.config[section] - return False + return self.config[section] if section in self.config else False def get_data(self): return self.data @@ -211,9 +202,8 @@ class Printer: if self.config_section_exists("fan"): fans.append("fan") fan_types = ["controller_fan", "fan_generic", "heater_fan"] - for type in fan_types: - for f in self.get_config_section_list("%s " % type): - fans.append(f) + for fan_type in fan_types: + fans.extend(iter(self.get_config_section_list(f"{fan_type} "))) return fans def get_gcode_macros(self): @@ -223,45 +213,27 @@ class Printer: heaters = [] if self.has_heated_bed(): heaters.append("heater_bed") - for h in self.get_config_section_list("heater_generic "): - heaters.append(h) - for h in self.get_config_section_list("temperature_sensor "): - heaters.append(h) - for h in self.get_config_section_list("temperature_fan "): - heaters.append(h) + heaters.extend(iter(self.get_config_section_list("heater_generic "))) + heaters.extend(iter(self.get_config_section_list("temperature_sensor "))) + heaters.extend(iter(self.get_config_section_list("temperature_fan "))) return heaters def get_filament_sensors(self): - sensors = [] - for s in self.get_config_section_list("filament_switch_sensor "): - sensors.append(s) - for s in self.get_config_section_list("filament_motion_sensor "): - sensors.append(s) + sensors = list(self.get_config_section_list("filament_switch_sensor ")) + sensors.extend(iter(self.get_config_section_list("filament_motion_sensor "))) return sensors def get_printer_status_data(self): data = { "printer": { - "extruders": { - "count": self.extrudercount - }, - "temperature_devices": { - "count": self.tempdevcount - }, - "fans": { - "count": self.fancount - }, + "extruders": {"count": self.extrudercount}, + "temperature_devices": {"count": self.tempdevcount}, + "fans": {"count": self.fancount}, "bltouch": self.config_section_exists("bltouch"), - "gcode_macros": { - "count": len(self.get_gcode_macros()) - }, + "gcode_macros": {"count": len(self.get_gcode_macros())}, "idle_timeout": self.get_stat("idle_timeout").copy(), - "pause_resume": { - "is_paused": True if self.state == "paused" else False - }, - "power_devices": { - "count": len(self.get_power_devices()) - }, + "pause_resume": {"is_paused": self.state == "paused"}, + "power_devices": {"count": len(self.get_power_devices())}, "probe": self.config_section_exists("probe"), "firmware_retraction": self.config_section_exists("firmware_retraction"), "input_shaper": self.config_section_exists("input_shaper") @@ -287,12 +259,10 @@ class Printer: return self.power_devices[device]['status'] def get_stat(self, stat, substat=None): - if stat not in self.data: + if self.data is None or stat not in self.data: return {} if substat is not None: - if substat in self.data[stat]: - return self.data[stat][substat] - return {} + return self.data[stat][substat] if substat in self.data[stat] else {} return self.data[stat] def get_state(self): @@ -305,9 +275,7 @@ class Printer: self.devices[dev]['target'] = target def get_dev_stats(self, dev): - if dev in self.devices: - return self.devices[dev] - return None + return self.devices[dev] if dev in self.devices else None def get_dev_stat(self, dev, stat): if dev in self.devices and stat in self.devices[dev]: @@ -316,7 +284,7 @@ class Printer: def get_fan_speed(self, fan="fan", speed=None): if fan not in self.config or fan not in self.data: - logging.debug("Error getting %s config", fan) + logging.debug(f"Error getting {fan} config") return speed if speed is not None else 0 if speed is None and "speed" in self.data[fan]: speed = self.data[fan]["speed"] @@ -338,10 +306,7 @@ class Printer: 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 + return device in self.tempstore and "targets" in self.tempstore[device] def get_temp_store(self, device, section=False, results=0): if device not in self.tempstore: @@ -378,12 +343,10 @@ class Printer: 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)) + logging.info(f"Temp store: {list(self.tempstore)}") def config_section_exists(self, section): - if section in self.get_config_section_list(): - return True - return False + return section in self.get_config_section_list() def set_callbacks(self, callbacks): for name, cb in callbacks.items(): diff --git a/ks_includes/screen_panel.py b/ks_includes/screen_panel.py index dd86dc86..7d53ee70 100644 --- a/ks_includes/screen_panel.py +++ b/ks_includes/screen_panel.py @@ -10,6 +10,7 @@ from ks_includes.KlippyGcodes import KlippyGcodes class ScreenPanel: def __init__(self, screen, title, back=True, action_bar=True, printer_name=True): + self.menu = None self._screen = screen self._config = screen._config self._files = screen.files @@ -42,19 +43,6 @@ class ScreenPanel: else: self._screen._ws.klippy.emergency_stop() - def format_target(self, temp): - if temp <= 0: - return "" - else: - return "(%s)" % str(int(temp)) - - def format_temp(self, temp, places=1): - if places == 0: - n = int(temp) - else: - n = round(temp, places) - return "%s°C" % str(n) - def get(self): return self.layout @@ -90,13 +78,12 @@ class ScreenPanel: self._screen._ws.klippy.gcode_script(KlippyGcodes.QUAD_GANTRY_LEVEL) def menu_item_clicked(self, widget, panel, item): - print("### Creating panel " + item['panel'] + " : %s %s" % (panel, item)) + logging.info(f"### Creating panel {item['panel']} : {panel} {item}") if "items" in item: - self._screen.show_panel(self._screen._cur_panels[-1] + '_' + panel, item['panel'], item['name'], - 1, False, items=item['items']) + self._screen.show_panel(f'{self._screen._cur_panels[-1]}_{panel}', + item['panel'], item['name'], 1, False, items=item['items']) return - self._screen.show_panel(self._screen._cur_panels[-1] + '_' + panel, item['panel'], item['name'], - 1, False) + self._screen.show_panel(f'{self._screen._cur_panels[-1]}_{panel}', item['panel'], item['name'], 1, False) def menu_return(self, widget, home=False): if home is False: @@ -114,26 +101,19 @@ class ScreenPanel: if label in self.labels and 'l' in self.labels[label]: self.labels[label]['l'].set_text(text) - def update_temp(self, dev, temp, target, name=None): - if dev in self.labels and temp is not None: - if name is None: - self.labels[dev].set_label(self._gtk.formatTemperatureString(temp, target)) - else: - self.labels[dev].set_label("%s\n%s" % (name, self._gtk.formatTemperatureString(temp, target))) - def load_menu(self, widget, name): - if ("%s_menu" % name) not in self.labels: + if f"{name}_menu" not in self.labels: return for child in self.content.get_children(): self.content.remove(child) - self.menu.append('%s_menu' % name) + self.menu.append(f'{name}_menu') self.content.add(self.labels[self.menu[-1]]) self.content.show_all() def unload_menu(self, widget=None): - logging.debug("self.menu: %s" % self.menu) + logging.debug(f"self.menu: {self.menu}") if len(self.menu) <= 1 or self.menu[-2] not in self.labels: return @@ -148,24 +128,49 @@ class ScreenPanel: if tree_iter is not None: model = combo.get_model() value = model[tree_iter][1] - logging.debug("[%s] %s changed to %s" % (section, option, value)) + logging.debug(f"[{section}] {option} changed to {value}") self._config.set(section, option, value) self._config.save_user_config_options() if callback is not None: callback(value) def scale_moved(self, widget, event, section, option): - logging.debug("[%s] %s changed to %s" % (section, option, widget.get_value())) + logging.debug(f"[{section}] {option} changed to {widget.get_value()}") if section not in self._config.get_config().sections(): self._config.get_config().add_section(section) self._config.set(section, option, str(int(widget.get_value()))) self._config.save_user_config_options() def switch_config_option(self, switch, gparam, section, option, callback=None): - logging.debug("[%s] %s toggled %s" % (section, option, switch.get_active())) + logging.debug(f"[{section}] {option} toggled {switch.get_active()}") if section not in self._config.get_config().sections(): self._config.get_config().add_section(section) self._config.set(section, option, "True" if switch.get_active() else "False") self._config.save_user_config_options() if callback is not None: callback(switch.get_active()) + + @staticmethod + def format_time(seconds): + if seconds is None or seconds <= 0: + return "-" + seconds = int(seconds) + days = seconds // 86400 + seconds %= 86400 + hours = seconds // 3600 + seconds %= 3600 + minutes = seconds // 60 + seconds %= 60 + return f"{f'{days:2.0f}d ' if days > 0 else ''}" \ + f"{f'{hours:2.0f}h ' if hours > 0 else ''}" \ + f"{f'{minutes:2.0f}m ' if minutes > 0 else ''}" \ + f"{f'{seconds:2.0f}s' if days == 0 and hours == 0 and minutes == 0 else ''}" + + @staticmethod + def format_size(size): + size = float(size) + suffixes = ["kB", "MB", "GB", "TB", "PB", "EB", "ZB", "YB"] + for i, suffix in enumerate(suffixes, start=2): + unit = 1024 ** i + if size < unit: + return f"{(1024 * size / unit):.1f} {suffix}" diff --git a/ks_includes/widgets/graph.py b/ks_includes/widgets/graph.py index ffadc3f3..fc86e569 100644 --- a/ks_includes/widgets/graph.py +++ b/ks_includes/widgets/graph.py @@ -23,37 +23,33 @@ class HeaterGraph(Gtk.DrawingArea): self.connect('button_press_event', self.event_cb) self.font_size = round(font_size * 0.75) - def add_object(self, name, type, rgb=[0, 0, 0], dashed=False, fill=False): + def add_object(self, name, ev_type, rgb=None, dashed=False, fill=False): + if rgb is None: + rgb = [0, 0, 0] if name not in self.store: self.store.update({name: {"show": True}}) - self.store[name].update({type: { + self.store[name].update({ev_type: { "dashed": dashed, "fill": fill, "rgb": rgb }}) - self.max_length = max(self.max_length, len(self.printer.get_temp_store(name, type))) + self.max_length = max(self.max_length, len(self.printer.get_temp_store(name, ev_type))) - def event_cb(self, da, ev): - if ev.type == Gdk.EventType.BUTTON_PRESS: + @staticmethod + def event_cb(da, ev): + if ev.ev_type == Gdk.EventType.BUTTON_PRESS: x = ev.x y = ev.y - logging.info("Graph area: %s %s" % (x, y)) + logging.info(f"Graph area: {x} {y}") def get_max_length(self): - n = [] - for name in self.store: - if "temperatures" not in self.store[name]: - continue - n.append(len(self.printer.get_temp_store(name, "temperatures"))) - return min(n) + return min(len(self.printer.get_temp_store(name, "temperatures")) + for name in self.store if "temperatures" in self.store[name]) def get_max_num(self, data_points=0): 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))) + mnum.extend(max(self.printer.get_temp_store(x, t, data_points)) for t in self.store[x] if t != "show") return max(mnum) def draw_graph(self, da, ctx): @@ -97,14 +93,15 @@ class HeaterGraph(Gtk.DrawingArea): 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) + for dev_type in self.store[name]: + d = self.printer.get_temp_store(name, dev_type, data_points) if d is False: continue - self.graph_data(ctx, d, gsize, d_height_scale, d_width, self.store[name][type]["rgb"], - self.store[name][type]["dashed"], self.store[name][type]["fill"]) + self.graph_data(ctx, d, gsize, d_height_scale, d_width, self.store[name][dev_type]["rgb"], + self.store[name][dev_type]["dashed"], self.store[name][dev_type]["fill"]) - def graph_data(self, ctx, data, gsize, hscale, swidth, rgb, dashed=False, fill=False): + @staticmethod + def graph_data(ctx, data, gsize, hscale, swidth, rgb, dashed=False, fill=False): i = 0 ctx.set_source_rgba(rgb[0], rgb[1], rgb[2], 1) ctx.move_to(gsize[0][0] + 1, gsize[0][1] - 1) @@ -173,25 +170,20 @@ class HeaterGraph(Gtk.DrawingArea): ctx.set_source_rgb(.5, .5, .5) ctx.move_to(x - round(self.font_size * 1.5), gsize[1][1] + round(self.font_size * 1.5)) - hour = now.hour - min = now.minute - (now.minute % 2) - i * 2 - if min < 0: - hour -= 1 - min = 60 + min - if hour < 0: - hour += 24 + h = now.hour + m = now.minute - (now.minute % 2) - i * 2 + if m < 0: + h -= 1 + m += 60 + if h < 0: + h += 24 ctx.set_font_size(self.font_size) - ctx.show_text("%02d:%02d" % (hour, min)) + ctx.show_text(f"{h:2}:{m:02}") ctx.stroke() - if self.max_length < 600: - i += 1 - else: - i += 2 + i += 1 if self.max_length < 600 else 2 def is_showing(self, device): - if device not in self.store: - return False - return self.store[device]['show'] + return False if device not in self.store else self.store[device]['show'] def set_showing(self, device, show=True): if device not in self.store: diff --git a/ks_includes/widgets/keypad.py b/ks_includes/widgets/keypad.py index 934d1be7..886236d1 100644 --- a/ks_includes/widgets/keypad.py +++ b/ks_includes/widgets/keypad.py @@ -33,16 +33,16 @@ class Keypad(Gtk.Box): ['E', 'numpad_bright'] ] for i in range(len(keys)): - id = 'button_' + str(keys[i][0]) + k_id = f'button_{str(keys[i][0])}' if keys[i][0] == "B": - self.labels[id] = self._gtk.ButtonImage("backspace", None, None, 1) + self.labels[k_id] = self._gtk.ButtonImage("backspace", None, None, 1) elif keys[i][0] == "E": - self.labels[id] = self._gtk.ButtonImage("complete", None, None, 1) + self.labels[k_id] = self._gtk.ButtonImage("complete", None, None, 1) else: - self.labels[id] = Gtk.Button(keys[i][0]) - self.labels[id].connect('clicked', self.update_entry, keys[i][0]) - self.labels[id].get_style_context().add_class(keys[i][1]) - numpad.attach(self.labels[id], i % 3, i/3, 1, 1) + self.labels[k_id] = Gtk.Button(keys[i][0]) + self.labels[k_id].connect('clicked', self.update_entry, keys[i][0]) + self.labels[k_id].get_style_context().add_class(keys[i][1]) + numpad.attach(self.labels[k_id], i % 3, i / 3, 1, 1) self.labels["keypad"] = Gtk.Box(orientation=Gtk.Orientation.VERTICAL) self.labels['entry'] = Gtk.Entry() @@ -66,7 +66,7 @@ class Keypad(Gtk.Box): if digit == 'B': if len(text) < 1: return - self.labels['entry'].set_text(text[0:-1]) + self.labels['entry'].set_text(text[:-1]) elif digit == 'E': try: temp = int(text) @@ -74,7 +74,7 @@ class Keypad(Gtk.Box): temp = 0 self.change_temp(temp) self.labels['entry'].set_text("") + elif len(text) >= 3: + return else: - if len(text) >= 3: - return self.labels['entry'].set_text(text + digit) diff --git a/ks_includes/wifi.py b/ks_includes/wifi.py index c63460a6..f3dadf2e 100644 --- a/ks_includes/wifi.py +++ b/ks_includes/wifi.py @@ -44,17 +44,17 @@ class WifiManager: self.timeout = None self.scan_time = 0 - KS_SOCKET_FILE = "/tmp/.KS_wpa_supplicant" - if os.path.exists(KS_SOCKET_FILE): - os.remove(KS_SOCKET_FILE) + ks_socket_file = "/tmp/.KS_wpa_supplicant" + if os.path.exists(ks_socket_file): + os.remove(ks_socket_file) try: self.soc = socket.socket(socket.AF_UNIX, socket.SOCK_DGRAM) - self.soc.bind(KS_SOCKET_FILE) - self.soc.connect("/var/run/wpa_supplicant/%s" % interface) + self.soc.bind(ks_socket_file) + self.soc.connect(f"/var/run/wpa_supplicant/{interface}") except Exception as e: logging.critical(e, exc_info=True) - logging.error("Error connecting to wifi socket: %s" % interface) + logging.error(f"Error connecting to wifi socket: {interface}") return self.wpa_thread = WpaSocket(self, self.queue, self.callback) @@ -71,73 +71,74 @@ class WifiManager: self._callbacks[name].append(callback) def add_network(self, ssid, psk): - for id in list(self.supplicant_networks): - if self.supplicant_networks[id]['ssid'] == ssid: + for netid in list(self.supplicant_networks): + if self.supplicant_networks[netid]['ssid'] == ssid: # Modify network return # TODO: Add wpa_cli error checking network_id = self.wpa_cli("ADD_NETWORK") commands = [ - 'ENABLE_NETWORK %s' % network_id, + f'ENABLE_NETWORK {network_id}', 'SET_NETWORK %s ssid "%s"' % (network_id, ssid.replace('"', '\"')), 'SET_NETWORK %s psk "%s"' % (network_id, psk.replace('"', '\"')) ] + self.wpa_cli_batch(commands) self.read_wpa_supplicant() - id = None + netid = None for i in list(self.supplicant_networks): if self.supplicant_networks[i]['ssid'] == ssid: - id = i + netid = i break - if id is None: + if netid is None: logging.info("Error adding network") return False self.save_wpa_conf() return True - def callback(self, type, msg): - if type in self._callbacks: - for cb in self._callbacks[type]: + def callback(self, cb_type, msg): + if cb_type in self._callbacks: + for cb in self._callbacks[cb_type]: Gdk.threads_add_idle( GLib.PRIORITY_DEFAULT_IDLE, cb, msg) def connect(self, ssid): - id = None - for netid, net in self.supplicant_networks.items(): + netid = None + for nid, net in self.supplicant_networks.items(): if net['ssid'] == ssid: - id = netid + netid = nid break - if id is None: + if netid is None: logging.info("Wifi network is not defined in wpa_supplicant") return False - logging.info("Attempting to connect to wifi: %s" % id) - self.connecting_info = ["Attempting to connect to %s" % ssid] - self.wpa_cli("SELECT_NETWORK %s" % id) + logging.info(f"Attempting to connect to wifi: {netid}") + self.connecting_info = [f"Attempting to connect to {ssid}"] + self.wpa_cli(f"SELECT_NETWORK {id}") self.save_wpa_conf() def delete_network(self, ssid): - id = None + netid = None for i in list(self.supplicant_networks): if self.supplicant_networks[i]['ssid'] == ssid: - id = i + netid = i break - if id is None: + if netid is None: logging.debug("Unable to find network in wpa_supplicant") return - self.wpa_cli("REMOVE_NETWORK %s" % id) + self.wpa_cli(f"REMOVE_NETWORK {netid}") - for id in list(self.supplicant_networks): - if self.supplicant_networks[id]['ssid'] == ssid: - del self.supplicant_networks[id] + for netid in list(self.supplicant_networks): + if self.supplicant_networks[netid]['ssid'] == ssid: + del self.supplicant_networks[netid] break self.save_wpa_conf() @@ -145,45 +146,39 @@ class WifiManager: def get_connected_ssid(self): return self.connected_ssid - def get_current_wifi(self, interface="wlan0"): + def get_current_wifi(self): con_ssid = os.popen("sudo iwgetid -r").read().strip() con_bssid = os.popen("sudo iwgetid -r -a").read().strip() # wpa_cli status output is unstable use it as backup only status = self.wpa_cli("STATUS").split('\n') - vars = {} + variables = {} for line in status: arr = line.split('=') - vars[arr[0]] = "=".join(arr[1:]) + variables[arr[0]] = "=".join(arr[1:]) prev_ssid = self.connected_ssid if con_ssid != "": self.connected = True self.connected_ssid = con_ssid for ssid, val in self.networks.items(): - if ssid == con_ssid: - self.networks[ssid]['connected'] = True - else: - self.networks[ssid]['connected'] = False + self.networks[ssid]['connected'] = ssid == con_ssid if prev_ssid != self.connected_ssid: for cb in self._callbacks['connected']: Gdk.threads_add_idle( GLib.PRIORITY_DEFAULT_IDLE, cb, self.connected_ssid, prev_ssid) return [con_ssid, con_bssid] - elif "ssid" in vars and "bssid" in vars: + elif "ssid" in variables and "bssid" in variables: self.connected = True - self.connected_ssid = vars['ssid'] + self.connected_ssid = variables['ssid'] for ssid, val in self.networks.items(): - if ssid == vars['ssid']: - self.networks[ssid]['connected'] = True - else: - self.networks[ssid]['connected'] = False + self.networks[ssid]['connected'] = ssid == variables['ssid'] if prev_ssid != self.connected_ssid: for cb in self._callbacks['connected']: Gdk.threads_add_idle( GLib.PRIORITY_DEFAULT_IDLE, cb, self.connected_ssid, prev_ssid) - return [vars['ssid'], vars['bssid']] + return [variables['ssid'], variables['bssid']] else: logging.info("Resetting connected_ssid") self.connected = False @@ -247,7 +242,7 @@ class WifiManager: logging.info("Saving WPA config") self.wpa_cli("SAVE_CONFIG") - def scan_results(self, interface='wlan0'): + def scan_results(self): new_networks = [] deleted_networks = list(self.networks) @@ -259,14 +254,14 @@ class WifiManager: match = re.match("^([a-f0-9:]+)\\s+([0-9]+)\\s+([\\-0-9]+)\\s+(\\S+)\\s+(.+)?", res) if match: net = { - "mac": match.group(1), - "channel": WifiChannels.lookup(match.group(2))[1], + "mac": match[1], + "channel": WifiChannels.lookup(match[2])[1], "connected": False, "configured": False, - "frequency": match.group(2), - "flags": match.group(4), - "signal_level_dBm": match.group(3), - "ssid": match.group(5) + "frequency": match[2], + "flags": match[4], + "signal_level_dBm": match[3], + "ssid": match[5] } if "WPA2" in net['flags']: @@ -292,7 +287,7 @@ class WifiManager: deleted_networks.remove(net) else: new_networks.append(net) - if len(new_networks) > 0 or len(deleted_networks) > 0: + if new_networks or deleted_networks: for cb in self._callbacks['scan_results']: Gdk.threads_add_idle( GLib.PRIORITY_DEFAULT_IDLE, @@ -303,8 +298,7 @@ class WifiManager: self.wpa_thread.skip_command() self.soc.send(command.encode()) if wait is True: - resp = self.queue.get() - return resp + return self.queue.get() def wpa_cli_batch(self, commands): for cmd in commands: @@ -322,7 +316,6 @@ class WpaSocket(Thread): self.wm = wm def run(self): - event = threading.Event() logging.debug("Setting up wifi event loop") while self._stop_loop is False: try: @@ -339,21 +332,18 @@ class WpaSocket(Thread): match = re.match('<3>CTRL-EVENT-DISCONNECTED bssid=(\\S+) reason=3 locally_generated=1', msg) if match: for net in self.wm.networks: - if self.wm.networks[net]['mac'] == match.group(1): + if self.wm.networks[net]['mac'] == match[1]: self.wm.networks[net]['connected'] = False break - elif "Trying to associate" in msg: - self.callback("connecting_status", msg) - elif "CTRL-EVENT-REGDOM-CHANGE" in msg: + elif "Trying to associate" in msg or "CTRL-EVENT-REGDOM-CHANGE" in msg: self.callback("connecting_status", msg) elif "CTRL-EVENT-CONNECTED" in msg: Gdk.threads_add_idle(GLib.PRIORITY_DEFAULT_IDLE, self.wm.get_current_wifi_idle_add) self.callback("connecting_status", msg) + elif self.skip_commands > 0: + self.skip_commands = self.skip_commands - 1 else: - if self.skip_commands > 0: - self.skip_commands = self.skip_commands - 1 - else: - self.queue.put(msg) + self.queue.put(msg) logging.info("Wifi event loop ended") def skip_command(self): diff --git a/panels/base_panel.py b/panels/base_panel.py index 4c461f47..07b6f76b 100644 --- a/panels/base_panel.py +++ b/panels/base_panel.py @@ -1,4 +1,5 @@ # -*- coding: utf-8 -*- +import contextlib import datetime import gi import logging @@ -19,11 +20,11 @@ class BasePanel(ScreenPanel): self.time_update = None self.titlebar_name_type = None self.buttons_showing = { - 'back': not(back), + 'back': not back, 'macros_shortcut': False, 'printer_select': False } - + self.current_extruder = None # Action bar buttons self.control['back'] = self._gtk.ButtonImage('back', None, None, 1) self.control['back'].connect("clicked", self.back) @@ -119,7 +120,7 @@ class BasePanel(ScreenPanel): self.titlebar_name_type = printer_cfg.get("titlebar_name_type", None) else: self.titlebar_name_type = None - logging.info("Titlebar name type: %s", self.titlebar_name_type) + logging.info(f"Titlebar name type: {self.titlebar_name_type}") for child in self.control['temp_box'].get_children(): self.control['temp_box'].remove(child) @@ -133,7 +134,7 @@ class BasePanel(ScreenPanel): if device == "extruder": icon = self._gtk.Image("extruder-0", .5) else: - icon = self._gtk.Image("extruder-%s" % device[8:], .5) + icon = self._gtk.Image(f"extruder-{device[8:]}", .5) else: icon = self._gtk.Image("extruder", .5) elif device.startswith("heater_bed"): @@ -152,10 +153,10 @@ class BasePanel(ScreenPanel): self.labels[device] = Gtk.Label(label="100º") self.labels[device].set_ellipsize(Pango.EllipsizeMode.START) - self.labels[device + '_box'] = Gtk.Box() + self.labels[f'{device}_box'] = Gtk.Box() if icon is not None: - self.labels[device + '_box'].pack_start(icon, False, False, 3) - self.labels[device + '_box'].pack_start(self.labels[device], False, False, 0) + self.labels[f'{device}_box'].pack_start(icon, False, False, 3) + self.labels[f'{device}_box'].pack_start(self.labels[device], False, False, 0) # Limit the number of items according to resolution if self._screen.width <= 480: @@ -168,7 +169,7 @@ class BasePanel(ScreenPanel): n = 0 if self._screen.printer.get_tools(): self.current_extruder = self._screen.printer.get_stat("toolhead", "extruder") - self.control['temp_box'].add(self.labels["%s_box" % self.current_extruder]) + self.control['temp_box'].add(self.labels[f"{self.current_extruder}_box"]) n += 1 if self._screen.printer.has_heated_bed(): @@ -180,18 +181,16 @@ class BasePanel(ScreenPanel): titlebar_items = printer_cfg.get("titlebar_items", "") if titlebar_items is not None: titlebar_items = [str(i.strip()) for i in titlebar_items.split(',')] - logging.info("Titlebar items: %s", titlebar_items) + logging.info(f"Titlebar items: {titlebar_items}") for device in self._screen.printer.get_temp_store_devices(): # Users can fill the bar if they want if n >= nlimit + 1: break - if not (device.startswith("extruder") or device.startswith("heater_bed")): - name = device.split(" ")[1:][0] - else: - name = device + name = device if (device.startswith("extruder") or device.startswith("heater_bed")) \ + else " ".join(device.split(" ")[1:]) for item in titlebar_items: if name == item: - self.control['temp_box'].add(self.labels["%s_box" % device]) + self.control['temp_box'].add(self.labels[f"{device}_box"]) n += 1 break @@ -200,7 +199,7 @@ class BasePanel(ScreenPanel): if n >= nlimit: break if device.startswith("heater_generic"): - self.control['temp_box'].add(self.labels["%s_box" % device]) + self.control['temp_box'].add(self.labels[f"{device}_box"]) n += 1 self.control['temp_box'].show_all() @@ -219,10 +218,9 @@ class BasePanel(ScreenPanel): self._screen.remove_keyboard() - if hasattr(self.current_panel, "back"): - if not self.current_panel.back(): - self._screen._menu_go_back() - else: + if hasattr(self.current_panel, "back") \ + and not self.current_panel.back() \ + or not hasattr(self.current_panel, "back"): self._screen._menu_go_back() def process_update(self, action, data): @@ -237,17 +235,17 @@ class BasePanel(ScreenPanel): name = "" if not (device.startswith("extruder") or device.startswith("heater_bed")): if self.titlebar_name_type == "full": - name = device.split(" ")[1:][0].capitalize().replace("_", " ") + ": " + name = " ".join(device.split(" ")[1:]).capitalize().replace("_", " ") + ": " elif self.titlebar_name_type == "short": - name = device.split(" ")[1:][0][:1].upper() + ": " - self.labels[device].set_label("%s%d°" % (name, round(temp))) + name = " ".join(device.split(" ")[1:])[:1].upper() + ": " + self.labels[device].set_label(f"{name}{int(temp)}°") - if "toolhead" in data and "extruder" in data["toolhead"]: + with contextlib.suppress(KeyError): if data["toolhead"]["extruder"] != self.current_extruder: - self.control['temp_box'].remove(self.labels["%s_box" % self.current_extruder]) + self.control['temp_box'].remove(self.labels[f"{self.current_extruder}_box"]) self.current_extruder = data["toolhead"]["extruder"] - self.control['temp_box'].pack_start(self.labels["%s_box" % self.current_extruder], True, True, 3) - self.control['temp_box'].reorder_child(self.labels["%s_box" % self.current_extruder], 0) + self.control['temp_box'].pack_start(self.labels[f"{self.current_extruder}_box"], True, True, 3) + self.control['temp_box'].reorder_child(self.labels[f"{self.current_extruder}_box"], 0) self.control['temp_box'].show_all() def remove(self, widget): @@ -290,21 +288,21 @@ class BasePanel(ScreenPanel): def set_title(self, title): try: - env = Environment(extensions=["jinja2.ext.i18n"]) + env = Environment(extensions=["jinja2.ext.i18n"], autoescape=True) env.install_gettext_translations(self.lang) j2_temp = env.from_string(title) title = j2_temp.render() except Exception: - logging.debug("Error parsing jinja for title: %s" % title) + logging.debug(f"Error parsing jinja for title: {title}") - self.titlelbl.set_label("%s | %s" % (self._screen.connecting_to_printer, title)) + self.titlelbl.set_label(f"{self._screen.connecting_to_printer} | {title}") def update_time(self): now = datetime.datetime.now() confopt = self._config.get_main_config().getboolean("24htime", True) if now.minute != self.time_min or self.time_format != confopt: if confopt: - self.control['time'].set_text(now.strftime("%H:%M")) + self.control['time'].set_text(f'{now:%H:%M}') else: - self.control['time'].set_text(now.strftime("%I:%M %p")) + self.control['time'].set_text(f'{now:%I:%M %p}') return True diff --git a/panels/bed_level.py b/panels/bed_level.py index 9fee902b..ac9ad5ff 100644 --- a/panels/bed_level.py +++ b/panels/bed_level.py @@ -14,13 +14,19 @@ def create_panel(*args): class BedLevelPanel(ScreenPanel): - x_offset = 0 - y_offset = 0 + def __init__(self, screen, title, back=True, action_bar=True, printer_name=True): + super().__init__(screen, title, back, action_bar, printer_name) + self.response_count = None + self.panel_name = None + self.screw_dict = None + self.screws = None + self.y_cnt = None + self.x_cnt = None + self.x_offset = 0 + self.y_offset = 0 def initialize(self, panel_name): - self.panel_name = panel_name - self.screws = None grid = self._gtk.HomogeneousGrid() screws = [] @@ -33,7 +39,7 @@ class BedLevelPanel(ScreenPanel): if config_section_name is not None: config_section = self._screen.printer.get_config_section(config_section_name) for item in config_section: - logging.debug("Screws section: %s" % config_section[item]) + logging.debug(f"Screws section: {config_section[item]}") result = re.match(r"([\-0-9\.]+)\s*,\s*([\-0-9\.]+)", config_section[item]) if result: screws.append([ @@ -41,12 +47,12 @@ class BedLevelPanel(ScreenPanel): round(float(result.group(2)), 2) ]) - screws = sorted(screws, key=lambda x: (float(x[1]), float(x[0]))) + screws = sorted(screws, key=lambda s: (float(s[1]), float(s[0]))) supported = [4, 6, 8] nscrews = len(screws) if nscrews not in supported: - logging.debug("%d bed_screws not supported: calculating 4 locations", nscrews) + logging.debug(f"{nscrews} bed_screws not supported: calculating 4 locations") xconf = self._screen.printer.get_config_section("stepper_x") yconf = self._screen.printer.get_config_section("stepper_y") x = int(int(xconf['position_max']) / 4) @@ -69,7 +75,7 @@ class BedLevelPanel(ScreenPanel): self.x_offset = float(bltouch['x_offset']) if "y_offset" in bltouch: self.y_offset = float(bltouch['y_offset']) - logging.debug("Bltouch found substracted offset X: %.0f Y: %.0f", self.x_offset, self.y_offset) + logging.debug(f"Bltouch found substracted offset X: {self.x_offset} Y: {self.y_offset}") self._screen.show_popup_message(_("Bltouch found applied offset"), level=1) elif "probe" in self._screen.printer.get_config_section_list(): probe = self._screen.printer.get_config_section("probe") @@ -77,7 +83,7 @@ class BedLevelPanel(ScreenPanel): self.x_offset = float(probe['x_offset']) if "y_offset" in probe: self.y_offset = float(probe['y_offset']) - logging.debug("Probe found substracting offset X: %.0f Y: %.0f", self.x_offset, self.y_offset) + logging.debug(f"Probe found substracting offset X: {self.x_offset} Y: {self.y_offset}") self._screen.show_popup_message(_("Probe found applied offset"), level=1) new_screws = [] for screw in self.screws: @@ -114,7 +120,7 @@ class BedLevelPanel(ScreenPanel): else: lm = rm = None - logging.debug("Using %d-screw locations [x,y] [%dx%d]", len(self.screws), self.x_cnt, self.y_cnt) + logging.debug(f"Using {len(self.screws)}-screw locations [x,y] [{self.x_cnt}x{self.y_cnt}]") self.labels['bl'] = self._gtk.ButtonImage("bed-level-t-l", None, None, 2.5) self.labels['br'] = self._gtk.ButtonImage("bed-level-t-r", None, None, 2.5) @@ -134,7 +140,7 @@ class BedLevelPanel(ScreenPanel): rotation = 0 if 'bed_screws' in self._config.get_config(): rotation = self._config.get_config()['bed_screws'].getint("rotation", 0) - logging.debug("Rotation: %d", rotation) + logging.debug(f"Rotation: {rotation}") if rotation == 90: # fl lm bl # fm bm @@ -271,11 +277,11 @@ class BedLevelPanel(ScreenPanel): def go_to_position(self, widget, position): if self._screen.printer.get_stat("toolhead", "homed_axes") != "xyz": self._screen._ws.klippy.gcode_script(KlippyGcodes.HOME) - logging.debug("Going to position: %s", position) + logging.debug(f"Going to position: {position}") script = [ - "%s" % KlippyGcodes.MOVE_ABSOLUTE, + f"{KlippyGcodes.MOVE_ABSOLUTE}", "G1 Z7 F800\n", - "G1 X%s Y%s F3600\n" % (position[0], position[1]), + f"G1 X{position[0]} Y{position[1]} F3600\n", "G1 Z.1 F300\n" ] @@ -305,7 +311,7 @@ class BedLevelPanel(ScreenPanel): y = self.apply_offset(result.group(3), self.y_offset) for key, value in self.screw_dict.items(): if value and x == value[0] and y == value[1]: - logging.debug("X: %s Y: %s Adjust: %s Pos: %s" % (x, y, result.group(5), key)) + logging.debug(f"X: {x} Y: {y} Adjust: {result.group(5)} Pos: {key}") self.labels[key].set_label(result.group(5)) break self.response_count += 1 @@ -319,13 +325,14 @@ class BedLevelPanel(ScreenPanel): if result and re.search('base', result.group(1)): x = self.apply_offset(result.group(2), self.x_offset) y = self.apply_offset(result.group(3), self.y_offset) - logging.debug("X: %s Y: %s is the reference" % (x, y)) + logging.debug(f"X: {x} Y: {y} is the reference") for key, value in self.screw_dict.items(): if value and x == value[0] and y == value[1]: - logging.debug("X: %s Y: %s Pos: %s" % (x, y, key)) + logging.debug(f"X: {x} Y: {y} Pos: {key}") self.labels[key].set_label(_("Reference")) - def apply_offset(self, pos, offset): + @staticmethod + def apply_offset(pos, offset): return max(0, int(float(pos) - offset)) def screws_tilt_calculate(self, widget): diff --git a/panels/bed_mesh.py b/panels/bed_mesh.py index 4f24345e..6f07be96 100644 --- a/panels/bed_mesh.py +++ b/panels/bed_mesh.py @@ -1,5 +1,6 @@ import gi import logging +import contextlib import numpy as np gi.require_version("Gtk", "3.0") @@ -24,17 +25,19 @@ class BedMeshPanel(ScreenPanel): active_mesh = None graphs = {} - def initialize(self, panel_name): - + def __init__(self, screen, title, back=True, action_bar=True, printer_name=True): + super().__init__(screen, title, back, action_bar, printer_name) + self.profiles = {} self.show_create = False + def initialize(self, panel_name): scroll = self._gtk.ScrolledWindow() # Create a grid for all profiles self.labels['profiles'] = Gtk.Grid() scroll.add(self.labels['profiles']) - addprofile = self._gtk.ButtonImage("increase", " %s" % _("Add bed mesh profile"), + addprofile = self._gtk.ButtonImage("increase", _("Add bed mesh profile"), "color1", .5, Gtk.PositionType.LEFT, False) addprofile.connect("clicked", self.show_create_profile) addprofile.set_size_request(60, 0) @@ -67,7 +70,7 @@ class BedMeshPanel(ScreenPanel): if profile == "": profile = "default" - logging.debug("Activating profile: %s %s" % (self.active_mesh, profile)) + logging.debug(f"Activating profile: {self.active_mesh} {profile}") if profile != self.active_mesh: if profile not in self.profiles: self.add_profile(profile) @@ -87,7 +90,7 @@ class BedMeshPanel(ScreenPanel): frame = Gtk.Frame() name = Gtk.Label() - name.set_markup("%s" % profile) + name.set_markup(f"{profile}") name.set_hexpand(True) name.set_vexpand(True) name.set_halign(Gtk.Align.START) @@ -143,7 +146,7 @@ class BedMeshPanel(ScreenPanel): dev.add(labels) buttons = Gtk.Box(orientation=Gtk.Orientation.HORIZONTAL, spacing=5) - logging.debug("Profile compare: '%s' '%s'" % (self.active_mesh, profile)) + logging.debug(f"Profile compare: '{self.active_mesh}' '{profile}'") if self.active_mesh == profile: buttons.pack_start(refresh, False, False, 0) else: @@ -187,9 +190,9 @@ class BedMeshPanel(ScreenPanel): def create_profile(self, widget): name = self.labels['profile_name'].get_text() if " " in name: - name = '"%s"' % name + name = f'"{name}"' - self._screen._ws.klippy.gcode_script("BED_MESH_PROFILE SAVE=%s" % name) + self._screen._ws.klippy.gcode_script(f"BED_MESH_PROFILE SAVE={name}") self.remove_create() def calibrate_mesh(self, widget): @@ -205,13 +208,12 @@ class BedMeshPanel(ScreenPanel): def load_meshes(self): bm_profiles = self._screen.printer.get_config_section_list("bed_mesh ") - self.profiles = {} for prof in bm_profiles: self.add_profile(prof[9:]) def process_update(self, action, data): if action == "notify_status_update": - if "bed_mesh" in data and "profile_name" in data['bed_mesh']: + with contextlib.suppress(KeyError): if data['bed_mesh']['profile_name'] != self.active_mesh: self.activate_mesh(data['bed_mesh']['profile_name']) @@ -291,25 +293,23 @@ class BedMeshPanel(ScreenPanel): def show_mesh(self, widget, profile): - bm = self._printer.get_config_section("bed_mesh %s" % profile) + bm = self._printer.get_config_section(f"bed_mesh {profile}") if bm is False: - logging.info("Unable to load profile: %s" % profile) + logging.info(f"Unable to load profile: {profile}") return if profile == self.active_mesh: abm = self._printer.get_stat("bed_mesh") if abm is None: - logging.info("Unable to load active mesh: %s" % profile) + logging.info(f"Unable to load active mesh: {profile}") return x_range = [int(abm['mesh_min'][0]), int(abm['mesh_max'][0])] y_range = [int(abm['mesh_min'][1]), int(abm['mesh_max'][1])] minz_mesh = min(min(abm['mesh_matrix'])) maxz_mesh = max(max(abm['mesh_matrix'])) # Do not use a very small zscale, because that could be misleading - if minz_mesh > -0.5: - minz_mesh = -0.5 - if maxz_mesh < 0.5: - maxz_mesh = 0.5 + minz_mesh = min(minz_mesh, -0.5) + maxz_mesh = max(maxz_mesh, 0.5) z_range = [minz_mesh, maxz_mesh] counts = [len(abm['mesh_matrix'][0]), len(abm['mesh_matrix'])] deltas = [(x_range[1] - x_range[0]) / (counts[0] - 1), (y_range[1] - y_range[0]) / (counts[1] - 1)] @@ -351,7 +351,7 @@ class BedMeshPanel(ScreenPanel): box.set_vexpand(True) title = Gtk.Label() - title.set_markup("%s" % profile) + title.set_markup(f"{profile}") title.set_hexpand(True) title.set_halign(Gtk.Align.CENTER) @@ -378,5 +378,6 @@ class BedMeshPanel(ScreenPanel): for css_class in style_ctx.list_classes(): style_ctx.remove_class(css_class) - def _close_dialog(self, widget, response): + @staticmethod + def _close_dialog(widget, response): widget.destroy() diff --git a/panels/console.py b/panels/console.py index 5b2799a6..6bc5f406 100644 --- a/panels/console.py +++ b/panels/console.py @@ -1,5 +1,4 @@ import gi -import logging import time import re @@ -24,12 +23,13 @@ COLORS = { class ConsolePanel(ScreenPanel): - def initialize(self, panel_name): - + def __init__(self, screen, title, back=True, action_bar=True, printer_name=True): + super().__init__(screen, title, back, action_bar, printer_name) self.autoscroll = True self.hidetemps = True - gcodes = self._screen._ws.send_method("server.gcode_store", {"count": 100}, self.gcode_response) + def initialize(self, panel_name): + self._screen._ws.send_method("server.gcode_store", {"count": 100}, self.gcode_response) o1_lbl = Gtk.Label(_("Auto-scroll")) o1_lbl.set_halign(Gtk.Align.END) @@ -108,8 +108,8 @@ class ConsolePanel(ScreenPanel): def clear(self, widget): self.labels['tb'].set_text("") - def add_gcode(self, type, time, message): - if type == "command": + def add_gcode(self, msgtype, msgtime, message): + if msgtype == "command": color = COLORS['command'] elif message.startswith("!!"): color = COLORS['error'] @@ -122,14 +122,14 @@ class ConsolePanel(ScreenPanel): else: color = COLORS['response'] - message = '%s' % (color, message) + message = f'{message}' message = message.replace('\n', '\n ') self.labels['tb'].insert_markup( self.labels['tb'].get_end_iter(), - '\n%s %s' % (COLORS['time'], datetime.fromtimestamp(time).strftime("%H:%M:%S"), - message), -1 + f'\n{datetime.fromtimestamp(msgtime).strftime("%H:%M:%S")} {message}', + -1 ) # Limit the length if self.labels['tb'].get_line_count() > 999: diff --git a/panels/extrude.py b/panels/extrude.py index fff9efdc..5e3aac98 100644 --- a/panels/extrude.py +++ b/panels/extrude.py @@ -13,28 +13,27 @@ def create_panel(*args): class ExtrudePanel(ScreenPanel): - distance = 5 - distances = ['5', '10', '15', '25'] + + def __init__(self, screen, title, back=True, action_bar=True, printer_name=True): + super().__init__(screen, title, back, action_bar, printer_name) + self.current_extruder = self._printer.get_stat("toolhead", "extruder") + self.speeds = ['1', '2', '5', '25'] + self.speed = 1 + self.distances = ['5', '10', '15', '25'] + self.distance = 5 + macros = self._screen.printer.get_gcode_macros() + self.load_filament = any("LOAD_FILAMENT" in macro.upper() for macro in macros) + self.unload_filament = any("UNLOAD_FILAMENT" in macro.upper() for macro in macros) def initialize(self, panel_name): - - self.load_filament = self.unload_filament = False - self.find_gcode_macros() - self.speed = 1 - self.speeds = ['1', '2', '5', '25'] - self.labels['extrude'] = self._gtk.ButtonImage("extrude", _("Extrude"), "color4") self.labels['extrude'].connect("clicked", self.extrude, "+") - if not self.load_filament: - self.labels['load'] = self._gtk.ButtonImage("arrow-down", _("Load")) - else: - self.labels['load'] = self._gtk.ButtonImage("arrow-down", _("Load"), "color3") - self.labels['load'].connect("clicked", self.load_unload, "+", self.load_filament) - if not self.unload_filament: - self.labels['unload'] = self._gtk.ButtonImage("arrow-up", _("Unload")) - else: - self.labels['unload'] = self._gtk.ButtonImage("arrow-up", _("Unload"), "color2") - self.labels['unload'].connect("clicked", self.load_unload, "-", self.unload_filament) + self.labels['load'] = self._gtk.ButtonImage("arrow-down", _("Load"), "color3") + + self.labels['load'].connect("clicked", self.load_unload, "+") + self.labels['unload'] = self._gtk.ButtonImage("arrow-up", _("Unload"), "color2") + + self.labels['unload'].connect("clicked", self.load_unload, "-") self.labels['retract'] = self._gtk.ButtonImage("retract", _("Retract"), "color1") self.labels['retract'].connect("clicked", self.extrude, "-") self.labels['temperature'] = self._gtk.ButtonImage("heat-up", _("Temperature"), "color4") @@ -44,13 +43,12 @@ class ExtrudePanel(ScreenPanel): }) extgrid = self._gtk.HomogeneousGrid() - self.current_extruder = self._printer.get_stat("toolhead", "extruder") limit = 5 i = 0 for extruder in self._printer.get_tools(): if self._printer.extrudercount > 1: - self.labels[extruder] = self._gtk.ButtonImage("extruder-%s" % i, - "T%s" % self._printer.get_tool_number(extruder)) + self.labels[extruder] = self._gtk.ButtonImage(f"extruder-{i}", + f"T{self._printer.get_tool_number(extruder)}") else: self.labels[extruder] = self._gtk.ButtonImage("extruder", "") self.labels[extruder].connect("clicked", self.change_extruder, extruder) @@ -63,11 +61,10 @@ class ExtrudePanel(ScreenPanel): extgrid.attach(self.labels['temperature'], i + 1, 0, 1, 1) distgrid = Gtk.Grid() - j = 0 - for i in self.distances: - self.labels["dist" + str(i)] = self._gtk.ToggleButton(i) - self.labels["dist" + str(i)].connect("clicked", self.change_distance, i) - ctx = self.labels["dist" + str(i)].get_style_context() + for j, i in enumerate(self.distances): + self.labels[f"dist{i}"] = self._gtk.ToggleButton(i) + self.labels[f"dist{i}"].connect("clicked", self.change_distance, int(i)) + ctx = self.labels[f"dist{i}"].get_style_context() if ((self._screen.lang_ltr is True and j == 0) or (self._screen.lang_ltr is False and j == len(self.distances) - 1)): ctx.add_class("distbutton_top") @@ -78,16 +75,14 @@ class ExtrudePanel(ScreenPanel): ctx.add_class("distbutton") if i == "5": ctx.add_class("distbutton_active") - distgrid.attach(self.labels["dist" + str(i)], j, 0, 1, 1) - j += 1 + distgrid.attach(self.labels[f"dist{i}"], j, 0, 1, 1) self.labels["dist5"].set_active(True) speedgrid = Gtk.Grid() - j = 0 - for i in self.speeds: - self.labels["speed" + str(i)] = self._gtk.ToggleButton(_(i)) - self.labels["speed" + str(i)].connect("clicked", self.change_speed, i) - ctx = self.labels["speed" + str(i)].get_style_context() + for j, i in enumerate(self.speeds): + self.labels[f"speed{i}"] = self._gtk.ToggleButton(_(i)) + self.labels[f"speed{i}"].connect("clicked", self.change_speed, int(i)) + ctx = self.labels[f"speed{i}"].get_style_context() if ((self._screen.lang_ltr is True and j == 0) or (self._screen.lang_ltr is False and j == len(self.speeds) - 1)): ctx.add_class("distbutton_top") @@ -98,8 +93,7 @@ class ExtrudePanel(ScreenPanel): ctx.add_class("distbutton") if i == "2": ctx.add_class("distbutton_active") - speedgrid.attach(self.labels["speed" + str(i)], j, 0, 1, 1) - j += 1 + speedgrid.attach(self.labels[f"speed{i}"], j, 0, 1, 1) self.labels["speed2"].set_active(True) distbox = Gtk.Box(orientation=Gtk.Orientation.VERTICAL) @@ -112,8 +106,8 @@ class ExtrudePanel(ScreenPanel): speedbox.add(speedgrid) filament_sensors = self._printer.get_filament_sensors() + sensors = Gtk.Grid() if len(filament_sensors) > 0: - sensors = Gtk.Grid() sensors.set_column_spacing(5) sensors.set_row_spacing(5) sensors.set_halign(Gtk.Align.CENTER) @@ -154,8 +148,7 @@ class ExtrudePanel(ScreenPanel): grid.attach(self.labels['unload'], 2, 2, 2, 1) grid.attach(distbox, 0, 3, 4, 1) grid.attach(speedbox, 0, 4, 4, 1) - if len(filament_sensors) > 0: - grid.attach(sensors, 0, 5, 4, 1) + grid.attach(sensors, 0, 5, 4, 1) else: grid.attach(self.labels['extrude'], 0, 2, 1, 1) grid.attach(self.labels['load'], 1, 2, 1, 1) @@ -163,8 +156,7 @@ class ExtrudePanel(ScreenPanel): grid.attach(self.labels['retract'], 3, 2, 1, 1) grid.attach(distbox, 0, 3, 2, 1) grid.attach(speedbox, 2, 3, 2, 1) - if len(filament_sensors) > 0: - grid.attach(sensors, 0, 4, 4, 1) + grid.attach(sensors, 0, 4, 4, 1) self.content.add(grid) @@ -191,7 +183,7 @@ class ExtrudePanel(ScreenPanel): if 'enabled' in data[x]: self._printer.set_dev_stat(x, "enabled", data[x]['enabled']) self.labels[x]['switch'].set_active(data[x]['enabled']) - logging.info("%s Enabled: %s" % (x, data[x]['enabled'])) + logging.info(f"{x} Enabled: {data[x]['enabled']}") if 'filament_detected' in data[x]: self._printer.set_dev_stat(x, "filament_detected", data[x]['filament_detected']) if data[x]['filament_detected']: @@ -200,84 +192,75 @@ class ExtrudePanel(ScreenPanel): else: self.labels[x]['box'].get_style_context().remove_class("filament_sensor_detected") self.labels[x]['box'].get_style_context().add_class("filament_sensor_empty") - logging.info("%s: Filament detected: %s" % (x, data[x]['filament_detected'])) + logging.info(f"{x}: Filament detected: {data[x]['filament_detected']}") def change_distance(self, widget, distance): if self.distance == distance: return - logging.info("### Distance " + str(distance)) + logging.info(f"### Distance {distance}") - ctx = self.labels["dist" + str(self.distance)].get_style_context() + ctx = self.labels[f"dist{self.distance}"].get_style_context() ctx.remove_class("distbutton_active") self.distance = distance - ctx = self.labels["dist" + self.distance].get_style_context() + ctx = self.labels[f"dist{self.distance}"].get_style_context() ctx.add_class("distbutton_active") for i in self.distances: if i == self.distance: continue - self.labels["dist" + str(i)].set_active(False) + self.labels[f"dist{i}"].set_active(False) def change_extruder(self, widget, extruder): - logging.info("Changing extruder to %s", extruder) + logging.info(f"Changing extruder to {extruder}") for tool in self._printer.get_tools(): self.labels[tool].get_style_context().remove_class("button_active") self.labels[extruder].get_style_context().add_class("button_active") - self._screen._ws.klippy.gcode_script("T%s" % self._printer.get_tool_number(extruder)) + self._screen._ws.klippy.gcode_script(f"T{self._printer.get_tool_number(extruder)}") def change_speed(self, widget, speed): if self.speed == speed: return - logging.info("### Speed " + str(speed)) + logging.info(f"### Speed {speed}") - self.labels["speed" + str(self.speed)].get_style_context().remove_class("distbutton_active") + self.labels[f"speed{self.speed}"].get_style_context().remove_class("distbutton_active") self.speed = speed - self.labels["speed" + self.speed].get_style_context().add_class("distbutton_active") + self.labels[f"speed{self.speed}"].get_style_context().add_class("distbutton_active") for i in self.speeds: if i == self.speed: continue - self.labels["speed" + str(i)].set_active(False) - - def extrude(self, widget, dir): - dist = str(self.distance) if dir == "+" else "-" + str(self.distance) - speed = str(int(self.speed) * 60) - print(KlippyGcodes.extrude(dist, speed)) + self.labels[f"speed{i}"].set_active(False) + def extrude(self, widget, direction): self._screen._ws.klippy.gcode_script(KlippyGcodes.EXTRUDE_REL) - self._screen._ws.klippy.gcode_script(KlippyGcodes.extrude(dist, speed)) + self._screen._ws.klippy.gcode_script(KlippyGcodes.extrude(f"{direction}{self.distance}", f"{self.speed * 60}")) - def load_unload(self, widget, dir, found): - if dir == "-": - if not found: + def load_unload(self, widget, direction): + if direction == "-": + if not self.unload_filament: self._screen.show_popup_message("Macro UNLOAD_FILAMENT not found") else: - self._screen._ws.klippy.gcode_script("UNLOAD_FILAMENT SPEED=" + str(int(self.speed) * 60)) - if dir == "+": - if not found: + self._screen._ws.klippy.gcode_script(f"UNLOAD_FILAMENT SPEED={self.speed * 60}") + if direction == "+": + if not self.load_filament: self._screen.show_popup_message("Macro LOAD_FILAMENT not found") else: - self._screen._ws.klippy.gcode_script("LOAD_FILAMENT SPEED=" + str(int(self.speed) * 60)) - - def find_gcode_macros(self): - macros = self._screen.printer.get_gcode_macros() - for x in macros: - macro = x[12:].strip() - macro = macro.upper() - if macro == "LOAD_FILAMENT": - logging.info("Found %s" % macro) - self.load_filament = True - if macro == "UNLOAD_FILAMENT": - logging.info("Found %s" % macro) - self.unload_filament = True + self._screen._ws.klippy.gcode_script(f"LOAD_FILAMENT SPEED={self.speed * 60}") def enable_disable_fs(self, switch, gparams, name, x): if switch.get_active(): self._printer.set_dev_stat(x, "enabled", True) - self._screen._ws.klippy.gcode_script("SET_FILAMENT_SENSOR SENSOR=" + name + " ENABLE=1") + self._screen._ws.klippy.gcode_script(f"SET_FILAMENT_SENSOR SENSOR={name} ENABLE=1") else: self._printer.set_dev_stat(x, "enabled", False) - self._screen._ws.klippy.gcode_script("SET_FILAMENT_SENSOR SENSOR=" + name + " ENABLE=0") + self._screen._ws.klippy.gcode_script(f"SET_FILAMENT_SENSOR SENSOR={name} ENABLE=0") self.labels[x]['box'].get_style_context().remove_class("filament_sensor_empty") self.labels[x]['box'].get_style_context().remove_class("filament_sensor_detected") + + def update_temp(self, dev, temp, target): + if dev in self.labels and temp is not None: + if target > 0: + self.labels[dev].set_label(f"{temp:.1f}°C\n({target:.0f})") + else: + self.labels[dev].set_label(f"{temp:.1f}°C") diff --git a/panels/fan.py b/panels/fan.py index 109352e9..92c3d61a 100644 --- a/panels/fan.py +++ b/panels/fan.py @@ -16,27 +16,21 @@ CHANGEABLE_FANS = ["fan", "fan_generic"] class FanPanel(ScreenPanel): - fan_speed = {} - user_selecting = False def initialize(self, panel_name): - + self.fan_speed = {} + self.user_selecting = False self.devices = {} - - scroll = self._gtk.ScrolledWindow() - # Create a grid for all devices self.labels['devices'] = Gtk.Grid() - scroll.add(self.labels['devices']) - - # Create a box to contain all of the above - box = Gtk.Box(orientation=Gtk.Orientation.VERTICAL, spacing=0) - box.set_vexpand(True) - box.pack_start(scroll, True, True, 0) + self.labels['devices'].set_valign(Gtk.Align.CENTER) self.load_fans() - self.content.add(box) + scroll = self._gtk.ScrolledWindow() + scroll.add(self.labels['devices']) + + self.content.add(scroll) def process_update(self, action, data): if action != "notify_status_update": @@ -65,19 +59,11 @@ class FanPanel(ScreenPanel): def add_fan(self, fan): - logging.info("Adding fan: %s" % fan) - changeable = False - for x in CHANGEABLE_FANS: - if fan.startswith(x) or fan == x: - changeable = True - break - + logging.info(f"Adding fan: {fan}") + changeable = any(fan.startswith(x) or fan == x for x in CHANGEABLE_FANS) name = Gtk.Label() - if fan == "fan": - fan_name = "Part Fan" - else: - fan_name = " ".join(fan.split(" ")[1:]) - name.set_markup("%s" % fan_name) + fan_name = _("Part Fan") if fan == "fan" else " ".join(fan.split(" ")[1:]) + name.set_markup(f"\n{fan_name}\n") name.set_hexpand(True) name.set_vexpand(True) name.set_halign(Gtk.Align.START) @@ -85,10 +71,7 @@ class FanPanel(ScreenPanel): name.set_line_wrap(True) name.set_line_wrap_mode(Pango.WrapMode.WORD_CHAR) - adj = Gtk.Adjustment(0, 0, 100, 1, 5, 0) fan_col = Gtk.Box(orientation=Gtk.Orientation.HORIZONTAL, spacing=5) - fan_col.set_hexpand(True) - fan_col.set_vexpand(False) stop_btn = self._gtk.ButtonImage("cancel", None, "color1", 1) stop_btn.set_hexpand(False) stop_btn.connect("clicked", self.update_fan_speed, fan, 0) @@ -97,9 +80,9 @@ class FanPanel(ScreenPanel): max_btn.connect("clicked", self.update_fan_speed, fan, 100) speed = float(self._printer.get_fan_speed(fan)) - if changeable is True: + if changeable: speed = round(speed * 100) - scale = Gtk.Scale(orientation=Gtk.Orientation.HORIZONTAL, adjustment=adj) + scale = Gtk.Scale.new_with_range(orientation=Gtk.Orientation.HORIZONTAL, min=0, max=100, step=1) scale.set_value(speed) scale.set_digits(0) scale.set_hexpand(True) @@ -116,9 +99,7 @@ class FanPanel(ScreenPanel): scale.set_hexpand(True) fan_col.pack_start(scale, True, True, 10) - fan_row = Gtk.Box(orientation=Gtk.Orientation.VERTICAL, spacing=5) - fan_row.set_hexpand(True) - fan_row.set_vexpand(False) + fan_row = Gtk.Box(orientation=Gtk.Orientation.VERTICAL) fan_row.add(name) fan_row.add(fan_col) @@ -128,7 +109,6 @@ class FanPanel(ScreenPanel): self.devices[fan] = { "changeable": changeable, - "row": frame, "scale": scale, "speed": speed, } @@ -143,17 +123,20 @@ class FanPanel(ScreenPanel): pos = devices.index(fan) self.labels['devices'].insert_row(pos) - self.labels['devices'].attach(self.devices[fan]['row'], 0, pos, 1, 1) + self.labels['devices'].attach(frame, 0, pos, 1, 1) self.labels['devices'].show_all() def load_fans(self): fans = self._printer.get_fans() for fan in fans: # Support for hiding devices by name - name = " ".join(fan.split(" ")[1:]) if not (fan == "fan") else fan + name = " ".join(fan.split(" ")[1:]) if fan != "fan" else fan if name.startswith("_"): continue self.add_fan(fan) + frame = Gtk.Frame() + frame.set_vexpand(False) + self.labels['devices'].attach(frame, 0, -1, 1, 1) def set_fan_speed(self, widget, event, fan): value = self.devices[fan]['scale'].get_value() @@ -162,7 +145,7 @@ class FanPanel(ScreenPanel): self._screen._ws.klippy.gcode_script(KlippyGcodes.set_fan_speed(value)) else: f = " ".join(fan.split(" ")[1:]) - self._screen._ws.klippy.gcode_script("SET_FAN_SPEED FAN=%s SPEED=%s" % (f, float(value) / 100)) + self._screen._ws.klippy.gcode_script(f"SET_FAN_SPEED FAN={f} SPEED={float(value) / 100}") # Check the speed in case it wasn't applied GLib.timeout_add_seconds(1, self.check_fan_speed, fan) diff --git a/panels/fine_tune.py b/panels/fine_tune.py index f8b74884..cb30d69c 100644 --- a/panels/fine_tune.py +++ b/panels/fine_tune.py @@ -33,16 +33,12 @@ class FineTunePanel(ScreenPanel): bs = print_cfg.get("z_babystep_values", "0.01, 0.05") if re.match(r'^[0-9,\.\s]+$', bs): bs = [str(i.strip()) for i in bs.split(',')] - if len(bs) <= 2: - self.bs_deltas = bs - else: - self.bs_deltas = [bs[0], bs[-1]] + self.bs_deltas = bs if len(bs) <= 2 else [bs[0], bs[-1]] self.bs_delta = self.bs_deltas[0] # babystepping grid bsgrid = Gtk.Grid() - j = 0 - for i in self.bs_deltas: + for j, i in enumerate(self.bs_deltas): self.labels[i] = self._gtk.ToggleButton(i) self.labels[i].connect("clicked", self.change_bs_delta, i) ctx = self.labels[i].get_style_context() @@ -55,13 +51,10 @@ class FineTunePanel(ScreenPanel): if i == self.bs_delta: ctx.add_class("distbutton_active") bsgrid.attach(self.labels[i], j, 0, 1, 1) - j += 1 - # Grid for percentage deltgrid = Gtk.Grid() - j = 0 - for i in self.percent_deltas: - self.labels[i] = self._gtk.ToggleButton("%s%%" % i) + for j, i in enumerate(self.percent_deltas): + self.labels[i] = self._gtk.ToggleButton(f"{i}%") self.labels[i].connect("clicked", self.change_percent_delta, i) ctx = self.labels[i].get_style_context() if j == 0: @@ -73,8 +66,6 @@ class FineTunePanel(ScreenPanel): if i == "1": ctx.add_class("distbutton_active") deltgrid.attach(self.labels[i], j, 0, 1, 1) - j += 1 - self.labels["1"].set_active(True) grid = self._gtk.HomogeneousGrid() @@ -154,36 +145,26 @@ class FineTunePanel(ScreenPanel): if "gcode_move" in data: if "homing_origin" in data["gcode_move"]: - self.labels['zoffset'].set_label(" %.2fmm" % data["gcode_move"]["homing_origin"][2]) + self.labels['zoffset'].set_label(f' {data["gcode_move"]["homing_origin"][2]:.2f}mm') if "extrude_factor" in data["gcode_move"]: self.extrusion = int(round(data["gcode_move"]["extrude_factor"] * 100)) - self.labels['extrudefactor'].set_label(" %3d%%" % self.extrusion) + self.labels['extrudefactor'].set_label(f" {self.extrusion:3}%") if "speed_factor" in data["gcode_move"]: self.speed = int(round(data["gcode_move"]["speed_factor"] * 100)) - self.labels['speedfactor'].set_label(" %3d%%" % self.speed) + self.labels['speedfactor'].set_label(f" {self.speed:3}%") - def change_babystepping(self, widget, dir): - if self._screen.printer.get_stat("toolhead", "homed_axes") != "xyz": - self._screen.show_popup_message("Must home first") - return - - if dir == "+": - gcode = "SET_GCODE_OFFSET Z_ADJUST=%s MOVE=1" % self.bs_delta - elif dir == "-": - gcode = "SET_GCODE_OFFSET Z_ADJUST=-%s MOVE=1" % self.bs_delta - elif dir == "reset": - gcode = "SET_GCODE_OFFSET Z=0 MOVE=1" - else: - gcode = "" - - self._screen._ws.klippy.gcode_script(gcode) + def change_babystepping(self, widget, direction): + if direction == "reset": + self._screen._ws.klippy.gcode_script("SET_GCODE_OFFSET Z=0 MOVE=1") + elif direction in ["+", "-"]: + self._screen._ws.klippy.gcode_script(f"SET_GCODE_OFFSET Z_ADJUST={direction}{self.bs_delta} MOVE=1") def change_bs_delta(self, widget, bs): if self.bs_delta == bs: return - logging.info("### BabyStepping " + str(bs)) + logging.info(f"### BabyStepping {bs}") - ctx = self.labels[str(self.bs_delta)].get_style_context() + ctx = self.labels[f"{self.bs_delta}"].get_style_context() ctx.remove_class("distbutton_active") self.bs_delta = bs @@ -194,38 +175,34 @@ class FineTunePanel(ScreenPanel): continue self.labels[i].set_active(False) - def change_extrusion(self, widget, dir): - if dir == "+": + def change_extrusion(self, widget, direction): + if direction == "+": self.extrusion += int(self.percent_delta) - elif dir == "-": + elif direction == "-": self.extrusion -= int(self.percent_delta) - elif dir == "reset": + elif direction == "reset": self.extrusion = 100 - if self.extrusion < 1: - self.extrusion = 1 - + self.extrusion = max(self.extrusion, 1) self._screen._ws.klippy.gcode_script(KlippyGcodes.set_extrusion_rate(self.extrusion)) - def change_speed(self, widget, dir): - if dir == "+": + def change_speed(self, widget, direction): + if direction == "+": self.speed += int(self.percent_delta) - elif dir == "-": + elif direction == "-": self.speed -= int(self.percent_delta) - elif dir == "reset": + elif direction == "reset": self.speed = 100 - if self.speed < 1: - self.speed = 1 - + self.speed = max(self.speed, 1) self._screen._ws.klippy.gcode_script(KlippyGcodes.set_speed_rate(self.speed)) def change_percent_delta(self, widget, delta): if self.percent_delta == delta: return - logging.info("### Delta " + str(delta)) + logging.info(f"### Delta {delta}") - ctx = self.labels[str(self.percent_delta)].get_style_context() + ctx = self.labels[f"{self.percent_delta}"].get_style_context() ctx.remove_class("distbutton_active") self.percent_delta = delta @@ -234,4 +211,4 @@ class FineTunePanel(ScreenPanel): for i in self.percent_deltas: if i == self.percent_delta: continue - self.labels[str(i)].set_active(False) + self.labels[f"{i}"].set_active(False) diff --git a/panels/gcode_macros.py b/panels/gcode_macros.py index 3844185e..2883a487 100644 --- a/panels/gcode_macros.py +++ b/panels/gcode_macros.py @@ -12,19 +12,22 @@ def create_panel(*args): class MacroPanel(ScreenPanel): - def initialize(self, panel_name): - - self.macros = {} - self.loaded_macros = [] + def __init__(self, screen, title, back=True, action_bar=True, printer_name=True): + super().__init__(screen, title, back, action_bar, printer_name) self.sort_reverse = False - self.menu = ['macros_menu'] - - sort = Gtk.Label(_("Sort:")) - sort.set_hexpand(False) self.sort_lbl = _("Name") self.sort_btn = self._gtk.ButtonImage("arrow-up", self.sort_lbl, "color1", .66, Gtk.PositionType.RIGHT, False) self.sort_btn.connect("clicked", self.change_sort) self.sort_btn.set_hexpand(True) + self.allmacros = {} + self.loaded_macros = [] + self.macros = {} + self.menu = ['macros_menu'] + + def initialize(self, panel_name): + sort = Gtk.Label(_("Sort:")) + sort.set_hexpand(False) + adjust = self._gtk.ButtonImage("settings", None, "color2", 1, Gtk.PositionType.LEFT, False) adjust.connect("clicked", self.load_menu, 'options') adjust.set_hexpand(False) @@ -60,7 +63,7 @@ class MacroPanel(ScreenPanel): return name = Gtk.Label() - name.set_markup("%s" % macro) + name.set_markup(f"{macro}") name.set_hexpand(True) name.set_vexpand(True) name.set_halign(Gtk.Align.START) @@ -118,8 +121,8 @@ class MacroPanel(ScreenPanel): def load_gcode_macros(self): macros = self._screen.printer.get_gcode_macros() - section_name = "displayed_macros %s" % self._screen.connected_printer - logging.info("Macro section name [%s]" % section_name) + section_name = f"displayed_macros {self._screen.connected_printer}" + logging.info(f"Macro section name [{section_name}]") for x in macros: macro = x[12:].strip() @@ -139,7 +142,7 @@ class MacroPanel(ScreenPanel): self.allmacros[macro] = { "name": macro, - "section": "displayed_macros %s" % self._screen.connected_printer, + "section": f"displayed_macros {self._screen.connected_printer}", } for macro in list(self.allmacros): self.add_option('options', self.allmacros, macro, self.allmacros[macro]) @@ -148,7 +151,7 @@ class MacroPanel(ScreenPanel): def add_option(self, boxname, opt_array, opt_name, option): name = Gtk.Label() - name.set_markup("%s" % (option['name'])) + name.set_markup(f"{option['name']}") name.set_hexpand(True) name.set_vexpand(True) name.set_halign(Gtk.Align.START) diff --git a/panels/input_shaper.py b/panels/input_shaper.py index e54ae6e9..1955cb11 100644 --- a/panels/input_shaper.py +++ b/panels/input_shaper.py @@ -21,6 +21,21 @@ SHAPERS = ['zv', 'mzv', 'zvd', 'ei', '2hump_ei', '3hump_ei'] class InputShaperPanel(ScreenPanel): + def __init__(self, screen, title, back=True, action_bar=True, printer_name=True): + super().__init__(screen, title, back, action_bar, printer_name) + self.freq_xy_adj = {} + self.freq_xy_combo = {} + self.calibrate_btn = self._gtk.ButtonImage("move", _('Finding ADXL'), "color1", word_wrap=False) + self.calibrate_btn.connect("clicked", self.on_popover_clicked) + self.calibrate_btn.set_sensitive(False) + self.status = Gtk.Label("") + self.status.set_hexpand(True) + self.status.set_vexpand(False) + self.status.set_halign(Gtk.Align.START) + self.status.set_ellipsize(Pango.EllipsizeMode.END) + self.calibrating_axis = None + self.has_sensor = False + def initialize(self, panel_name): self.has_sensor = False @@ -30,10 +45,6 @@ class InputShaperPanel(ScreenPanel): auto_calibration_label.set_markup('Auto Calibration') auto_calibration_label.set_hexpand(True) - self.calibrate_btn = self._gtk.ButtonImage("move", _('Finding ADXL'), "color1", word_wrap=False) - self.calibrate_btn.connect("clicked", self.on_popover_clicked) - self.calibrate_btn.set_sensitive(False) - auto_grid = Gtk.Grid() auto_grid.attach(auto_calibration_label, 0, 0, 1, 1) auto_grid.attach(self.calibrate_btn, 1, 0, 1, 1) @@ -51,11 +62,9 @@ class InputShaperPanel(ScreenPanel): input_grid.attach(manual_calibration_label, 0, 0, 3, 1) input_grid.attach(disclaimer, 0, 1, 3, 1) - self.freq_xy_adj = {} - self.freq_xy_combo = {} for i, dim_freq in enumerate(XY_FREQ): axis_lbl = Gtk.Label() - axis_lbl.set_markup("{}".format(dim_freq['name'])) + axis_lbl.set_markup(f"{dim_freq['name']}") axis_lbl.set_hexpand(False) axis_lbl.set_vexpand(True) axis_lbl.set_halign(Gtk.Align.START) @@ -81,12 +90,6 @@ class InputShaperPanel(ScreenPanel): input_grid.attach(scale, 1, i + 2, 1, 1) input_grid.attach(self.freq_xy_combo[shaper_slug], 2, i + 2, 1, 1) - self.status = Gtk.Label("") - self.status.set_hexpand(True) - self.status.set_vexpand(False) - self.status.set_halign(Gtk.Align.START) - self.status.set_ellipsize(Pango.EllipsizeMode.END) - box = Gtk.Box(orientation=Gtk.Orientation.VERTICAL) box.add(auto_grid) box.add(input_grid) @@ -134,9 +137,11 @@ class InputShaperPanel(ScreenPanel): shaper_type_y = self.freq_xy_combo['shaper_type_y'].get_active_text() self._screen._ws.klippy.gcode_script( - 'SET_INPUT_SHAPER SHAPER_FREQ_X={} SHAPER_TYPE_X={} SHAPER_FREQ_Y={} SHAPER_TYPE_Y={}'.format( - shaper_freq_x, shaper_type_x, shaper_freq_y, shaper_type_y - ) + f'SET_INPUT_SHAPER ' + f'SHAPER_FREQ_X={shaper_freq_x} ' + f'SHAPER_TYPE_X={shaper_type_x} ' + f'SHAPER_FREQ_Y={shaper_freq_y} ' + f'SHAPER_TYPE_Y={shaper_type_y}' ) def save_config(self): @@ -166,7 +171,7 @@ class InputShaperPanel(ScreenPanel): def process_update(self, action, data): if action == "notify_gcode_response": - self.status.set_text('{}'.format(data.replace('shaper_', '').replace('damping_', ''))) + self.status.set_text(f"{data.replace('shaper_', '').replace('damping_', '')}") data = data.lower() if 'got 0' in data: self.calibrate_btn.set_label(_('Check ADXL Wiring')) @@ -184,11 +189,8 @@ class InputShaperPanel(ScreenPanel): r'?P[0-9.]+)', data).groupdict() self.freq_xy_adj['shaper_freq_' + results['axis']].set_value(float(results['shaper_freq'])) self.freq_xy_combo['shaper_type_' + results['axis']].set_active(SHAPERS.index(results['shaper_type'])) - if self.calibrating_axis == results['axis']: - self.calibrate_btn.set_sensitive(True) - self.calibrate_btn.set_label(_('Calibrated')) - self.save_config() - elif self.calibrating_axis == "both" and results['axis'] == 'y': + if self.calibrating_axis == results['axis'] \ + or (self.calibrating_axis == "both" and results['axis'] == 'y'): self.calibrate_btn.set_sensitive(True) self.calibrate_btn.set_label(_('Calibrated')) self.save_config() diff --git a/panels/job_status.py b/panels/job_status.py index 83cf0b8b..8ae3b80a 100644 --- a/panels/job_status.py +++ b/panels/job_status.py @@ -3,6 +3,7 @@ import gi import logging import os import time +import contextlib gi.require_version("Gtk", "3.0") from gi.repository import GLib, Gtk, Pango @@ -15,17 +16,31 @@ def create_panel(*args): class JobStatusPanel(ScreenPanel): - is_paused = False - filename = state_timeout = prev_pos = prev_gpos = vel_timeout = animation_timeout = close_timeout = None - file_metadata = labels = {} - state = "standby" - timeleft_type = "auto" - progress = zoffset = flowrate = vel = 0 - main_status_displayed = True - velstore = flowstore = [] - def __init__(self, screen, title, back=False): super().__init__(screen, title, False) + self.grid = self._gtk.HomogeneousGrid() + self.grid.set_row_homogeneous(False) + self.pos_z = 0 + self.extrusion = 100 + self.speed = 100 + self.speed_factor = 1 + self.req_speed = 0 + self.f_layer_h = self.layer_h = 1 + self.oheight = 0 + self.current_extruder = self._printer.get_stat("toolhead", "extruder") + # the diameter may change with extruders but is highly unusual + diameter = float(self._printer.get_config_section(self.current_extruder)['filament_diameter']) + self.fila_section = pi * ((diameter / 2) ** 2) + self.buttons = None + self.is_paused = False + self.filename_label = self.filename = self.prev_pos = self.prev_gpos = None + self.state_timeout = self.close_timeout = self.vel_timeout = self.animation_timeout = None + self.file_metadata = self.fans = {} + self.state = "standby" + self.timeleft_type = "auto" + self.progress = self.zoffset = self.flowrate = self.vel = 0 + self.main_status_displayed = True + self.velstore = self.flowstore = [] def initialize(self, panel_name): @@ -56,13 +71,12 @@ class JobStatusPanel(ScreenPanel): self.labels['height_lbl'] = Gtk.Label(_("Height:")) self.labels['layer_lbl'] = Gtk.Label(_("Layer:")) - self.fans = {} for fan in self._printer.get_fans(): # fan_types = ["controller_fan", "fan_generic", "heater_fan"] if fan == "fan": name = " " elif fan.startswith("fan_generic"): - name = fan.split(" ")[1:][0][:1].upper() + ":" + name = " ".join(fan.split(" ")[1:])[:1].upper() + ":" if name.startswith("_"): continue else: @@ -117,8 +131,6 @@ class JobStatusPanel(ScreenPanel): self.labels['info_grid'].attach(self.labels['thumbnail'], 0, 0, 1, 1) self.create_status_grid() - self.grid = self._gtk.HomogeneousGrid() - self.grid.set_row_homogeneous(False) self.grid.attach(overlay, 0, 0, 1, 1) self.grid.attach(fi_box, 1, 0, 3, 1) self.grid.attach(self.labels['info_grid'], 0, 1, 4, 2) @@ -127,26 +139,17 @@ class JobStatusPanel(ScreenPanel): self.content.add(self.grid) self._screen.wake_screen() - self.current_extruder = self._printer.get_stat("toolhead", "extruder") - # the diameter may change with extruders but is highly unusual - diameter = float(self._printer.get_config_section(self.current_extruder)['filament_diameter']) - self.fila_section = pi * ((diameter / 2) ** 2) - def create_status_grid(self, widget=None): - self.main_status_displayed = True self.labels['temp_grid'] = Gtk.Grid() - if self._screen.width <= 480: - nlimit = 2 - else: - nlimit = 3 + nlimit = 2 if self._screen.width <= 480 else 3 n = 0 self.extruder_button = {} if self._screen.printer.get_tools(): for i, extruder in enumerate(self._printer.get_tools()): self.labels[extruder] = Gtk.Label("-") - self.extruder_button[extruder] = self._gtk.ButtonImage("extruder-%s" % i, + self.extruder_button[extruder] = self._gtk.ButtonImage(f"extruder-{i}", None, None, .6, Gtk.PositionType.LEFT) self.extruder_button[extruder].set_label(self.labels[extruder].get_text()) self.extruder_button[extruder].connect("clicked", self.menu_item_clicked, "temperature", @@ -187,10 +190,10 @@ class JobStatusPanel(ScreenPanel): titlebar_items = printer_cfg.get("titlebar_items", "") if titlebar_items is not None: titlebar_items = [str(i.strip()) for i in titlebar_items.split(',')] - logging.info("Titlebar items: %s", titlebar_items) + logging.info(f"Titlebar items: {titlebar_items}") for device in self._screen.printer.get_heaters(): if device.startswith("temperature_sensor"): - name = device.split(" ")[1:][0] + name = " ".join(device.split(" ")[1:]) for item in titlebar_items: if name == item: if extra_item: @@ -395,10 +398,7 @@ class JobStatusPanel(ScreenPanel): elif self._printer.config_section_exists("bltouch"): saved_z_offset = float(self._screen.printer.get_config_section("bltouch")['z_offset']) - if self.zoffset > 0: - sign = "+" - else: - sign = "-" + sign = "+" if self.zoffset > 0 else "-" label = Gtk.Label() if device == "probe": label.set_text(_("Apply %s%.2f offset to Probe?") % (sign, abs(self.zoffset)) @@ -500,7 +500,7 @@ class JobStatusPanel(ScreenPanel): self.buttons[arg].set_sensitive(False) def _callback_metadata(self, newfiles, deletedfiles, modifiedfiles): - if bool(self.file_metadata) is False and self.filename in modifiedfiles: + if not bool(self.file_metadata) and self.filename in modifiedfiles: self.update_file_metadata() self._files.remove_file_callback(self._callback_metadata) @@ -542,24 +542,23 @@ class JobStatusPanel(ScreenPanel): self.update_message() - if "toolhead" in data and "extruder" in data["toolhead"]: - if self.current_extruder is not None and data["toolhead"]["extruder"] != self.current_extruder: + with contextlib.suppress(KeyError): + if data["toolhead"]["extruder"] != self.current_extruder: self.labels['temp_grid'].remove_column(0) self.labels['temp_grid'].insert_column(0) self.current_extruder = data["toolhead"]["extruder"] self.labels['temp_grid'].attach(self.extruder_button[self.current_extruder], 0, 0, 1, 1) self._screen.show_all() - if "max_accel" in data["toolhead"]: - self.labels['max_accel'].set_text("%d mm/s²" % (data["toolhead"]["max_accel"])) - - if "extruder" in data and "pressure_advance" in data['extruder']: - self.labels['advance'].set_text("%.2f" % data['extruder']['pressure_advance']) + with contextlib.suppress(KeyError): + self.labels['max_accel'].set_text(f"{data['toolhead']['max_accel']} mm/s²") + with contextlib.suppress(KeyError): + self.labels['advance'].set_text(f"{data['extruder']['pressure_advance']:.2f}") if "gcode_move" in data: - if "gcode_position" in data["gcode_move"]: - self.labels['pos_x'].set_text("X: %6.2f" % (data["gcode_move"]["gcode_position"][0])) - self.labels['pos_y'].set_text("Y: %6.2f" % (data["gcode_move"]["gcode_position"][1])) - self.labels['pos_z'].set_text("Z: %6.2f" % (data["gcode_move"]["gcode_position"][2])) + with contextlib.suppress(KeyError): + self.labels['pos_x'].set_text(f"X: {data['gcode_move']['gcode_position'][0]:6.2f}") + self.labels['pos_y'].set_text(f"Y: {data['gcode_move']['gcode_position'][1]:6.2f}") + self.labels['pos_z'].set_text(f"Z: {data['gcode_move']['gcode_position'][2]:6.2f}") self.pos_z = data["gcode_move"]["gcode_position"][2] if self.main_status_displayed: self.z_button.set_label(self.labels['pos_z'].get_text()) @@ -574,53 +573,54 @@ class JobStatusPanel(ScreenPanel): vel = array(vel) self.velstore.append(sqrt(vel.dot(vel)) / interval) self.prev_gpos = [pos, now] - if "extrude_factor" in data["gcode_move"]: + with contextlib.suppress(KeyError): self.extrusion = int(round(data["gcode_move"]["extrude_factor"] * 100)) - self.labels['extrude_factor'].set_text("%3d%%" % self.extrusion) + self.labels['extrude_factor'].set_text(f"{self.extrusion:3}%") if self.main_status_displayed: - self.extrusion_button.set_label("%3d%%" % self.extrusion) - if "speed_factor" in data["gcode_move"]: + self.extrusion_button.set_label(f"{self.extrusion:3}%") + with contextlib.suppress(KeyError): self.speed = int(round(data["gcode_move"]["speed_factor"] * 100)) self.speed_factor = float(data["gcode_move"]["speed_factor"]) - self.labels['speed_factor'].set_text("%3d%%" % self.speed) - if "speed" in data["gcode_move"]: + self.labels['speed_factor'].set_text(f"{self.speed:3}%") + with contextlib.suppress(KeyError): self.req_speed = int(round(data["gcode_move"]["speed"] / 60 * self.speed_factor)) - if "homing_origin" in data["gcode_move"]: + with contextlib.suppress(KeyError): self.zoffset = data["gcode_move"]["homing_origin"][2] - self.labels['zoffset'].set_text("%.2f" % self.zoffset) - if "motion_report" in data: - if 'live_position' in data["motion_report"]: - now = time.time() - pos = data["motion_report"]["live_position"] - if self.prev_pos is not None: - interval = (now - self.prev_pos[1]) - # Calculate Flowrate - evelocity = (pos[3] - self.prev_pos[0][3]) / interval - self.flowstore.append(self.fila_section * evelocity) - # Calculate Velocity - vel = [(pos[0] - self.prev_pos[0][0]), - (pos[1] - self.prev_pos[0][1]), - (pos[2] - self.prev_pos[0][2])] - vel = array(vel) - self.velstore.append(sqrt(vel.dot(vel)) / interval) - self.prev_pos = [pos, now] - if "live_velocity" in data["motion_report"]: - self.velstore.append(data["motion_report"]["live_velocity"]) - if "live_extruder_velocity" in data["motion_report"]: - self.flowstore.append(self.flowrate) + self.labels['zoffset'].set_text(f"{self.zoffset:.2f}") + if "motion_report" in data: + with contextlib.suppress(KeyError): + pos = data["motion_report"]["live_position"] + now = time.time() + if self.prev_pos is not None: + interval = (now - self.prev_pos[1]) + # Calculate Flowrate + evelocity = (pos[3] - self.prev_pos[0][3]) / interval + self.flowstore.append(self.fila_section * evelocity) + # Calculate Velocity + vel = [(pos[0] - self.prev_pos[0][0]), + (pos[1] - self.prev_pos[0][1]), + (pos[2] - self.prev_pos[0][2])] + vel = array(vel) + self.velstore.append(sqrt(vel.dot(vel)) / interval) + self.prev_pos = [pos, now] + with contextlib.suppress(KeyError): + self.velstore.append(float(data["motion_report"]["live_velocity"])) + with contextlib.suppress(KeyError): + self.flowstore.append(self.fila_section * float(data["motion_report"]["live_extruder_velocity"])) - for fan in self.fans: - if fan in data and "speed" in data[fan]: - fan_speed = int(round(self._printer.get_fan_speed(fan, data[fan]["speed"]), 2) * 100) - self.fans[fan]['speed'] = ("%3d%%" % fan_speed) fan_label = "" for fan in self.fans: - fan_label += self.fans[fan]['name'] + self.fans[fan]['speed'] + " " - self.labels['fan'].set_text(fan_label[:12]) + with contextlib.suppress(KeyError): + fan_speed = int(round(self._printer.get_fan_speed(fan, data[fan]["speed"]), 2) * 100) + self.fans[fan]['speed'] = f"{fan_speed:3}%" + fan_label += f" {self.fans[fan]['name']}{self.fans[fan]['speed']}" + if fan_label: + self.labels['fan'].set_text(fan_label[:12]) if "layer_height" in self.file_metadata and "object_height" in self.file_metadata: - layer_label = str(1 + round((self.pos_z - self.f_layer_h) / self.layer_h)) - layer_label += " / " + self.labels['total_layers'].get_text() + layer_label = ( + f"{1 + round((self.pos_z - self.f_layer_h) / self.layer_h)} / {self.labels['total_layers'].get_text()}" + ) self.labels['layer'].set_label(layer_label) self.state_check() @@ -634,21 +634,19 @@ class JobStatusPanel(ScreenPanel): else: duration = ps['print_duration'] if 'filament_used' in ps: - fila_used = float(ps['filament_used']) - self.labels['filament_used'].set_text("%.1f m" % (fila_used / 1000)) + self.labels['filament_used'].set_text(f"{float(ps['filament_used']) / 1000:.1f} m") if 'filename' in ps and (ps['filename'] != self.filename): - logging.debug("Changing filename: '%s' to '%s'" % (self.filename, ps['filename'])) + logging.debug(f"Changing filename: '{self.filename}' to '{ps['filename']}'") self.update_filename() else: self.update_percent_complete() - self.update_text("duration", str(self._gtk.formatTimeString(duration))) - self.update_text("time_left", self.calculate_time_left(duration, ps['filament_used'])) + self.update_time_left(duration, ps['filament_used']) if self.main_status_displayed: self.fan_button.set_label(self.labels['fan'].get_text()) - elapsed_label = self.labels['elapsed'].get_text() + " " + self.labels['duration'].get_text() + elapsed_label = f"{self.labels['elapsed'].get_text()} {self.labels['duration'].get_text()}" self.elapsed_button.set_label(elapsed_label) - remaining_label = self.labels['left'].get_text() + " " + self.labels['time_left'].get_text() + remaining_label = f"{self.labels['left'].get_text()} {self.labels['time_left'].get_text()}" self.left_button.set_label(remaining_label) if self.vel_timeout is None: self.vel_timeout = GLib.timeout_add_seconds(1, self.update_velocity) @@ -661,72 +659,57 @@ class JobStatusPanel(ScreenPanel): self.flowrate = (self.flowrate + median(array(self.flowstore))) / 2 self.flowstore = [] - self.labels['flowrate'].set_label("%.1f mm³/s" % self.flowrate) - self.labels['req_speed'].set_text("%d/%d mm/s" % (self.vel, self.req_speed)) + self.labels['flowrate'].set_label(f"{self.flowrate:.1f} mm³/s") + self.labels['req_speed'].set_text(f"{self.vel:.0f}/{self.req_speed:.0f} mm/s") if self.main_status_displayed: - self.speed_button.set_label("%3d%% %5d mm/s" % (self.speed, self.vel)) - self.extrusion_button.set_label("%3d%% %5.1f mm³/s" % (self.extrusion, self.flowrate)) + self.speed_button.set_label(f"{self.speed:3.0f}% {self.vel:5.0f} mm/s") + self.extrusion_button.set_label(f"{self.extrusion:3}% {self.flowrate:5.1f} mm³/s") return True - def calculate_time_left(self, duration=0, filament_used=0): + def update_time_left(self, duration=0, fila_used=0): total_duration = None if self.progress < 1: slicer_time = filament_time = file_time = None timeleft_type = self._config.get_config()['main'].get('print_estimate_method', 'auto') - slicer_correction = (self._config.get_config()['main'].getint('print_estimate_compensation', 100) / 100) - # speed_factor compensation based on empirical testing - spdcomp = sqrt(self.speed_factor) - if "estimated_time" in self.file_metadata: + with contextlib.suppress(KeyError): if self.file_metadata['estimated_time'] > 0: - slicer_time = (self.file_metadata['estimated_time'] * slicer_correction) / spdcomp - if slicer_time < duration: - slicer_time = None - self.update_text("slicer_time", "-") - else: - self.update_text("slicer_time", str(self._gtk.formatTimeString(slicer_time))) + usrcomp = (self._config.get_config()['main'].getint('print_estimate_compensation', 100) / 100) + # speed_factor compensation based on empirical testing + spdcomp = sqrt(self.speed_factor) + slicer_time = (self.file_metadata['estimated_time'] * usrcomp) / spdcomp + self.update_text("slicer_time", self.format_time(slicer_time)) - if "filament_total" in self.file_metadata: - if self.file_metadata['filament_total'] > 0 and filament_used > 0: - if self.file_metadata['filament_total'] > filament_used: - filament_time = duration / (filament_used / self.file_metadata['filament_total']) - if filament_time < duration: - filament_time = None - self.update_text("filament_time", "-") - else: - self.update_text("filament_time", str(self._gtk.formatTimeString(slicer_time))) + with contextlib.suppress(Exception): + if self.file_metadata['filament_total'] > fila_used: + filament_time = duration / (fila_used / self.file_metadata['filament_total']) + self.update_text("filament_time", self.format_time(filament_time)) - if self.progress > 0: + with contextlib.suppress(ZeroDivisionError): file_time = duration / self.progress - self.update_text("file_time", str(self._gtk.formatTimeString(file_time))) - else: - self.update_text("file_time", "-") + self.update_text("file_time", self.format_time(file_time)) - if timeleft_type == "file" and file_time is not None: + if timeleft_type == "file": total_duration = file_time - elif timeleft_type == "filament" and filament_time is not None: + elif timeleft_type == "filament": total_duration = filament_time elif slicer_time is not None: if timeleft_type == "slicer": total_duration = slicer_time + elif filament_time is not None and self.progress > 0.14: + # Weighted arithmetic mean (Slicer is the most accurate) + total_duration = (slicer_time * 3 + filament_time + file_time) / 5 else: - if filament_time is not None and self.progress > 0.14: - # Weighted arithmetic mean (Slicer is the most accurate) - total_duration = (slicer_time * 3 + filament_time + file_time) / 5 - else: - # At the begining file and filament are innacurate - total_duration = slicer_time + # At the begining file and filament are innacurate + total_duration = slicer_time elif file_time is not None: if filament_time is not None: total_duration = (filament_time + file_time) / 2 else: total_duration = file_time - - if total_duration is not None: - self.update_text("est_time", str(self._gtk.formatTimeString(total_duration))) - return str(self._gtk.formatTimeString((total_duration - duration))) - else: - return "-" + self.update_text("duration", self.format_time(duration)) + self.update_text("est_time", self.format_time(total_duration)) + self.update_text("time_left", self.format_time(total_duration - duration)) def state_check(self): ps = self._printer.get_stat("print_stats") @@ -743,42 +726,35 @@ class JobStatusPanel(ScreenPanel): self.progress = 1 self.update_progress() self.set_state("complete") - self._screen.wake_screen() - self.remove_close_timeout() - timeout = self._config.get_main_config().getint("job_complete_timeout", 0) - if timeout != 0: - self.close_timeout = GLib.timeout_add_seconds(timeout, self.close_panel) - return False + return self._add_timeout("job_complete_timeout") elif ps['state'] == "error": logging.debug("Error!") self.set_state("error") - self.labels['status'].set_text("%s" % (_("Error"))) + self.labels['status'].set_text(_("Error")) self._screen.show_popup_message(ps['message']) - self._screen.wake_screen() - self.remove_close_timeout() - timeout = self._config.get_main_config().getint("job_error_timeout", 0) - if timeout != 0: - self.close_timeout = GLib.timeout_add_seconds(timeout, self.close_panel) - return False + return self._add_timeout("job_error_timeout") elif ps['state'] == "cancelled": # Print was cancelled self.set_state("cancelled") - self._screen.wake_screen() - self.remove_close_timeout() - timeout = self._config.get_main_config().getint("job_cancelled_timeout", 0) - if timeout != 0: - self.close_timeout = GLib.timeout_add_seconds(timeout, self.close_panel) - return False + return self._add_timeout("job_cancelled_timeout") elif ps['state'] == "paused": self.set_state("paused") elif ps['state'] == "standby": self.set_state("standby") return True + def _add_timeout(self, job_timeout): + self._screen.wake_screen() + self.remove_close_timeout() + timeout = self._config.get_main_config().getint(job_timeout, 0) + if timeout != 0: + self.close_timeout = GLib.timeout_add_seconds(timeout, self.close_panel) + return False + def set_state(self, state): if self.state != state: - logging.debug("Changing job_status state from '%s' to '%s'" % (self.state, state)) + logging.debug(f"Changing job_status state from '{self.state}' to '{state}'") if state == "paused": self.update_text("status", _("Paused")) elif state == "printing": @@ -868,28 +844,22 @@ class JobStatusPanel(ScreenPanel): def update_file_metadata(self): if self._files.file_metadata_exists(self.filename): self.file_metadata = self._files.get_file_info(self.filename) - logging.info("Update Metadata. File: %s Size: %s" % (self.filename, self.file_metadata['size'])) + logging.info(f"Update Metadata. File: {self.filename} Size: {self.file_metadata['size']}") if "estimated_time" in self.file_metadata and self.timeleft_type == "slicer": - self.update_text("est_time", - str(self._gtk.formatTimeString(self.file_metadata['estimated_time']))) - if "thumbnails" in self.file_metadata: - tmp = self.file_metadata['thumbnails'].copy() - for i in tmp: - i['data'] = "" + self.update_text("est_time", self.format_time(self.file_metadata['estimated_time'])) self.show_file_thumbnail() if "object_height" in self.file_metadata: - self.height = float(self.file_metadata['object_height']) - self.labels['height'].set_label(str(self.height) + " mm") + self.oheight = float(self.file_metadata['object_height']) + self.labels['height'].set_label(f"{self.oheight} mm") if "layer_height" in self.file_metadata: self.layer_h = float(self.file_metadata['layer_height']) if "first_layer_height" in self.file_metadata: self.f_layer_h = float(self.file_metadata['first_layer_height']) else: self.f_layer_h = self.layer_h - self.labels['total_layers'].set_label(str(int((self.height - self.f_layer_h) / self.layer_h) + 1)) + self.labels['total_layers'].set_label(f"{((self.oheight - self.f_layer_h) / self.layer_h) + 1:.0f}") if "filament_total" in self.file_metadata: - filament_total = float(self.file_metadata['filament_total']) / 1000 - self.labels['filament_total'].set_text("%.1f m" % filament_total) + self.labels['filament_total'].set_text(f"{float(self.file_metadata['filament_total']) / 1000:.1f} m") else: self.file_metadata = {} logging.debug("Cannot find file metadata. Listening for updated metadata") @@ -920,20 +890,17 @@ class JobStatusPanel(ScreenPanel): self.labels[label].set_text(text) def update_progress(self): - if self.progress < 1: - self.labels['progress_text'].set_text("%s%%" % (str((int(self.progress * 100))))) - else: - self.labels['progress_text'].set_text("100") + self.labels['progress_text'].set_text(f"{self.progress * 100:.0f}%") def update_message(self): msg = self._printer.get_stat("display_status", "message") if msg is None: msg = " " - self.labels['lcdmessage'].set_text(str(msg)) + self.labels['lcdmessage'].set_text(f"{msg}") def update_temp(self, x, temp, target): if x in self.labels and temp is not None: if target is not None and target > 0: - self.labels[x].set_label("%3d/%3d°" % (temp, target)) + self.labels[x].set_label(f"{int(temp):3}/{int(target):3}°") else: - self.labels[x].set_label("%3d°" % temp) + self.labels[x].set_label(f"{int(temp):3}°") diff --git a/panels/limits.py b/panels/limits.py index 2602938e..3ae52620 100644 --- a/panels/limits.py +++ b/panels/limits.py @@ -12,29 +12,31 @@ def create_panel(*args): class LimitsPanel(ScreenPanel): - values = {} + + def __init__(self, screen, title, back=True, action_bar=True, printer_name=True): + super().__init__(screen, title, back, action_bar, printer_name) + self.limits = {} + self.grid = Gtk.Grid() + self.options = None + self.values = {} def initialize(self, panel_name): - self.limits = {} - scroll = self._gtk.ScrolledWindow() - - # Create a grid for all limits - self.grid = Gtk.Grid() scroll.add(self.grid) conf = self._printer.get_config_section("printer") self.options = [ {"name": _("Max Acceleration"), "units": _("mm/s²"), "option": "max_accel", - "max": self.stn(conf['max_accel'])}, + "max": int(float(conf['max_accel']))}, {"name": _("Max Acceleration to Deceleration"), "units": _("mm/s²"), "option": "max_accel_to_decel", - "max": self.stn(conf['max_accel_to_decel']) if "max_accel_to_decel" in conf else - round(self.stn(conf['max_accel']) / 2)}, + "max": int(float(conf['max_accel_to_decel'])) if "max_accel_to_decel" in conf + else int(float(conf['max_accel']) / 2)}, {"name": _("Max Velocity"), "units": _("mm/s"), "option": "max_velocity", - "max": self.stn(conf["max_velocity"])}, + "max": int(float(conf["max_velocity"]))}, {"name": _("Square Corner Velocity"), "units": _("mm/s"), "option": "square_corner_velocity", - "max": self.stn(conf['square_corner_velocity']) if "square_corner_velocity" in conf else 5} + "max": int(float(conf['square_corner_velocity'])) if "square_corner_velocity" in conf + else 5} ] for opt in self.options: @@ -43,9 +45,6 @@ class LimitsPanel(ScreenPanel): self.content.add(scroll) self.content.show_all() - def stn(self, str): - return int(float(str)) - def process_update(self, action, data): if action != "notify_status_update": return @@ -73,10 +72,10 @@ class LimitsPanel(ScreenPanel): self.limits[option]['scale'].connect("button-release-event", self.set_opt_value, option) def add_option(self, option, optname, units, value): - logging.info("Adding option: %s" % option) + logging.info(f"Adding option: {option}") name = Gtk.Label() - name.set_markup("%s (%s)" % (optname, units)) + name.set_markup(f"{optname} ({units})") name.set_hexpand(True) name.set_vexpand(True) name.set_halign(Gtk.Align.START) @@ -84,15 +83,14 @@ class LimitsPanel(ScreenPanel): name.set_line_wrap(True) name.set_line_wrap_mode(Pango.WrapMode.WORD_CHAR) - adj = Gtk.Adjustment(0, 1, (value * 1.5), 1, 5, 0) - self.values[option] = value - scale = Gtk.Scale(orientation=Gtk.Orientation.HORIZONTAL, adjustment=adj) - scale.set_value(self.values[option]) + scale = Gtk.Scale.new_with_range(orientation=Gtk.Orientation.HORIZONTAL, min=0, max=value * 1.5, step=1) + scale.set_value(value) scale.set_digits(0) scale.set_hexpand(True) scale.set_has_origin(True) scale.get_style_context().add_class("option_slider") scale.connect("button-release-event", self.set_opt_value, option) + self.values[option] = value reset = self._gtk.ButtonImage("refresh", None, "color1") reset.connect("clicked", self.reset_value, option) @@ -129,10 +127,10 @@ class LimitsPanel(ScreenPanel): value = self.limits[opt]['scale'].get_value() if opt == "max_accel": - self._screen._ws.klippy.gcode_script("SET_VELOCITY_LIMIT ACCEL=%s" % value) + self._screen._ws.klippy.gcode_script(f"SET_VELOCITY_LIMIT ACCEL={value}") elif opt == "max_accel_to_decel": - self._screen._ws.klippy.gcode_script("SET_VELOCITY_LIMIT ACCEL_TO_DECEL=%s" % value) + self._screen._ws.klippy.gcode_script(f"SET_VELOCITY_LIMIT ACCEL_TO_DECEL={value}") elif opt == "max_velocity": - self._screen._ws.klippy.gcode_script("SET_VELOCITY_LIMIT VELOCITY=%s" % value) + self._screen._ws.klippy.gcode_script(f"SET_VELOCITY_LIMIT VELOCITY={value}") elif opt == "square_corner_velocity": - self._screen._ws.klippy.gcode_script("SET_VELOCITY_LIMIT SQUARE_CORNER_VELOCITY=%s" % value) + self._screen._ws.klippy.gcode_script(f"SET_VELOCITY_LIMIT SQUARE_CORNER_VELOCITY={value}") diff --git a/panels/main_menu.py b/panels/main_menu.py index 85247b3f..97074db0 100644 --- a/panels/main_menu.py +++ b/panels/main_menu.py @@ -16,26 +16,25 @@ def create_panel(*args): class MainPanel(MenuPanel): def __init__(self, screen, title, back=False): super().__init__(screen, title, False) + self.popover_device = None + self.items = None + self.grid = self._gtk.HomogeneousGrid() + self.grid.set_hexpand(True) + self.grid.set_vexpand(True) self.devices = {} self.graph_update = None self.active_heater = None + self.h = 1 def initialize(self, panel_name, items, extrudercount): - print("### Making MainMenu") - - grid = self._gtk.HomogeneousGrid() - grid.set_hexpand(True) - grid.set_vexpand(True) + logging.info("### Making MainMenu") self.items = items self.create_menu_items() self._gtk.reset_temp_color() - self.grid = Gtk.Grid() - self.grid.set_row_homogeneous(True) - self.grid.set_column_homogeneous(True) - leftpanel = self.create_left_panel() + grid = self._gtk.HomogeneousGrid() grid.attach(leftpanel, 0, 0, 1, 1) if self._screen.vertical_mode: self.labels['menu'] = self.arrangeMenuItems(items, 3, True) @@ -43,9 +42,7 @@ class MainPanel(MenuPanel): else: self.labels['menu'] = self.arrangeMenuItems(items, 2, True) grid.attach(self.labels['menu'], 1, 0, 1, 1) - self.grid = grid - self.content.add(self.grid) self.layout.show_all() @@ -62,7 +59,7 @@ class MainPanel(MenuPanel): def add_device(self, device): - logging.info("Adding device: %s" % device) + logging.info(f"Adding device: {device}") temperature = self._printer.get_dev_stat(device, "temperature") if temperature is None: @@ -77,60 +74,40 @@ class MainPanel(MenuPanel): devname = device if device.startswith("extruder"): - i = 0 - for d in self.devices: - if d.startswith('extruder'): - i += 1 - if self._printer.extrudercount > 1: - image = "extruder-%s" % i - else: - image = "extruder" - class_name = "graph_label_%s" % device - type = "extruder" + i = sum(d.startswith('extruder') for d in self.devices) + image = f"extruder-{i}" if self._printer.extrudercount > 1 else "extruder" + class_name = f"graph_label_{device}" + dev_type = "extruder" elif device == "heater_bed": image = "bed" devname = "Heater Bed" class_name = "graph_label_heater_bed" - type = "bed" + dev_type = "bed" elif device.startswith("heater_generic"): - self.h = 1 - for d in self.devices: - if "heater_generic" in d: - self.h += 1 + self.h = sum("heater_generic" in d for d in self.devices) image = "heater" - class_name = "graph_label_sensor_%s" % self.h - type = "sensor" + class_name = f"graph_label_sensor_{self.h}" + dev_type = "sensor" elif device.startswith("temperature_fan"): - f = 1 - for d in self.devices: - if "temperature_fan" in d: - f += 1 + f = 1 + sum("temperature_fan" in d for d in self.devices) image = "fan" - class_name = "graph_label_fan_%s" % f - type = "fan" + class_name = f"graph_label_fan_{f}" + dev_type = "fan" elif self._config.get_main_config().getboolean("only_heaters", False): return False else: - s = 1 - try: - s += self.h - except Exception: - pass - for d in self.devices: - if "sensor" in d: - s += 1 + self.h += sum("sensor" in d for d in self.devices) image = "heat-up" - class_name = "graph_label_sensor_%s" % s - type = "sensor" + class_name = f"graph_label_sensor_{self.h}" + dev_type = "sensor" - rgb, color = self._gtk.get_temp_color(type) + rgb = self._gtk.get_temp_color(dev_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().replace("_", " "), None, .5, Gtk.PositionType.LEFT, False) name.connect('clicked', self.on_popover_clicked, device) @@ -151,18 +128,11 @@ class MainPanel(MenuPanel): 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")))) - else: - temp.get_child().set_label("%.1f " % temperature) - devices = sorted(self.devices) pos = devices.index(device) + 1 @@ -174,11 +144,11 @@ class MainPanel(MenuPanel): def change_target_temp(self, temp): - MAX_TEMP = int(float(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)) + max_temp = int(float(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:") + f' {max_temp}') return - temp = 0 if temp < 0 else temp + temp = max(temp, 0) if self.active_heater.startswith('extruder'): self._screen._ws.klippy.set_tool_temp(self._printer.get_tool_number(self.active_heater), temp) @@ -189,7 +159,7 @@ class MainPanel(MenuPanel): 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) + logging.info(f"Unknown heater: {self.active_heater}") self._screen.show_popup_message(_("Unknown Heater") + " " + self.active_heater) self._printer.set_dev_stat(self.active_heater, "target", temp) @@ -232,16 +202,14 @@ class MainPanel(MenuPanel): popover.set_position(Gtk.PositionType.BOTTOM) self.labels['popover'] = popover - i = 0 - for d in self._printer.get_temp_store_devices(): - if self.add_device(d): - i += 1 + i = sum(1 for d in self._printer.get_temp_store_devices() if self.add_device(d)) + graph_height = (self._gtk.get_content_height() / 2) - ((i + 2) * 4 * self._gtk.get_font_size()) self.labels['da'].set_size_request(-1, graph_height) return box def graph_show_device(self, widget, show=True): - logging.info("Graph show: %s %s" % (self.popover_device, show)) + logging.info(f"Graph show: {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") @@ -281,12 +249,10 @@ class MainPanel(MenuPanel): if self.labels['da'].is_showing(self.popover_device): pobox.pack_start(self.labels['graph_hide'], True, True, 5) - if self.devices[self.popover_device]['type'] != "sensor": - pobox.pack_start(self.labels['graph_settemp'], True, True, 5) else: pobox.pack_start(self.labels['graph_show'], True, True, 5) - if self.devices[self.popover_device]['type'] != "sensor": - pobox.pack_start(self.labels['graph_settemp'], True, True, 5) + if self.devices[self.popover_device]["can_target"]: + pobox.pack_start(self.labels['graph_settemp'], True, True, 5) def process_update(self, action, data): if action != "notify_status_update": @@ -334,8 +300,7 @@ class MainPanel(MenuPanel): 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))) + if self.devices[device]["can_target"] and target > 0: + self.devices[device]["temp"].get_child().set_label(f"{temp:.1f} / {target:.0f}") else: - self.devices[device]["temp"].get_child().set_label("%.1f " % temp) + self.devices[device]["temp"].get_child().set_label(f"{temp:.1f}") diff --git a/panels/menu.py b/panels/menu.py index 4879b64f..c68dcff9 100644 --- a/panels/menu.py +++ b/panels/menu.py @@ -39,7 +39,7 @@ class MenuPanel(ScreenPanel): else: self.arrangeMenuItems(self.items, 4) - def arrangeMenuItems(self, items, columns, expandLast=False): + def arrangeMenuItems(self, items, columns, expand_last=False): for child in self.grid.get_children(): self.grid.remove(child) @@ -47,7 +47,7 @@ class MenuPanel(ScreenPanel): i = 0 for item in items: key = list(item)[0] - logging.debug("Evaluating item: %s" % key) + logging.debug(f"Evaluating item: {key}") if not self.evaluate_enable(item[key]['enable']): continue @@ -63,7 +63,7 @@ class MenuPanel(ScreenPanel): row = int(i / columns) width = height = 1 - if expandLast is True and i + 1 == length and length % 2 == 1: + if expand_last is True and i + 1 == length and length % 2 == 1: width = 2 self.grid.attach(self.labels[key], col, row, width, height) @@ -76,13 +76,13 @@ class MenuPanel(ScreenPanel): key = list(self.items[i])[0] item = self.items[i][key] - env = Environment(extensions=["jinja2.ext.i18n"]) + env = Environment(extensions=["jinja2.ext.i18n"], autoescape=True) env.install_gettext_translations(self.lang) j2_temp = env.from_string(item['name']) parsed_name = j2_temp.render() b = self._gtk.ButtonImage( - item['icon'], parsed_name, "color" + str((i % 4) + 1) + item['icon'], parsed_name, f"color{(i % 4) + 1}" ) if item['panel'] is not False: b.connect("clicked", self.menu_item_clicked, item['panel'], item) @@ -108,13 +108,12 @@ class MenuPanel(ScreenPanel): self.j2_data = self._printer.get_printer_status_data() try: - logging.debug("Template: '%s'" % enable) - logging.debug("Data: %s" % self.j2_data) - j2_temp = Template(enable) + logging.debug(f"Template: '{enable}'") + j2_temp = Template(enable, autoescape=True) result = j2_temp.render(self.j2_data) if result == 'True': return True return False except Exception: - logging.debug("Error evaluating enable statement: %s", enable) + logging.debug(f"Error evaluating enable statement: {enable}") return False diff --git a/panels/move.py b/panels/move.py index 74825a0b..78eabe81 100644 --- a/panels/move.py +++ b/panels/move.py @@ -20,11 +20,12 @@ class MovePanel(ScreenPanel): distance = 1 distances = ['.1', '.5', '1', '5', '10', '25', '50'] - def initialize(self, panel_name): - + def __init__(self, screen, title, back=True, action_bar=True, printer_name=True): + super().__init__(screen, title, back, action_bar, printer_name) self.settings = {} self.menu = ['move_menu'] + def initialize(self, panel_name): grid = self._gtk.HomogeneousGrid() self.labels['x+'] = self._gtk.ButtonImage("arrow-right", _("X+"), "color1") @@ -92,15 +93,13 @@ class MovePanel(ScreenPanel): grid.attach(self.labels['z_tilt'], 2, 0, 1, 1) elif self._printer.config_section_exists("quad_gantry_level"): grid.attach(self.labels['quad_gantry_level'], 2, 0, 1, 1) + elif "delta" in self._screen.printer.get_config_section("printer")['kinematics']: + grid.attach(self.labels['motors-off'], 2, 0, 1, 1) else: - if "delta" in self._screen.printer.get_config_section("printer")['kinematics']: - grid.attach(self.labels['motors-off'], 2, 0, 1, 1) - else: - grid.attach(self.labels['home-xy'], 2, 0, 1, 1) + grid.attach(self.labels['home-xy'], 2, 0, 1, 1) distgrid = Gtk.Grid() - j = 0 - for i in self.distances: + for j, i in enumerate(self.distances): self.labels[i] = self._gtk.ToggleButton(i) self.labels[i].set_direction(Gtk.TextDirection.LTR) self.labels[i].connect("clicked", self.change_distance, i) @@ -114,8 +113,6 @@ class MovePanel(ScreenPanel): if i == "1": ctx.add_class("distbutton_active") distgrid.attach(self.labels[i], j, 0, 1, 1) - j += 1 - self.labels["1"].set_active(True) self.labels['pos_x'] = Gtk.Label("X: 0") @@ -143,6 +140,7 @@ class MovePanel(ScreenPanel): self.content.add(self.labels['move_menu']) printer_cfg = self._printer.get_config_section("printer") + # The max_velocity parameter is not optional in klipper config. max_velocity = int(float(printer_cfg["max_velocity"])) if "max_z_velocity" in printer_cfg: max_z_velocity = int(float(printer_cfg["max_z_velocity"])) @@ -175,32 +173,32 @@ class MovePanel(ScreenPanel): homed_axes = self._screen.printer.get_stat("toolhead", "homed_axes") if homed_axes == "xyz": if "gcode_move" in data and "gcode_position" in data["gcode_move"]: - self.labels['pos_x'].set_text("X: %.2f" % (data["gcode_move"]["gcode_position"][0])) - self.labels['pos_y'].set_text("Y: %.2f" % (data["gcode_move"]["gcode_position"][1])) - self.labels['pos_z'].set_text("Z: %.2f" % (data["gcode_move"]["gcode_position"][2])) + self.labels['pos_x'].set_text(f"X: {data['gcode_move']['gcode_position'][0]:.2f}") + self.labels['pos_y'].set_text(f"Y: {data['gcode_move']['gcode_position'][1]:.2f}") + self.labels['pos_z'].set_text(f"Z: {data['gcode_move']['gcode_position'][2]:.2f}") else: if "x" in homed_axes: if "gcode_move" in data and "gcode_position" in data["gcode_move"]: - self.labels['pos_x'].set_text("X: %.2f" % (data["gcode_move"]["gcode_position"][0])) + self.labels['pos_x'].set_text(f"X: {data['gcode_move']['gcode_position'][0]:.2f}") else: self.labels['pos_x'].set_text("X: ?") if "y" in homed_axes: if "gcode_move" in data and "gcode_position" in data["gcode_move"]: - self.labels['pos_y'].set_text("Y: %.2f" % (data["gcode_move"]["gcode_position"][1])) + self.labels['pos_y'].set_text(f"Y: {data['gcode_move']['gcode_position'][1]:.2f}") else: self.labels['pos_y'].set_text("Y: ?") if "z" in homed_axes: if "gcode_move" in data and "gcode_position" in data["gcode_move"]: - self.labels['pos_z'].set_text("Z: %.2f" % (data["gcode_move"]["gcode_position"][2])) + self.labels['pos_z'].set_text(f"Z: {data['gcode_move']['gcode_position'][2]:.2f}") else: self.labels['pos_z'].set_text("Z: ?") def change_distance(self, widget, distance): if self.distance == distance: return - logging.info("### Distance " + str(distance)) + logging.info(f"### Distance {distance}") - ctx = self.labels[str(self.distance)].get_style_context() + ctx = self.labels[f"{self.distance}"].get_style_context() ctx.remove_class("distbutton_active") self.distance = distance @@ -209,36 +207,28 @@ class MovePanel(ScreenPanel): for i in self.distances: if i == self.distance: continue - self.labels[str(i)].set_active(False) + self.labels[f"{i}"].set_active(False) - def move(self, widget, axis, dir): - if self._config.get_config()['main'].getboolean("invert_%s" % axis.lower(), False): - dir = "-" if dir == "+" else "+" + def move(self, widget, axis, direction): + if self._config.get_config()['main'].getboolean(f"invert_{axis.lower()}", False): + direction = "-" if direction == "+" else "+" - dist = str(self.distance) if dir == "+" else "-" + str(self.distance) + dist = f"{direction}{self.distance}" config_key = "move_speed_z" if axis == AXIS_Z else "move_speed_xy" - speed = None - printer_cfg = self._config.get_printer_config(self._screen.connected_printer) - - if printer_cfg is not None: - speed = printer_cfg.getint(config_key, None) - + speed = self._config.get_printer_config(self._screen.connected_printer).getint(config_key, None) if speed is None: speed = self._config.get_config()['main'].getint(config_key, 20) - speed = max(1, speed) + speed = 60 * max(1, speed) - self._screen._ws.klippy.gcode_script( - "%s\n%s %s%s F%s%s" % ( - KlippyGcodes.MOVE_RELATIVE, KlippyGcodes.MOVE, axis, dist, speed * 60, - "\nG90" if self._printer.get_stat("gcode_move", "absolute_coordinates") is True else "" - ) - ) + self._screen._ws.klippy.gcode_script(f"{KlippyGcodes.MOVE_RELATIVE}\n{KlippyGcodes.MOVE} {axis}{dist} F{speed}") + if self._printer.get_stat("gcode_move", "absolute_coordinates"): + self._screen._ws.klippy.gcode_script("G90") def add_option(self, boxname, opt_array, opt_name, option): name = Gtk.Label() - name.set_markup("%s" % (option['name'])) + name.set_markup(f"{option['name']}") name.set_hexpand(True) name.set_vexpand(True) name.set_halign(Gtk.Align.START) @@ -266,10 +256,10 @@ class MovePanel(ScreenPanel): dev.add(box) elif option['type'] == "scale": dev.set_orientation(Gtk.Orientation.VERTICAL) - val = int(self._config.get_config().get(option['section'], opt_name, fallback=option['value'])) - adj = Gtk.Adjustment(val, option['range'][0], option['range'][1], option['step'], option['step'] * 5) - scale = Gtk.Scale(orientation=Gtk.Orientation.HORIZONTAL, adjustment=adj) + scale = Gtk.Scale.new_with_range(orientation=Gtk.Orientation.HORIZONTAL, + min=option['range'][0], max=option['range'][1], step=option['step']) scale.set_hexpand(True) + scale.set_value(int(self._config.get_config().get(option['section'], opt_name, fallback=option['value']))) scale.set_digits(0) scale.connect("button-release-event", self.scale_moved, option['section'], opt_name) dev.add(scale) @@ -284,7 +274,6 @@ class MovePanel(ScreenPanel): "row": frame } - opts = sorted(opt_array) opts = sorted(list(opt_array), key=lambda x: opt_array[x]['name']) pos = opts.index(opt_name) diff --git a/panels/network.py b/panels/network.py index 25c354a3..e84396a4 100644 --- a/panels/network.py +++ b/panels/network.py @@ -16,19 +16,22 @@ def create_panel(*args): class NetworkPanel(ScreenPanel): initialized = False - def initialize(self, menu): - + def __init__(self, screen, title, back=True, action_bar=True, printer_name=True): + super().__init__(screen, title, back, action_bar, printer_name) self.show_add = False self.networks = {} + self.interface = None + self.prev_network = None self.update_timeout = None - self.network_interfaces = netifaces.interfaces() - self.wireless_interfaces = [int for int in self.network_interfaces if int.startswith('w')] + self.wireless_interfaces = [iface for iface in self.network_interfaces if iface.startswith('w')] self.wifi = None if len(self.wireless_interfaces) > 0: - logging.info("Found wireless interfaces: %s" % self.wireless_interfaces) + logging.info(f"Found wireless interfaces: {self.wireless_interfaces}") self.wifi = WifiManager(self.wireless_interfaces[0]) + + def initialize(self, menu): grid = self._gtk.HomogeneousGrid() grid.set_hexpand(True) @@ -67,7 +70,7 @@ class NetworkPanel(ScreenPanel): sbox.set_vexpand(False) sbox.add(self.labels['interface']) if ip is not None: - self.labels['ip'].set_text("IP: %s " % ip) + self.labels['ip'].set_text(f"IP: {ip} ") sbox.add(self.labels['ip']) sbox.add(reload_networks) @@ -129,11 +132,7 @@ class NetworkPanel(ScreenPanel): if configured_networks[net]['ssid'] == ssid: network_id = net - if ssid.startswith("\x00"): - display_name = _("Hidden") - else: - display_name = str(ssid) - + display_name = _("Hidden") if ssid.startswith("\x00") else f"{ssid}" netinfo = self.wifi.get_network_info(ssid) connected_ssid = self.wifi.get_connected_ssid() if netinfo is None: @@ -147,7 +146,7 @@ class NetworkPanel(ScreenPanel): display_name += " (" + _("Connected") + ")" name = Gtk.Label("") - name.set_markup("%s" % display_name) + name.set_markup(f"{display_name}") name.set_hexpand(True) name.set_halign(Gtk.Align.START) name.set_line_wrap(True) @@ -225,7 +224,7 @@ class NetworkPanel(ScreenPanel): if result: self.connect_network(widget, ssid, False) else: - self._screen.show_popup_message("Error adding network %s" % ssid) + self._screen.show_popup_message(f"Error adding network {ssid}") def back(self): if self.show_add: @@ -256,7 +255,8 @@ class NetworkPanel(ScreenPanel): del self.labels[i] self.show_add = False - def close_dialog(self, widget, response_id): + @staticmethod + def close_dialog(widget, response_id): widget.destroy() def connected_callback(self, ssid, prev_ssid): @@ -272,7 +272,7 @@ class NetworkPanel(ScreenPanel): snets = self.wifi.get_supplicant_networks() isdef = False - for id, net in snets.items(): + for netid, net in snets.items(): if net['ssid'] == ssid: isdef = True break @@ -309,7 +309,7 @@ class NetworkPanel(ScreenPanel): self.wifi.connect(ssid) def connecting_status_callback(self, msg): - self.labels['connecting_info'].set_text(self.labels['connecting_info'].get_text() + "\n" + msg) + self.labels['connecting_info'].set_text(f"{self.labels['connecting_info'].get_text()}\n{msg}") self.labels['connecting_info'].show_all() def remove_network(self, ssid, show=True): @@ -346,7 +346,7 @@ class NetworkPanel(ScreenPanel): if "add_network" in self.labels: del self.labels['add_network'] - label = self._gtk.Label("%s %s:" % (_("PSK for"), ssid)) + label = self._gtk.Label(_("PSK for") + f' ssid') label.set_hexpand(False) self.labels['network_psk'] = Gtk.Entry() self.labels['network_psk'].set_text('') @@ -385,11 +385,11 @@ class NetworkPanel(ScreenPanel): info = freq = encr = chan = lvl = ipv4 = ipv6 = "" if ssid not in list(self.networks) or ssid not in self.labels['networks']: - logging.info("Unknown SSID %s", ssid) + logging.info(f"Unknown SSID {ssid}") return netinfo = self.wifi.get_network_info(ssid) if netinfo is None: - netinfo = [] + netinfo = {} if "connected" in netinfo: connected = netinfo['connected'] else: @@ -400,10 +400,10 @@ class NetworkPanel(ScreenPanel): hostname = stream.read().strip() ifadd = netifaces.ifaddresses(self.interface) if netifaces.AF_INET in ifadd and len(ifadd[netifaces.AF_INET]) > 0: - ipv4 = "%s: %s " % ("IPv4", ifadd[netifaces.AF_INET][0]['addr']) + ipv4 = f"IPv4: {ifadd[netifaces.AF_INET][0]['addr']} " if netifaces.AF_INET6 in ifadd and len(ifadd[netifaces.AF_INET6]) > 0: - ipv6 = "%s: %s " % ("IPv6", ifadd[netifaces.AF_INET6][0]['addr'].split('%')[0]) - info = "%s: %s\n%s\n%s\n" % (_("Hostname"), hostname, ipv4, ipv6) + ipv6 = f"IPv6: {ifadd[netifaces.AF_INET6][0]['addr'].split('%')[0]} " + info = f'' + _("Hostname") + f': {hostname}\n{ipv4}\n{ipv6}\n' elif "psk" in netinfo: info = _("Password saved") if "encryption" in netinfo: @@ -412,12 +412,11 @@ class NetworkPanel(ScreenPanel): if "frequency" in netinfo: freq = "2.4 GHz" if netinfo['frequency'][0:1] == "2" else "5 Ghz" if "channel" in netinfo: - chan = _("Channel") + " " + netinfo['channel'] + chan = _("Channel") + f' {netinfo["channel"]}' if "signal_level_dBm" in netinfo: - lvl = netinfo['signal_level_dBm'] + " " + _("dBm") + lvl = f'{netinfo["signal_level_dBm"]} ' + _("dBm") - self.labels['networks'][ssid]['info'].set_markup("%s %s %s %s %s" % ( - info, encr, freq, chan, lvl)) + self.labels['networks'][ssid]['info'].set_markup(f"{info} {encr} {freq} {chan} {lvl}") self.labels['networks'][ssid]['info'].show_all() def update_single_network_info(self): @@ -428,11 +427,16 @@ class NetworkPanel(ScreenPanel): ipv4 = "" ipv6 = "" if netifaces.AF_INET in ifadd and len(ifadd[netifaces.AF_INET]) > 0: - ipv4 = "%s: %s " % ("IPv4", ifadd[netifaces.AF_INET][0]['addr']) + ipv4 = f"IPv4: {ifadd[netifaces.AF_INET][0]['addr']} " if netifaces.AF_INET6 in ifadd and len(ifadd[netifaces.AF_INET6]) > 0: - ipv6 = ipv6 = "%s: %s " % ("IPv6", ifadd[netifaces.AF_INET6][0]['addr'].split('%')[0]) - connected = "%s\n\n%s\n%s: %s\n%s\n%s\n" % ( - self.interface, _("Connected"), _("Hostname"), hostname, ipv4, ipv6) + ipv6 = f"IPv6: {ifadd[netifaces.AF_INET6][0]['addr'].split('%')[0]} " + connected = ( + f'{self.interface}\n\n' + f'' + _("Connected") + f'\n' + f'' + _("Hostname") + f': {hostname}\n' + f'{ipv4}\n' + f'{ipv6}\n' + ) self.labels['networkinfo'].set_markup(connected) self.labels['networkinfo'].show_all() diff --git a/panels/power.py b/panels/power.py index 2fce00ab..10c741d4 100644 --- a/panels/power.py +++ b/panels/power.py @@ -36,8 +36,8 @@ class PowerPanel(ScreenPanel): devices = self._screen.printer.get_power_devices() for x in devices: self.devices[x]['switch'].disconnect_by_func(self.on_switch) - self.devices[x]['switch'].set_active(True if self._screen.printer.get_power_device_status(x) == "on" - else False) + self.devices[x]['switch'].set_active(self._screen.printer.get_power_device_status(x) == "on") + self.devices[x]['switch'].connect("notify::active", self.on_switch, x) def add_device(self, device): @@ -45,7 +45,7 @@ class PowerPanel(ScreenPanel): frame.get_style_context().add_class("frame-item") name = Gtk.Label() - name.set_markup("%s" % device) + name.set_markup(f"{device}") name.set_hexpand(True) name.set_vexpand(True) name.set_halign(Gtk.Align.START) @@ -55,7 +55,7 @@ class PowerPanel(ScreenPanel): switch = Gtk.Switch() switch.set_hexpand(False) - switch.set_active(True if self._screen.printer.get_power_device_status(device) == "on" else False) + switch.set_active(self._screen.printer.get_power_device_status(device) == "on") switch.connect("notify::active", self.on_switch, device) switch.set_property("width-request", round(self._gtk.get_font_size() * 7)) switch.set_property("height-request", round(self._gtk.get_font_size() * 3.5)) @@ -89,7 +89,7 @@ class PowerPanel(ScreenPanel): self.add_device(x) def on_switch(self, switch, gparam, device): - logging.debug("Power toggled %s" % device) + logging.debug(f"Power toggled {device}") if switch.get_active(): self._screen._ws.klippy.power_device_on(device) else: @@ -103,5 +103,5 @@ class PowerPanel(ScreenPanel): return device = data['device'] self.devices[device]['switch'].disconnect_by_func(self.on_switch) - self.devices[device]['switch'].set_active(True if data['status'] == "on" else False) + self.devices[device]['switch'].set_active(data['status'] == "on") self.devices[device]['switch'].connect("notify::active", self.on_switch, device) diff --git a/panels/print.py b/panels/print.py index f909b17c..151597b6 100644 --- a/panels/print.py +++ b/panels/print.py @@ -19,40 +19,37 @@ class PrintPanel(ScreenPanel): dir_panels = {} filelist = {'gcodes': {'directories': [], 'files': []}} - def initialize(self, panel_name): - - self.labels['directories'] = {} - self.labels['files'] = {} - self.sort_items = { - "name": _("Name"), - "date": _("Date") - } - self.sort_icon = ["arrow-up", "arrow-down"] - + def __init__(self, screen, title, back=True, action_bar=True, printer_name=True): + super().__init__(screen, title, back, action_bar, printer_name) sortdir = self._config.get_main_config().get("print_sort_dir", "name_asc") sortdir = sortdir.split('_') if sortdir[0] not in ["name", "date"] or sortdir[1] not in ["asc", "desc"]: sortdir = ["name", "asc"] self.sort_current = [sortdir[0], 0 if sortdir[1] == "asc" else 1] # 0 for asc, 1 for desc + self.sort_items = { + "name": _("Name"), + "date": _("Date") + } + self.sort_icon = ["arrow-up", "arrow-down"] + self.scroll = self._gtk.ScrolledWindow() + self.files = {} + self.directories = {} + self.labels['directories'] = {} + self.labels['files'] = {} - scroll = self._gtk.ScrolledWindow() - - sort = Gtk.Label() - sort.set_text(_("Sort by: ")) + def initialize(self, panel_name): + sort = Gtk.Label(_("Sort by: ")) sbox = Gtk.Box(spacing=0) sbox.set_vexpand(False) sbox.add(sort) - i = 1 - for name, val in self.sort_items.items(): - s = self._gtk.ButtonImage(None, val, "color%s" % (i % 4), .66, Gtk.PositionType.RIGHT, False) - if name == sortdir[0]: + for i, (name, val) in enumerate(self.sort_items.items(), start=1): + s = self._gtk.ButtonImage(None, val, f"color{i % 4}", .66, Gtk.PositionType.RIGHT, False) + if name == self.sort_current[0]: s.set_image(self._gtk.Image(self.sort_icon[self.sort_current[1]], .66)) s.connect("clicked", self.change_sort, name) - self.labels['sort_%s' % name] = s + self.labels[f'sort_{name}'] = s sbox.add(s) - i += 1 - - refresh = self._gtk.ButtonImage("refresh", None, None, .5) + refresh = self._gtk.ButtonImage("refresh", None, None, .66) refresh.connect('clicked', self._refresh_files) sbox.add(refresh) sbox.set_hexpand(True) @@ -69,16 +66,13 @@ class PrintPanel(ScreenPanel): box.set_vexpand(True) box.pack_start(sbox, False, False, 0) box.pack_start(pbox, False, False, 0) - box.pack_start(scroll, True, True, 0) + box.pack_start(self.scroll, True, True, 0) self.dir_panels['gcodes'] = Gtk.Grid() - self.files = {} - self.directories = {} GLib.idle_add(self.reload_files) - scroll.add(self.dir_panels['gcodes']) - self.scroll = scroll + self.scroll.add(self.dir_panels['gcodes']) self.content.add(box) self._screen.files.add_file_callback(self._callback) @@ -93,58 +87,13 @@ class PrintPanel(ScreenPanel): self.filelist[parent_dir]['directories'].append(directory) if directory not in self.labels['directories']: - frame = Gtk.Frame() - frame.get_style_context().add_class("frame-item") + self._create_frame(directory) + reverse = self.sort_current[1] != 0 + dirs = sorted( + self.filelist[parent_dir]['directories'], + reverse=reverse, key=lambda item: self.filelist[item]['modified'] + ) if self.sort_current[0] == "date" else sorted(self.filelist[parent_dir]['directories'], reverse=reverse) - name = Gtk.Label() - name.set_markup("%s" % (directory.split("/")[-1])) - name.set_hexpand(True) - name.set_halign(Gtk.Align.START) - name.set_line_wrap(True) - name.set_line_wrap_mode(Pango.WrapMode.WORD_CHAR) - - info = Gtk.Label() - info.set_halign(Gtk.Align.START) - - labels = Gtk.Box(orientation=Gtk.Orientation.VERTICAL) - labels.add(name) - labels.add(info) - labels.set_vexpand(True) - labels.set_valign(Gtk.Align.CENTER) - labels.set_halign(Gtk.Align.START) - - actions = self._gtk.ButtonImage("load", None, "color3") - actions.connect("clicked", self.change_dir, directory) - actions.set_hexpand(False) - actions.set_halign(Gtk.Align.END) - - file = Gtk.Box(orientation=Gtk.Orientation.HORIZONTAL, spacing=5) - file.set_hexpand(True) - file.set_vexpand(False) - - icon = self._gtk.Image("folder", 1) - - file.add(icon) - file.add(labels) - file.add(actions) - frame.add(file) - - self.directories[directory] = frame - - self.labels['directories'][directory] = { - "icon": icon, - "info": info, - "name": name - } - - self.dir_panels[directory] = Gtk.Grid() - - reverse = False if self.sort_current[1] == 0 else True - if self.sort_current[0] == "date": - dirs = sorted(self.filelist[parent_dir]['directories'], reverse=reverse, - key=lambda item: self.filelist[item]['modified']) - else: - dirs = sorted(self.filelist[parent_dir]['directories'], reverse=reverse) pos = dirs.index(directory) self.dir_panels[parent_dir].insert_row(pos) @@ -158,83 +107,36 @@ class PrintPanel(ScreenPanel): if fileinfo is None: return - dir = ("gcodes/%s" % filepath).split('/')[:-1] - directory = '/'.join(dir) + d = f"gcodes/{filepath}".split('/')[:-1] + directory = '/'.join(d) filename = filepath.split('/')[-1] - for i in range(1, len(dir)): - curdir = "/".join(dir[0:i]) - newdir = "/".join(dir[0:i + 1]) + for i in range(1, len(d)): + curdir = "/".join(d[:i]) + newdir = "/".join(d[:i + 1]) if newdir not in self.filelist[curdir]['directories']: self.add_directory(newdir) if filename not in self.filelist[directory]['files']: - for i in range(1, len(dir)): - curdir = "/".join(dir[0:i + 1]) + for i in range(1, len(d)): + curdir = "/".join(d[:i + 1]) if curdir != "gcodes" and fileinfo['modified'] > self.filelist[curdir]['modified']: self.filelist[curdir]['modified'] = fileinfo['modified'] self.labels['directories'][curdir]['info'].set_markup( - "%s: %s" % - (_("Modified"), datetime.fromtimestamp(fileinfo['modified']).strftime("%Y-%m-%d %H:%M"))) + f'' + _("Modified") + + f' {datetime.fromtimestamp(fileinfo["modified"]):%Y-%m-%d %H:%M}' + ) + self.filelist[directory]['files'].append(filename) if filepath not in self.files: - frame = Gtk.Frame() - frame.get_style_context().add_class("frame-item") + self._create_frame_file(filename, filepath) + reverse = self.sort_current[1] != 0 + files = sorted( + self.filelist[directory]['files'], + reverse=reverse, + key=lambda item: self._screen.files.get_file_info(f"{directory}/{item}"[7:])['modified'] + ) if self.sort_current[0] == "date" else sorted(self.filelist[directory]['files'], reverse=reverse) - name = Gtk.Label() - name.set_markup("%s" % (os.path.splitext(filename)[0].replace("_", " "))) - name.set_hexpand(True) - name.set_halign(Gtk.Align.START) - name.set_line_wrap(True) - name.set_line_wrap_mode(Pango.WrapMode.CHAR) - - info = Gtk.Label() - info.set_halign(Gtk.Align.START) - info.set_markup(self.get_file_info_str(filepath)) - labels = Gtk.Box(orientation=Gtk.Orientation.VERTICAL) - labels.add(name) - labels.add(info) - labels.set_vexpand(True) - labels.set_valign(Gtk.Align.CENTER) - labels.set_halign(Gtk.Align.START) - - actions = self._gtk.ButtonImage("print", None, "color3") - actions.connect("clicked", self.confirm_print, filepath) - actions.set_hexpand(False) - actions.set_halign(Gtk.Align.END) - - file = Gtk.Box(orientation=Gtk.Orientation.HORIZONTAL, spacing=5) - file.set_hexpand(True) - file.set_vexpand(False) - - icon = Gtk.Image() - pixbuf = self.get_file_image(filepath, small=True) - if pixbuf is not None: - icon.set_from_pixbuf(pixbuf) - else: - icon = self._gtk.Image("file", 1.6) - - file.add(icon) - file.add(labels) - if os.path.splitext(filename)[1] in [".gcode", ".g", ".gco"]: - file.add(actions) - frame.add(file) - - self.files[filepath] = frame - self.labels['files'][filepath] = { - "icon": icon, - "info": info, - "name": name - } - - reverse = False if self.sort_current[1] == 0 else True - if self.sort_current[0] == "date": - files = sorted( - self.filelist[directory]['files'], reverse=reverse, - key=lambda item: self._screen.files.get_file_info(("%s/%s" % (directory, item))[7:])['modified'] - ) - else: - files = sorted(self.filelist[directory]['files'], reverse=reverse) pos = files.index(filename) pos += len(self.filelist[directory]['directories']) @@ -243,6 +145,103 @@ class PrintPanel(ScreenPanel): if show is True: self.dir_panels[directory].show_all() + def _create_frame(self, directory): + frame = Gtk.Frame() + frame.get_style_context().add_class("frame-item") + + name = Gtk.Label() + name.set_markup(f"{directory.split('/')[-1]}") + name.set_hexpand(True) + name.set_halign(Gtk.Align.START) + name.set_line_wrap(True) + name.set_line_wrap_mode(Pango.WrapMode.WORD_CHAR) + + info = Gtk.Label() + info.set_halign(Gtk.Align.START) + + labels = Gtk.Box(orientation=Gtk.Orientation.VERTICAL) + labels.add(name) + labels.add(info) + labels.set_vexpand(True) + labels.set_valign(Gtk.Align.CENTER) + labels.set_halign(Gtk.Align.START) + + actions = self._gtk.ButtonImage("load", None, "color3") + actions.connect("clicked", self.change_dir, directory) + actions.set_hexpand(False) + actions.set_halign(Gtk.Align.END) + + file = Gtk.Box(orientation=Gtk.Orientation.HORIZONTAL, spacing=5) + file.set_hexpand(True) + file.set_vexpand(False) + + icon = self._gtk.Image("folder", 1) + + file.add(icon) + file.add(labels) + file.add(actions) + frame.add(file) + + self.directories[directory] = frame + + self.labels['directories'][directory] = { + "icon": icon, + "info": info, + "name": name + } + + self.dir_panels[directory] = Gtk.Grid() + + def _create_frame_file(self, filename, filepath): + frame = Gtk.Frame() + frame.get_style_context().add_class("frame-item") + + name = Gtk.Label() + name.set_markup(f'{os.path.splitext(filename)[0].replace("_", " ")}') + name.set_hexpand(True) + name.set_halign(Gtk.Align.START) + name.set_line_wrap(True) + name.set_line_wrap_mode(Pango.WrapMode.CHAR) + + info = Gtk.Label() + info.set_halign(Gtk.Align.START) + info.set_markup(self.get_file_info_str(filepath)) + labels = Gtk.Box(orientation=Gtk.Orientation.VERTICAL) + labels.add(name) + labels.add(info) + labels.set_vexpand(True) + labels.set_valign(Gtk.Align.CENTER) + labels.set_halign(Gtk.Align.START) + + actions = self._gtk.ButtonImage("print", None, "color3") + actions.connect("clicked", self.confirm_print, filepath) + actions.set_hexpand(False) + actions.set_halign(Gtk.Align.END) + + file = Gtk.Box(orientation=Gtk.Orientation.HORIZONTAL, spacing=5) + file.set_hexpand(True) + file.set_vexpand(False) + + icon = Gtk.Image() + pixbuf = self.get_file_image(filepath, small=True) + if pixbuf is not None: + icon.set_from_pixbuf(pixbuf) + else: + icon = self._gtk.Image("file", 1.6) + + file.add(icon) + file.add(labels) + if os.path.splitext(filename)[1] in [".gcode", ".g", ".gco"]: + file.add(actions) + frame.add(file) + + self.files[filepath] = frame + self.labels['files'][filepath] = { + "icon": icon, + "info": info, + "name": name + } + def back(self): if len(self.cur_directory.split('/')) > 1: self.change_dir(None, '/'.join(self.cur_directory.split('/')[:-1])) @@ -252,12 +251,12 @@ class PrintPanel(ScreenPanel): def change_dir(self, widget, directory): if directory not in self.dir_panels: return - logging.debug("Changing dir to %s" % directory) + logging.debug(f"Changing dir to {directory}") for child in self.scroll.get_children(): self.scroll.remove(child) self.cur_directory = directory - self.labels['path'].set_text(" /%s" % self.cur_directory[7:]) + self.labels['path'].set_text(f" /{self.cur_directory[7:]}") self.scroll.add(self.dir_panels[directory]) self.content.show_all() @@ -267,15 +266,15 @@ class PrintPanel(ScreenPanel): self.sort_current[1] = (self.sort_current[1] + 1) % 2 else: oldkey = self.sort_current[0] - logging.info("Changing %s to %s" % ('sort_%s' % oldkey, self.sort_items[self.sort_current[0]])) - self.labels['sort_%s' % oldkey].set_image(None) - self.labels['sort_%s' % oldkey].show_all() + logging.info(f"Changing sort_{oldkey} to {self.sort_items[self.sort_current[0]]}") + self.labels[f'sort_{oldkey}'].set_image(None) + self.labels[f'sort_{oldkey}'].show_all() self.sort_current = [key, 0] - self.labels['sort_%s' % key].set_image(self._gtk.Image(self.sort_icon[self.sort_current[1]], .66)) - self.labels['sort_%s' % key].show() + self.labels[f'sort_{key}'].set_image(self._gtk.Image(self.sort_icon[self.sort_current[1]], .66)) + self.labels[f'sort_{key}'].show() GLib.idle_add(self.reload_files) - self._config.set("main", "print_sort_dir", "%s_%s" % (key, "asc" if self.sort_current[1] == 0 else "desc")) + self._config.set("main", "print_sort_dir", f'{key}_{"asc" if self.sort_current[1] == 0 else "desc"}') self._config.save_user_config_options() def confirm_print(self, widget, filename): @@ -286,7 +285,7 @@ class PrintPanel(ScreenPanel): ] label = Gtk.Label() - label.set_markup("%s\n" % filename) + label.set_markup(f"{filename}\n") label.set_hexpand(True) label.set_halign(Gtk.Align.CENTER) label.set_vexpand(True) @@ -314,16 +313,16 @@ class PrintPanel(ScreenPanel): if response_id == Gtk.ResponseType.CANCEL: return - logging.info("Starting print: %s" % filename) + logging.info(f"Starting print: {filename}") self._screen._ws.klippy.print_start(filename) def delete_file(self, filename): - dir_parts = ("gcodes/%s" % filename).split('/')[:-1] + dir_parts = f"gcodes/{filename}".split('/')[:-1] directory = '/'.join(dir_parts) self.filelist[directory]["files"].pop(self.filelist[directory]["files"].index(filename.split('/')[-1])) i = len(dir_parts) while i > 1: - cur_dir = '/'.join(dir_parts[0:i]) + cur_dir = '/'.join(dir_parts[:i]) if len(self.filelist[cur_dir]['directories']) > 0 or len(self.filelist[cur_dir]['files']) > 0: break par_dir = '/'.join(cur_dir.split('/')[:-1]) @@ -348,47 +347,14 @@ class PrintPanel(ScreenPanel): fileinfo = self._screen.files.get_file_info(filename) if fileinfo is None: return + info = '' + _("Uploaded") + f': {datetime.fromtimestamp(fileinfo["modified"]):%Y-%m-%d %H:%M}\n' - return "%s: %s\n%s: %s\n%s: %s" % ( - _("Uploaded"), - datetime.fromtimestamp(fileinfo['modified']).strftime("%Y-%m-%d %H:%M"), - _("Size"), - self.formatsize(fileinfo['size']), - _("Print Time"), - self.get_print_time(filename) - ) - - def formatsize(self, size): - size = float(size) - suffixes = ["kB", "MB", "GB", "TB", "PB", "EB", "ZB", "YB"] - for i, suffix in enumerate(suffixes, start=2): - unit = 1024 ** i - if size < unit: - return "%.1f %s" % ((1024 * size / unit), suffix) - - def get_print_time(self, filename): - fileinfo = self._screen.files.get_file_info(filename) - if fileinfo is None: - return - + if "size" in fileinfo: + info += _("Size") + f': {self.format_size(fileinfo["size"])}\n' if "estimated_time" in fileinfo: - print_time = fileinfo['estimated_time'] - print_str = "" + info += _("Print Time") + f': {self.format_time(fileinfo["estimated_time"])}' - # Figure out how many days - print_val = int(print_time / 86400) - if print_val > 0: - print_str = "%sd " % print_val - - # Take remainder from days and divide by hours - print_val = int((print_time % 86400) / 3600) - if print_val > 0: - print_str = "%s%sh " % (print_str, print_val) - - print_val = int(((print_time % 86400) % 3600) / 60) - print_str = "%s%sm" % (print_str, print_val) - return print_str - return "Unavailable" + return info def reload_files(self, widget=None): self.filelist = {'gcodes': {'directories': [], 'files': []}} @@ -402,10 +368,10 @@ class PrintPanel(ScreenPanel): def update_file(self, filename): if filename not in self.labels['files']: - logging.debug("Cannot update file, file not in labels: %s" % filename) + logging.debug(f"Cannot update file, file not in labels: {filename}") return - logging.info("Updating file %s" % filename) + logging.info(f"Updating file {filename}") self.labels['files'][filename]['info'].set_markup(self.get_file_info_str(filename)) # Update icon @@ -413,22 +379,22 @@ class PrintPanel(ScreenPanel): if pixbuf is not None: self.labels['files'][filename]['icon'].set_from_pixbuf(pixbuf) - def _callback(self, newfiles, deletedfiles, updatedfiles=[]): - logging.debug("newfiles: %s", newfiles) + def _callback(self, newfiles, deletedfiles, updatedfiles=None): + logging.debug(f"newfiles: {newfiles}") for file in newfiles: self.add_file(file) - logging.debug("deletedfiles: %s", deletedfiles) + logging.debug(f"deletedfiles: {deletedfiles}") for file in deletedfiles: self.delete_file(file) - logging.debug("updatefiles: %s", updatedfiles) - for file in updatedfiles: - self.update_file(file) + if updatedfiles is not None: + logging.debug(f"updatefiles: {updatedfiles}") + for file in updatedfiles: + self.update_file(file) def _refresh_files(self, widget): self._files.refresh_files() def process_update(self, action, data): - if action == "notify_gcode_response": - if "unknown" in data.lower(): - self._screen.show_popup_message("%s" % data) + if action == "notify_gcode_response" and "unknown" in data.lower(): + self._screen.show_popup_message(data) return diff --git a/panels/printer_select.py b/panels/printer_select.py index b5ab1f65..0da426d5 100644 --- a/panels/printer_select.py +++ b/panels/printer_select.py @@ -38,7 +38,7 @@ class PrinterSelect(ScreenPanel): for i, printer in enumerate(printers): name = list(printer)[0] - self.labels[name] = self._gtk.ButtonImage("extruder", name, "color%s" % (1 + i % 4)) + self.labels[name] = self._gtk.ButtonImage("extruder", name, f"color{1 + i % 4}") self.labels[name].connect("clicked", self._screen.connect_printer_widget, name) if self._screen.vertical_mode: row = i % columns diff --git a/panels/retraction.py b/panels/retraction.py index 0afd11da..c9fa8431 100644 --- a/panels/retraction.py +++ b/panels/retraction.py @@ -13,13 +13,16 @@ def create_panel(*args): class FWRetractionPanel(ScreenPanel): - values = {} - list = {} + + def __init__(self, screen, title, back=True, action_bar=True, printer_name=True): + super().__init__(screen, title, back, action_bar, printer_name) + self.options = None + self.grid = Gtk.Grid() + self.values = {} + self.list = {} def initialize(self, panel_name): - self.grid = Gtk.Grid() - conf = self._printer.get_config_section("firmware_retraction") retract_length = float(conf['retract_length']) if 'retract_length' in conf else 0 @@ -83,10 +86,10 @@ class FWRetractionPanel(ScreenPanel): data ) if result: - self.update_option('retract_length', result.group(1)) - self.update_option('retract_speed', result.group(2)) - self.update_option('unretract_extra_length', result.group(3)) - self.update_option('unretract_speed', result.group(4)) + self.update_option('retract_length', result[1]) + self.update_option('retract_speed', result[2]) + self.update_option('unretract_extra_length', result[3]) + self.update_option('unretract_speed', result[4]) def update_option(self, option, value): if option not in self.list: @@ -101,22 +104,19 @@ class FWRetractionPanel(ScreenPanel): self.list[option]['scale'].connect("button-release-event", self.set_opt_value, option) def add_option(self, option, optname, units, value, digits, maxval): - logging.info("Adding option: %s" % option) + logging.info(f"Adding option: {option}") name = Gtk.Label() - name.set_markup("%s (%s)" % (optname, units)) + name.set_markup(f"{optname} ({units})") name.set_hexpand(True) name.set_vexpand(True) name.set_halign(Gtk.Align.START) name.set_valign(Gtk.Align.CENTER) name.set_line_wrap(True) name.set_line_wrap_mode(Pango.WrapMode.WORD_CHAR) - if option in ["retract_speed", "unretract_speed"]: - adj = Gtk.Adjustment(0, 1, maxval, 1, 5, 0) - else: - adj = Gtk.Adjustment(0, 0, maxval, 1, 5, 0) + minimum = 1 if option in ["retract_speed", "unretract_speed"] else 0 self.values[option] = value - scale = Gtk.Scale(orientation=Gtk.Orientation.HORIZONTAL, adjustment=adj) + scale = Gtk.Scale.new_with_range(orientation=Gtk.Orientation.HORIZONTAL, min=minimum, max=maxval, step=1) scale.set_value(self.values[option]) scale.set_digits(digits) scale.set_hexpand(True) @@ -156,10 +156,10 @@ class FWRetractionPanel(ScreenPanel): value = self.list[opt]['scale'].get_value() if opt == "retract_speed": - self._screen._ws.klippy.gcode_script("SET_RETRACTION RETRACT_SPEED=%s" % value) + self._screen._ws.klippy.gcode_script(f"SET_RETRACTION RETRACT_SPEED={value}") elif opt == "retract_length": - self._screen._ws.klippy.gcode_script("SET_RETRACTION RETRACT_LENGTH=%s" % value) + self._screen._ws.klippy.gcode_script(f"SET_RETRACTION RETRACT_LENGTH={value}") elif opt == "unretract_extra_length": - self._screen._ws.klippy.gcode_script("SET_RETRACTION UNRETRACT_EXTRA_LENGTH=%s" % value) + self._screen._ws.klippy.gcode_script(f"SET_RETRACTION UNRETRACT_EXTRA_LENGTH={value}") elif opt == "unretract_speed": - self._screen._ws.klippy.gcode_script("SET_RETRACTION UNRETRACT_SPEED=%s" % value) + self._screen._ws.klippy.gcode_script(f"SET_RETRACTION UNRETRACT_SPEED={value}") diff --git a/panels/settings.py b/panels/settings.py index 936a00ad..b27de0c1 100644 --- a/panels/settings.py +++ b/panels/settings.py @@ -12,10 +12,13 @@ def create_panel(*args): class SettingsPanel(ScreenPanel): + def __init__(self, screen, title, back=True, action_bar=True, printer_name=True): + super().__init__(screen, title, back, action_bar, printer_name) + self.printers = self.settings = {} + self.menu = ['settings_menu'] + def initialize(self, panel_name): - self.settings = {} - self.menu = ['settings_menu'] self.labels['add_printer_button'] = self._gtk.Button(_("Add Printer"), "color1") options = self._config.get_configurable_options().copy() @@ -35,13 +38,12 @@ class SettingsPanel(ScreenPanel): self.labels['printers_menu'] = self._gtk.ScrolledWindow() self.labels['printers'] = Gtk.Grid() self.labels['printers_menu'].add(self.labels['printers']) - self.printers = {} for printer in self._config.get_printers(): - logging.debug("Printer: %s" % printer) + logging.debug(f"Printer: {printer}") pname = list(printer)[0] self.printers[pname] = { "name": pname, - "section": "printer %s" % pname, + "section": f"printer {pname}", "type": "printer", "moonraker_host": printer[pname]['moonraker_host'], "moonraker_port": printer[pname]['moonraker_port'], @@ -68,7 +70,7 @@ class SettingsPanel(ScreenPanel): frame.get_style_context().add_class("frame-item") name = Gtk.Label() - name.set_markup("%s" % (option['name'])) + name.set_markup(f"{option['name']}") name.set_hexpand(True) name.set_vexpand(True) name.set_halign(Gtk.Align.START) @@ -112,28 +114,28 @@ class SettingsPanel(ScreenPanel): dev.add(dropdown) elif option['type'] == "scale": dev.set_orientation(Gtk.Orientation.VERTICAL) - val = int(self._config.get_config().get(option['section'], opt_name, fallback=option['value'])) - adj = Gtk.Adjustment(val, option['range'][0], option['range'][1], option['step'], option['step'] * 5) - scale = Gtk.Scale(orientation=Gtk.Orientation.HORIZONTAL, adjustment=adj) + scale = Gtk.Scale.new_with_range(orientation=Gtk.Orientation.HORIZONTAL, + min=option['range'][0], max=option['range'][1], step=option['step']) scale.set_hexpand(True) + scale.set_value(int(self._config.get_config().get(option['section'], opt_name, fallback=option['value']))) scale.set_digits(0) scale.connect("button-release-event", self.scale_moved, option['section'], opt_name) dev.add(scale) elif option['type'] == "printer": - logging.debug("Option: %s" % option) + logging.debug(f"Option: {option}") box = Gtk.Box() box.set_vexpand(False) label = Gtk.Label() - url = "%s:%s" % (option['moonraker_host'], option['moonraker_port']) - label.set_markup("%s\n%s" % (option['name'], url)) + url = f"{option['moonraker_host']}:{option['moonraker_port']}" + label.set_markup(f"{option['name']}\n{url}") box.add(label) dev.add(box) elif option['type'] == "menu": - open = self._gtk.ButtonImage("settings", None, "color3") - open.connect("clicked", self.load_menu, option['menu']) - open.set_hexpand(False) - open.set_halign(Gtk.Align.END) - dev.add(open) + open_menu = self._gtk.ButtonImage("settings", None, "color3") + open_menu.connect("clicked", self.load_menu, option['menu']) + open_menu.set_hexpand(False) + open_menu.set_halign(Gtk.Align.END) + dev.add(open_menu) frame.add(dev) frame.show_all() @@ -143,7 +145,6 @@ class SettingsPanel(ScreenPanel): "row": frame } - opts = sorted(opt_array) opts = sorted(list(opt_array), key=lambda x: opt_array[x]['name']) pos = opts.index(opt_name) diff --git a/panels/splash_screen.py b/panels/splash_screen.py index 3ec7efff..6ba2e4e3 100644 --- a/panels/splash_screen.py +++ b/panels/splash_screen.py @@ -68,7 +68,7 @@ class SplashScreenPanel(ScreenPanel): self.content.add(main) def update_text(self, text): - self.labels['text'].set_markup("%s" % text) + self.labels['text'].set_markup(f"{text}") self.show_restart_buttons() def clear_action_bar(self): @@ -84,18 +84,16 @@ class SplashScreenPanel(ScreenPanel): if printer_cfg is not None: power_devices = printer_cfg.get("power_devices", "") power_devices = [str(i.strip()) for i in power_devices.split(',')] - logging.info("Associated power devices: %s", power_devices) + logging.info(f"Associated power devices: {power_devices}") self.add_power_button(self._screen.search_power_devices(power_devices)) if self._screen.printer is not None and self._screen.printer.state != "disconnected": self.labels['actions'].add(self.labels['restart']) self.labels['actions'].add(self.labels['firmware_restart']) - self.labels['actions'].add(self.labels['menu']) else: self.labels['actions'].add(self.labels['restart_system']) self.labels['actions'].add(self.labels['shutdown']) - self.labels['actions'].add(self.labels['menu']) - + self.labels['actions'].add(self.labels['menu']) self.labels['actions'].show_all() def add_power_button(self, powerdevs): diff --git a/panels/system.py b/panels/system.py index c2c89fe3..9154321f 100644 --- a/panels/system.py +++ b/panels/system.py @@ -2,7 +2,7 @@ import gi import logging gi.require_version("Gtk", "3.0") -from gi.repository import Gdk, Gtk, Pango +from gi.repository import Gtk, Pango from datetime import datetime from ks_includes.screen_panel import ScreenPanel @@ -16,16 +16,22 @@ ALLOWED_SERVICES = ["KlipperScreen", "MoonCord", "klipper", "moonraker"] class SystemPanel(ScreenPanel): + def __init__(self, screen, title, back=True, action_bar=True, printer_name=True): + super().__init__(screen, title, back, action_bar, printer_name) + self.update_status = None + self.update_dialog = None + self.update_prog = None + def initialize(self, panel_name): grid = self._gtk.HomogeneousGrid() grid.set_row_homogeneous(False) - update_all = self._gtk.ButtonImage('refresh', "\n".join(_('Full\nUpdate').split(' ')), 'color1') + update_all = self._gtk.ButtonImage('refresh', _('Full\nUpdate'), 'color1') update_all.connect("clicked", self.show_update_info, "full") update_all.set_vexpand(False) - firmrestart = self._gtk.ButtonImage('refresh', "\n".join(_('Firmware\nRestart').split(' ')), 'color2') - firmrestart.connect("clicked", self.restart_klippy, "firmware") + firmrestart = self._gtk.ButtonImage('refresh', _('Firmware\nRestart'), 'color2') + firmrestart.connect("clicked", self._screen._ws.klippy.restart_firmware) firmrestart.set_vexpand(False) reboot = self._gtk.ButtonImage('refresh', _('System\nRestart'), 'color3') @@ -38,12 +44,11 @@ class SystemPanel(ScreenPanel): shutdown.set_vexpand(False) scroll = self._gtk.ScrolledWindow() - scroll.set_policy(Gtk.PolicyType.NEVER, Gtk.PolicyType.AUTOMATIC) infogrid = Gtk.Grid() infogrid.get_style_context().add_class("system-program-grid") update_resp = self._screen.apiclient.send_request("machine/update/status") - self.update_status = False + self.update_status = None if not update_resp: logging.info("No update manager configured") @@ -57,17 +62,17 @@ class SystemPanel(ScreenPanel): self.labels[prog].set_hexpand(True) self.labels[prog].set_halign(Gtk.Align.START) - self.labels["%s_status" % prog] = self._gtk.Button() - self.labels["%s_status" % prog].set_hexpand(False) - self.labels["%s_status" % prog].connect("clicked", self.show_update_info, prog) + self.labels[f"{prog}_status"] = self._gtk.Button() + self.labels[f"{prog}_status"].set_hexpand(False) + self.labels[f"{prog}_status"].connect("clicked", self.show_update_info, prog) if prog in ALLOWED_SERVICES: - self.labels["%s_restart" % prog] = self._gtk.ButtonImage("refresh", None, None, .7, .7) - self.labels["%s_restart" % prog].connect("clicked", self.restart, prog) - infogrid.attach(self.labels["%s_restart" % prog], 0, i, 1, 1) + self.labels[f"{prog}_restart"] = self._gtk.ButtonImage("refresh", None, None, .7, .7) + self.labels[f"{prog}_restart"].connect("clicked", self.restart, prog) + infogrid.attach(self.labels[f"{prog}_restart"], 0, i, 1, 1) - infogrid.attach(self.labels["%s_status" % prog], 2, i, 1, 1) - logging.info("Updating program: %s " % prog) + infogrid.attach(self.labels[f"{prog}_status"], 2, i, 1, 1) + logging.info(f"Updating program: {prog} ") self.update_program_info(prog) infogrid.attach(self.labels[prog], 1, i, 1, 1) @@ -86,9 +91,6 @@ class SystemPanel(ScreenPanel): def activate(self): self.get_updates() - def destroy_widget(self, widget, response_id): - widget.destroy() - def finish_updating(self, widget, response_id): widget.destroy() self._screen.set_updating(False) @@ -107,15 +109,12 @@ class SystemPanel(ScreenPanel): def process_update(self, action, data): if action == "notify_update_response": - logging.info("Update: %s" % data) + logging.info(f"Update: {data}") if 'application' in data: - self.labels['update_progress'].set_text(self.labels['update_progress'].get_text().strip() + "\n" + - data['message'] + "\n") - self.labels['update_progress'].set_ellipsize(Pango.EllipsizeMode.END) - adjustment = self.labels['update_scroll'].get_vadjustment() - adjustment.set_value(adjustment.get_upper() - adjustment.get_page_size()) - adjustment = self.labels['update_scroll'].show_all() - + self.labels['update_progress'].set_text( + f"{self.labels['update_progress'].get_text().strip()}\n" + f"{data['message']}\n" + ) if data['complete']: self.update_dialog.set_response_sensitive(Gtk.ResponseType.CANCEL, True) @@ -123,7 +122,7 @@ class SystemPanel(ScreenPanel): if program not in ALLOWED_SERVICES: return - logging.info("Restarting service: %s" % program) + logging.info(f"Restarting service: {program}") self._screen._ws.send_method("machine.services.restart", {"service": program}) def show_update_info(self, widget, program): @@ -133,15 +132,9 @@ class SystemPanel(ScreenPanel): if program in self.update_status['version_info']: info = self.update_status['version_info'][program] else: - info = {"full"} + info = {"full": True} - 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_events(Gdk.EventMask.TOUCH_MASK) - scroll.add_events(Gdk.EventMask.BUTTON_PRESS_MASK) + scroll = self._gtk.ScrolledWindow() grid = Gtk.Grid() grid.set_column_homogeneous(True) @@ -172,7 +165,7 @@ class SystemPanel(ScreenPanel): ":\n") grid.attach(label, 0, i, 1, 1) - i = i + 1 + i += 1 date = "" for c in info['commits_behind']: ndate = datetime.fromtimestamp(int(c['date'])).strftime("%b %d") @@ -180,51 +173,52 @@ class SystemPanel(ScreenPanel): date = ndate label = Gtk.Label() label.set_line_wrap(True) - label.set_markup("%s\n" % date) + label.set_markup(f"{date}\n") label.set_halign(Gtk.Align.START) grid.attach(label, 0, i, 1, 1) - i = i + 1 + i += 1 label = Gtk.Label() label.set_line_wrap(True) - label.set_markup("%s\n%s\n" % (c['subject'], c['author'])) + label.set_markup(f"{c['subject']}\n{c['author']}\n") label.set_halign(Gtk.Align.START) grid.attach(label, 0, i, 1, 1) - i = i + 1 + i += 1 - details = Gtk.Label(label=c['message'] + "\n\n\n") + details = Gtk.Label(label=f"{c['message']}\n\n\n") details.set_line_wrap(True) details.set_halign(Gtk.Align.START) grid.attach(details, 0, i, 1, 1) - i = i + 1 + i += 1 if "package_count" in info: - label.set_markup("%d " % info['package_count'] + - ngettext("Package will be updated", "Packages will be updated", info['package_count']) + - ":\n") + label.set_markup(( + f'{info["package_count"]} ' + + ngettext("Package will be updated", "Packages will be updated", info["package_count"]) + + f':\n' + )) label.set_halign(Gtk.Align.CENTER) grid.attach(label, 0, i, 3, 1) - i = i + 1 - j = 0 - for c in info["package_list"]: + i += 1 + for j, c in enumerate(info["package_list"]): label = Gtk.Label() - label.set_markup(" %s " % c) + label.set_markup(f" {c} ") label.set_halign(Gtk.Align.START) label.set_ellipsize(Pango.EllipsizeMode.END) pos = (j % 3) grid.attach(label, pos, i, 1, 1) - j = j + 1 if pos == 2: - i = i + 1 + i += 1 elif "full" in info: - label.set_markup("" + _("Perform a full upgrade?") + "") + label.set_markup('' + _("Perform a full upgrade?") + '') grid.attach(label, 0, i, 1, 1) - i = i + 1 + i += 1 else: - label.set_markup("" + _("%s will be updated to version") % program.capitalize() + - ": %s" % (info['remote_version'])) - + label.set_markup( + "" + _("%s will be updated to version") % program.capitalize() + + f": {info['remote_version']}" + ) + grid.attach(label, 0, i, 1, 1) - i = i + 1 scroll.add(grid) @@ -236,16 +230,16 @@ class SystemPanel(ScreenPanel): def update_confirm(self, widget, response_id, program): if response_id == Gtk.ResponseType.OK: - logging.debug("Updating %s" % program) + logging.debug(f"Updating {program}") self.update_program(self, program) widget.destroy() def reset_confirm(self, widget, response_id, program): if response_id == Gtk.ResponseType.OK: - logging.debug("Recovering hard %s" % program) + logging.debug(f"Recovering hard {program}") self.reset_repo(self, program, True) if response_id == Gtk.ResponseType.APPLY: - logging.debug("Recovering soft %s" % program) + logging.debug(f"Recovering soft {program}") self.reset_repo(self, program, False) widget.destroy() @@ -257,17 +251,12 @@ class SystemPanel(ScreenPanel): {"name": _("Finish"), "response": Gtk.ResponseType.CANCEL} ] - 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_events(Gdk.EventMask.TOUCH_MASK) - scroll.add_events(Gdk.EventMask.BUTTON_PRESS_MASK) + scroll = self._gtk.ScrolledWindow() - self.labels['update_progress'] = Gtk.Label("%s %s..." % (_("Starting recovery for"), program)) + self.labels['update_progress'] = Gtk.Label(_("Starting recovery for") + f' {program}...') self.labels['update_progress'].set_halign(Gtk.Align.START) self.labels['update_progress'].set_valign(Gtk.Align.START) + self.labels['update_progress'].set_ellipsize(Pango.EllipsizeMode.END) scroll.add(self.labels['update_progress']) self.labels['update_scroll'] = scroll @@ -277,9 +266,9 @@ class SystemPanel(ScreenPanel): self.update_prog = program self.update_dialog = dialog - logging.info("Sending machine.update.recover name: %s" % program) + logging.info(f"Sending machine.update.recover name: {program}") - self._screen._ws.send_method("machine.update.recover", {"name": program, "hard": str(hard)}) + self._screen._ws.send_method("machine.update.recover", {"name": program, "hard": hard}) self._screen.set_updating(True) def update_program(self, widget, program): @@ -291,34 +280,24 @@ class SystemPanel(ScreenPanel): if program in self.update_status['version_info']: info = self.update_status['version_info'][program] - logging.info("program: %s" % info) + logging.info(f"program: {info}") else: - info = ["full"] + info = {"full": True} logging.info("full upgrade") - if "package_count" in info: - if info['package_count'] == 0: - return - elif "version" in info: - if info['version'] == info['remote_version']: - return - + if "package_count" in info and info['package_count'] == 0 \ + or "version" in info and info['version'] == info['remote_version']: + return buttons = [ {"name": _("Finish"), "response": Gtk.ResponseType.CANCEL} ] - 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_events(Gdk.EventMask.TOUCH_MASK) - scroll.add_events(Gdk.EventMask.BUTTON_PRESS_MASK) + scroll = self._gtk.ScrolledWindow() if "full" in info: - self.labels['update_progress'] = Gtk.Label("%s\n" % _("Updating")) + self.labels['update_progress'] = Gtk.Label(_("Updating") + '\n') else: - self.labels['update_progress'] = Gtk.Label("%s %s..." % (_("Starting update for"), program)) + self.labels['update_progress'] = Gtk.Label(_("Starting update for") + f' {program}...') self.labels['update_progress'].set_halign(Gtk.Align.START) self.labels['update_progress'].set_valign(Gtk.Align.START) scroll.add(self.labels['update_progress']) @@ -331,30 +310,30 @@ class SystemPanel(ScreenPanel): self.update_dialog = dialog if program in ['klipper', 'moonraker', 'system', 'full']: - logging.info("Sending machine.update.%s" % program) - self._screen._ws.send_method("machine.update.%s" % program) + logging.info(f"Sending machine.update.{program}") + self._screen._ws.send_method(f"machine.update.{program}") else: - logging.info("Sending machine.update.client name: %s" % program) + logging.info(f"Sending machine.update.client name: {program}") self._screen._ws.send_method("machine.update.client", {"name": program}) self._screen.set_updating(True) def update_program_info(self, p): - logging.info("Updating program: %s " % p) + logging.info(f"Updating program: {p} ") if 'version_info' not in self.update_status or p not in self.update_status['version_info']: return info = self.update_status['version_info'][p] - logging.info("%s: %s" % (p, info)) + logging.info(f"{p}: {info}") if p == "system": self.labels[p].set_markup("System") if info['package_count'] == 0: - self.labels["%s_status" % p].set_label(_("Up To Date")) - self.labels["%s_status" % p].get_style_context().remove_class('update') - self.labels["%s_status" % p].set_sensitive(False) + self.labels[f"{p}_status"].set_label(_("Up To Date")) + self.labels[f"{p}_status"].get_style_context().remove_class('update') + self.labels[f"{p}_status"].set_sensitive(False) else: - self._needs_update(p, "Update", 'update') + self._needs_update(p) elif 'configured_type' in info and info['configured_type'] == 'git_repo': if info['is_valid'] and not info['is_dirty']: diff --git a/panels/temperature.py b/panels/temperature.py index c70bf132..7ac95b8f 100644 --- a/panels/temperature.py +++ b/panels/temperature.py @@ -2,7 +2,7 @@ import gi import logging gi.require_version("Gtk", "3.0") -from gi.repository import Gtk, Gdk, GLib, Pango +from gi.repository import Gtk, GLib, Pango from ks_includes.screen_panel import ScreenPanel from ks_includes.widgets.graph import HeaterGraph @@ -17,11 +17,19 @@ class TemperaturePanel(ScreenPanel): graph_update = None active_heater = None - def initialize(self, panel_name): + def __init__(self, screen, title, back=True, action_bar=True, printer_name=True): + super().__init__(screen, title, back, action_bar, printer_name) + self.popover_device = None + self.h = 1 + self.tempdeltas = ["1", "5", "10", "25"] + self.tempdelta = "10" + self.show_preheat = False self.preheat_options = self._screen._config.get_preheat_options() - logging.debug("Preheat options: %s" % self.preheat_options) - self._gtk.reset_temp_color() + logging.debug(f"Preheat options: {self.preheat_options}") self.grid = self._gtk.HomogeneousGrid() + + def initialize(self, panel_name): + self._gtk.reset_temp_color() self.grid.attach(self.create_left_panel(), 0, 0, 1, 1) # When printing start in temp_delta mode and only select tools @@ -33,8 +41,6 @@ class TemperaturePanel(ScreenPanel): if state not in ["printing", "paused"]: self.show_preheat = True selection.extend(self._printer.get_heaters()) - else: - self.show_preheat = False # Select heaters for h in selection: @@ -57,7 +63,7 @@ class TemperaturePanel(ScreenPanel): def create_right_panel(self): - cooldown = self._gtk.ButtonImage('cool-down', _('Cooldown'), "color4", 1, Gtk.PositionType.LEFT, False) + cooldown = self._gtk.ButtonImage('cool-down', _('Cooldown'), "color4", .66, Gtk.PositionType.LEFT, False) adjust = self._gtk.ButtonImage('fine-tune', '', "color3", 1, Gtk.PositionType.LEFT, False) right = self._gtk.HomogeneousGrid() @@ -87,19 +93,15 @@ class TemperaturePanel(ScreenPanel): self.labels["preheat_grid"] = self._gtk.HomogeneousGrid() for i, option in enumerate(self.preheat_options): if option != "cooldown": - self.labels[option] = self._gtk.Button(option, "color%d" % ((i % 4) + 1)) + self.labels[option] = self._gtk.Button(option, f"color{(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 = self._gtk.ScrolledWindow() + scroll = Gtk.ScrolledWindow() scroll.set_policy(Gtk.PolicyType.NEVER, Gtk.PolicyType.AUTOMATIC) scroll.add(self.labels["preheat_grid"]) return scroll def delta_adjust(self): - - 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, "+") @@ -107,11 +109,10 @@ class TemperaturePanel(ScreenPanel): self.labels["decrease"].connect("clicked", self.change_target_temp_incremental, "-") tempgrid = Gtk.Grid() - j = 0 - for i in self.tempdeltas: - self.labels['deg' + i] = self._gtk.ToggleButton(i) - self.labels['deg' + i].connect("clicked", self.change_temp_delta, i) - ctx = self.labels['deg' + i].get_style_context() + for j, i in enumerate(self.tempdeltas): + self.labels[f'deg{i}'] = self._gtk.ToggleButton(i) + self.labels[f'deg{i}'].connect("clicked", self.change_temp_delta, i) + ctx = self.labels[f'deg{i}'].get_style_context() if j == 0: ctx.add_class("distbutton_top") elif j == len(self.tempdeltas) - 1: @@ -120,58 +121,52 @@ class TemperaturePanel(ScreenPanel): ctx.add_class("distbutton") if i == "10": ctx.add_class("distbutton_active") - tempgrid.attach(self.labels['deg' + i], j, 0, 1, 1) - j += 1 - - self.labels["deg" + self.tempdelta].set_active(True) + tempgrid.attach(self.labels[f'deg{i}'], j, 0, 1, 1) + self.labels[f"deg{self.tempdelta}"].set_active(True) vbox = Gtk.Box(orientation=Gtk.Orientation.VERTICAL) vbox.pack_start(Gtk.Label(_("Temperature") + " (°C)"), False, False, 8) vbox.pack_end(tempgrid, True, True, 2) - if self._screen.vertical_mode: - deltagrid.attach(self.labels["decrease"], 0, 0, 1, 2) - deltagrid.attach(self.labels["increase"], 1, 0, 1, 2) - deltagrid.attach(vbox, 0, 2, 2, 2) - else: - deltagrid.attach(self.labels["decrease"], 0, 0, 1, 3) - deltagrid.attach(self.labels["increase"], 1, 0, 1, 3) - deltagrid.attach(vbox, 0, 3, 2, 2) + vsize = 2 if self._screen.vertical_mode else 3 + deltagrid.attach(self.labels["decrease"], 0, 0, 1, vsize) + deltagrid.attach(self.labels["increase"], 1, 0, 1, vsize) + deltagrid.attach(vbox, 0, vsize, 2, 2) return deltagrid def change_temp_delta(self, widget, tempdelta): if self.tempdelta == tempdelta: return - logging.info("### tempdelta " + str(tempdelta)) + logging.info(f"### tempdelta {tempdelta}") - ctx = self.labels["deg" + str(self.tempdelta)].get_style_context() + ctx = self.labels[f"deg{self.tempdelta}"].get_style_context() ctx.remove_class("distbutton_active") self.tempdelta = tempdelta - ctx = self.labels["deg" + self.tempdelta].get_style_context() + ctx = self.labels[f"deg{self.tempdelta}"].get_style_context() ctx.add_class("distbutton_active") for i in self.tempdeltas: if i == self.tempdeltas: continue - self.labels["deg" + str(i)].set_active(False) + self.labels[f"deg{i}"].set_active(False) - def change_target_temp_incremental(self, widget, dir): + def change_target_temp_incremental(self, widget, direction): 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 == "+": + if direction == "+": target += int(self.tempdelta) - MAX_TEMP = int(float(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)) + max_temp = int(float(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:") + f' {target}') + else: target -= int(self.tempdelta) - if target < 0: - target = 0 + target = max(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'): @@ -181,10 +176,10 @@ class TemperaturePanel(ScreenPanel): 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) + logging.info(f"Unknown heater: {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)) + logging.info(f"Setting {heater} to {target}") def activate(self): if self.graph_update is None: @@ -222,42 +217,42 @@ class TemperaturePanel(ScreenPanel): 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)) + logging.info(f"Setting {heater} to 0") self._printer.set_dev_stat(heater, "target", 0) else: target = None for heater in self.active_heaters: - MAX_TEMP = int(float(self._printer.get_config_section(heater)['max_temp'])) + max_temp = int(float(self._printer.get_config_section(heater)['max_temp'])) if heater.startswith('extruder'): target = self.preheat_options[setting]["extruder"] - if target is not None and target >= 0 and target <= MAX_TEMP: + if target is not None and 0 <= target <= max_temp: 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"] - if target is not None and target >= 0 and target <= MAX_TEMP: + if target is not None and 0 <= target <= max_temp: self._screen._ws.klippy.set_bed_temp(target) elif heater.startswith('heater_generic '): target = self.preheat_options[setting]["heater_generic"] - if target is not None and target >= 0 and target <= MAX_TEMP: + if target is not None and 0 <= target <= max_temp: self._screen._ws.klippy.set_heater_temp(" ".join(heater.split(" ")[1:]), target) elif heater.startswith('temperature_fan '): target = self.preheat_options[setting]["temperature_fan"] - if target is not None and target >= 0 and target <= MAX_TEMP: + if target is not None and 0 <= target <= max_temp: self._screen._ws.klippy.set_temp_fan_temp(" ".join(heater.split(" ")[1:]), target) else: - logging.info("Unknown heater: %s" % heater) + logging.info(f"Unknown heater: {heater}") self._screen.show_popup_message(_("Unknown Heater") + " " + heater) if target is None: continue - if target <= MAX_TEMP: + if target <= max_temp: if target >= 0: self._printer.set_dev_stat(heater, "target", target) - logging.info("Setting %s to %d" % (heater, target)) + logging.info(f"Setting {heater} to {target}") else: - self._screen.show_popup_message(_("Can't set above the maximum:") + (" %s" % MAX_TEMP)) + self._screen.show_popup_message(_("Can't set above the maximum:") + f' {max_temp}') if setting in self.preheat_options and self.preheat_options[setting]['gcode']: # This small delay is needed to properly update the target if the user configured something above - # and then changed the target again using the preheat gcode + # and then changed the target again using preheat gcode GLib.timeout_add(250, self.preheat_gcode, setting) def preheat_gcode(self, setting): @@ -266,7 +261,7 @@ class TemperaturePanel(ScreenPanel): def add_device(self, device): - logging.info("Adding device: %s" % device) + logging.info(f"Adding device: {device}") temperature = self._printer.get_dev_stat(device, "temperature") if temperature is None: @@ -281,60 +276,40 @@ class TemperaturePanel(ScreenPanel): devname = device if device.startswith("extruder"): - i = 0 - for d in self.devices: - if d.startswith('extruder'): - i += 1 - if self._printer.extrudercount > 1: - image = "extruder-%s" % i - else: - image = "extruder" - class_name = "graph_label_%s" % device - type = "extruder" + i = sum(d.startswith('extruder') for d in self.devices) + image = f"extruder-{i}" if self._printer.extrudercount > 1 else "extruder" + class_name = f"graph_label_{device}" + dev_type = "extruder" elif device == "heater_bed": image = "bed" devname = "Heater Bed" class_name = "graph_label_heater_bed" - type = "bed" + dev_type = "bed" elif device.startswith("heater_generic"): - self.h = 1 - for d in self.devices: - if "heater_generic" in d: - self.h += 1 + self.h = sum("heater_generic" in d for d in self.devices) image = "heater" - class_name = "graph_label_sensor_%s" % self.h - type = "sensor" + class_name = f"graph_label_sensor_{self.h}" + dev_type = "sensor" elif device.startswith("temperature_fan"): - f = 1 - for d in self.devices: - if "temperature_fan" in d: - f += 1 + f = 1 + sum("temperature_fan" in d for d in self.devices) image = "fan" - class_name = "graph_label_fan_%s" % f - type = "fan" + class_name = f"graph_label_fan_{f}" + dev_type = "fan" elif self._config.get_main_config().getboolean("only_heaters", False): return False else: - s = 1 - try: - s += self.h - except Exception: - pass - for d in self.devices: - if "sensor" in d: - s += 1 + self.h += sum("sensor" in d for d in self.devices) image = "heat-up" - class_name = "graph_label_sensor_%s" % s - type = "sensor" + class_name = f"graph_label_sensor_{self.h}" + dev_type = "sensor" - rgb, color = self._gtk.get_temp_color(type) + rgb = self._gtk.get_temp_color(dev_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().replace("_", " "), None, .5, Gtk.PositionType.LEFT, False) name.connect('clicked', self.on_popover_clicked, device) @@ -355,19 +330,14 @@ class TemperaturePanel(ScreenPanel): 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 @@ -380,11 +350,11 @@ class TemperaturePanel(ScreenPanel): def change_target_temp(self, temp): - MAX_TEMP = int(float(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)) + max_temp = int(float(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:") + f' {max_temp}') return - temp = 0 if temp < 0 else temp + temp = max(temp, 0) if self.active_heater.startswith('extruder'): self._screen._ws.klippy.set_tool_temp(self._printer.get_tool_number(self.active_heater), temp) @@ -395,7 +365,7 @@ class TemperaturePanel(ScreenPanel): 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) + logging.info(f"Unknown heater: {self.active_heater}") self._screen.show_popup_message(_("Unknown Heater") + " " + self.active_heater) self._printer.set_dev_stat(self.active_heater, "target", temp) @@ -416,12 +386,7 @@ class TemperaturePanel(ScreenPanel): da.set_vexpand(True) self.labels['da'] = da - scroll = Gtk.ScrolledWindow() - scroll.set_property("overlay-scrolling", False) - scroll.set_hexpand(True) - scroll.set_vexpand(True) - scroll.add_events(Gdk.EventMask.TOUCH_MASK) - scroll.add_events(Gdk.EventMask.BUTTON_PRESS_MASK) + scroll = self._gtk.ScrolledWindow() scroll.set_policy(Gtk.PolicyType.NEVER, Gtk.PolicyType.AUTOMATIC) scroll.add(self.labels['devices']) @@ -443,16 +408,14 @@ class TemperaturePanel(ScreenPanel): popover.set_position(Gtk.PositionType.BOTTOM) self.labels['popover'] = popover - i = 0 - for d in self._printer.get_temp_store_devices(): - if self.add_device(d): - i += 1 + i = sum(1 for d in self._printer.get_temp_store_devices() if self.add_device(d)) + graph_height = (self._gtk.get_content_height() / 2) - ((i + 2) * 4 * self._gtk.get_font_size()) self.labels['da'].set_size_request(-1, graph_height) return box def graph_show_device(self, widget, show=True): - logging.info("Graph show: %s %s" % (self.popover_device, show)) + logging.info(f"Graph show: {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") @@ -544,8 +507,7 @@ class TemperaturePanel(ScreenPanel): 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))) + if self.devices[device]["can_target"] and target > 0: + self.devices[device]["temp"].get_child().set_label(f"{temp:.1f} / {target:.0f}") else: - self.devices[device]["temp"].get_child().set_label("%.1f " % temp) + self.devices[device]["temp"].get_child().set_label(f"{temp:.1f}") diff --git a/panels/zcalibrate.py b/panels/zcalibrate.py index 104004a1..e984bf0c 100644 --- a/panels/zcalibrate.py +++ b/panels/zcalibrate.py @@ -21,15 +21,16 @@ class ZCalibratePanel(ScreenPanel): def __init__(self, screen, title, back=True): super().__init__(screen, title, False) + self.z_offset = None def initialize(self, panel_name): if self._printer.config_section_exists("probe"): - self.z_offset = self._screen.printer.get_config_section("probe")['z_offset'] + self.z_offset = float(self._screen.printer.get_config_section("probe")['z_offset']) elif self._printer.config_section_exists("bltouch"): - self.z_offset = self._screen.printer.get_config_section("bltouch")['z_offset'] + self.z_offset = float(self._screen.printer.get_config_section("bltouch")['z_offset']) elif self._printer.config_section_exists("smart_effector"): - self.z_offset = self._screen.printer.get_config_section("smart_effector")['z_offset'] + self.z_offset = float(self._screen.printer.get_config_section("smart_effector")['z_offset']) else: self.z_offset = None @@ -42,7 +43,7 @@ class ZCalibratePanel(ScreenPanel): pos.attach(Gtk.Label(_("Probe Offset") + ": "), 0, 2, 2, 1) pos.attach(Gtk.Label(_("Saved")), 0, 3, 1, 1) pos.attach(Gtk.Label(_("New")), 1, 3, 1, 1) - pos.attach(Gtk.Label(str(round(float(self.z_offset), 2))), 0, 4, 1, 1) + pos.attach(Gtk.Label(f"{self.z_offset:.2f}"), 0, 4, 1, 1) pos.attach(self.widgets['zoffset'], 1, 4, 1, 1) self.widgets['zpos'] = self._gtk.ButtonImage('z-farther', _("Raise Nozzle"), 'color4') @@ -55,47 +56,28 @@ class ZCalibratePanel(ScreenPanel): self.widgets['cancel'] = self._gtk.ButtonImage('cancel', _('Abort'), 'color2') self.widgets['cancel'].connect("clicked", self.abort) - functions = ["endstop", "probe", "mesh", "delta", "delta_manual"] + functions = [] pobox = Gtk.Box(orientation=Gtk.Orientation.VERTICAL) - endstop = (self._printer.config_section_exists("stepper_z") and - not self._screen.printer.get_config_section("stepper_z")['endstop_pin'].startswith("probe")) - if endstop: - endstop = self._gtk.Button(label="Endstop") - endstop.connect("clicked", self.start_calibration, "endstop") - pobox.pack_start(endstop, True, True, 5) - else: - functions.remove("endstop") - + if self._printer.config_section_exists("stepper_z") \ + and not self._screen.printer.get_config_section("stepper_z")['endstop_pin'].startswith("probe"): + self._add_button("Endstop", "endstop", pobox) + functions.append("endstop") if self._printer.config_section_exists("probe") or self._printer.config_section_exists("bltouch"): - probe = self._gtk.Button(label="Probe") - probe.connect("clicked", self.start_calibration, "probe") - pobox.pack_start(probe, True, True, 5) - functions.remove("mesh") - else: - functions.remove("probe") + self._add_button("Probe", "probe", pobox) + functions.append("probe") + if self._printer.config_section_exists("bed_mesh") and "probe" not in functions: # This is used to do a manual bed mesh if there is no probe - if self._printer.config_section_exists("bed_mesh"): - mesh = self._gtk.Button(label="Bed mesh") - mesh.connect("clicked", self.start_calibration, "mesh") - pobox.pack_start(mesh, True, True, 5) - else: - functions.remove("mesh") - + self._add_button("Bed mesh", "mesh", pobox) + functions.append("mesh") if "delta" in self._screen.printer.get_config_section("printer")['kinematics']: - if self._printer.config_section_exists("probe") or self._printer.config_section_exists("bltouch"): - delta = self._gtk.Button(label="Delta Automatic") - delta.connect("clicked", self.start_calibration, "delta") - pobox.pack_start(delta, True, True, 5) - else: - functions.remove("delta") - delta_manual = self._gtk.Button(label="Delta Manual") - delta_manual.connect("clicked", self.start_calibration, "delta_manual") - pobox.pack_start(delta_manual, True, True, 5) - else: - functions.remove("delta") - functions.remove("delta_manual") + if "probe" in functions: + self._add_button("Delta Automatic", "delta", pobox) + functions.append("delta") + # Since probes may not be accturate enough for deltas, always show the manual method + self._add_button("Delta Manual", "delta_manual", pobox) + functions.append("delta_manual") - logging.info("Available functions: %s" % functions) + logging.info(f"Available functions for calibration: {functions}") self.labels['popover'] = Gtk.Popover() self.labels['popover'].add(pobox) @@ -107,8 +89,7 @@ class ZCalibratePanel(ScreenPanel): self.widgets['start'].connect("clicked", self.start_calibration, functions[0]) distgrid = Gtk.Grid() - j = 0 - for i in self.distances: + for j, i in enumerate(self.distances): self.widgets[i] = self._gtk.ToggleButton(i) self.widgets[i].set_direction(Gtk.TextDirection.LTR) self.widgets[i].connect("clicked", self.change_distance, i) @@ -122,12 +103,10 @@ class ZCalibratePanel(ScreenPanel): if i == "1": ctx.add_class("distbutton_active") distgrid.attach(self.widgets[i], j, 0, 1, 1) - j += 1 - self.widgets["1"].set_active(True) - distances = Gtk.Box(orientation=Gtk.Orientation.VERTICAL) self.widgets['move_dist'] = Gtk.Label(_("Move Distance (mm)")) + distances = Gtk.Box(orientation=Gtk.Orientation.VERTICAL) distances.pack_start(self.widgets['move_dist'], True, True, 0) distances.pack_start(distgrid, True, True, 0) @@ -149,67 +128,25 @@ class ZCalibratePanel(ScreenPanel): grid.attach(self.widgets['complete'], 2, 0, 1, 1) grid.attach(self.widgets['cancel'], 2, 1, 1, 1) grid.attach(distances, 0, 2, 3, 1) - self.buttons_not_calibrating() - self.content.add(grid) + def _add_button(self, label, method, pobox): + popover_button = self._gtk.Button(label=label) + popover_button.connect("clicked", self.start_calibration, method) + pobox.pack_start(popover_button, True, True, 5) + def on_popover_clicked(self, widget): self.labels['popover'].set_relative_to(widget) self.labels['popover'].show_all() def start_calibration(self, widget, method): - x_position = y_position = 0 self.labels['popover'].popdown() if self._screen.printer.get_stat("toolhead", "homed_axes") != "xyz": self._screen._ws.klippy.gcode_script(KlippyGcodes.HOME) if method == "probe": - # Get position from config - printer = self._screen.connected_printer - printer_cfg = self._config.get_printer_config(printer) - logging.info(printer_cfg) - if printer_cfg is not None: - x_position = printer_cfg.getfloat("calibrate_x_position", 0) - y_position = printer_cfg.getfloat("calibrate_y_position", 0) - elif 'z_calibrate_position' in self._config.get_config(): - # OLD global way, this should be deprecated - x_position = self._config.get_config()['z_calibrate_position'].getfloat("calibrate_x_position", 0) - y_position = self._config.get_config()['z_calibrate_position'].getfloat("calibrate_y_position", 0) - - if x_position > 0 and y_position > 0: - logging.debug("Configured probing position X: %.0f Y: %.0f", x_position, y_position) - self._screen._ws.klippy.gcode_script('G0 X%d Y%d F3000' % (x_position, y_position)) - elif "delta" in self._screen.printer.get_config_section("printer")['kinematics']: - logging.info("Detected delta kinematics calibrating at 0,0") - self._screen._ws.klippy.gcode_script('G0 X%d Y%d F3000' % (0, 0)) - else: - logging.debug("Position not configured, probing the middle of the bed") - x_position = int(int(self._screen.printer.get_config_section("stepper_x")['position_max']) / 2) - y_position = int(int(self._screen.printer.get_config_section("stepper_y")['position_max']) / 2) - - # Find probe offset - klipper_cfg = self._screen.printer.get_config_section_list() - x_offset = y_offset = 0 - if "bltouch" in klipper_cfg: - bltouch = self._screen.printer.get_config_section("bltouch") - if "x_offset" in bltouch: - x_offset = float(bltouch['x_offset']) - if "y_offset" in bltouch: - y_offset = float(bltouch['y_offset']) - elif "probe" in klipper_cfg: - probe = self._screen.printer.get_config_section("probe") - if "x_offset" in probe: - x_offset = float(probe['x_offset']) - if "y_offset" in probe: - y_offset = float(probe['y_offset']) - if x_offset > 0 or y_offset > 0: - logging.debug("Substracting probe offset X: %.0f Y: %.0f", x_offset, y_offset) - x_position = self.apply_probe_offset(x_position, x_offset) - y_position = self.apply_probe_offset(y_position, y_offset) - # Move - self._screen._ws.klippy.gcode_script('G0 X%d Y%d F3000' % (x_position, y_position)) - + self._move_to_position() self._screen._ws.klippy.gcode_script(KlippyGcodes.PROBE_CALIBRATE) elif method == "mesh": self._screen._ws.klippy.gcode_script("BED_MESH_CALIBRATE") @@ -220,8 +157,62 @@ class ZCalibratePanel(ScreenPanel): elif method == "endstop": self._screen._ws.klippy.gcode_script(KlippyGcodes.Z_ENDSTOP_CALIBRATE) - def apply_probe_offset(self, pos, offset): - return max(0, int(float(pos) - offset)) + def _move_to_position(self): + # Get position from config + x_position = y_position = None + printer_cfg = self._config.get_printer_config(self._screen.connected_printer) + logging.info(printer_cfg) + if printer_cfg is not None: + x_position = printer_cfg.getfloat("calibrate_x_position", None) + y_position = printer_cfg.getfloat("calibrate_y_position", None) + elif 'z_calibrate_position' in self._config.get_config(): + # OLD global way, this should be deprecated + x_position = self._config.get_config()['z_calibrate_position'].getfloat("calibrate_x_position", None) + y_position = self._config.get_config()['z_calibrate_position'].getfloat("calibrate_y_position", None) + + if x_position is not None and y_position is not None: + logging.debug(f"Configured probing position X: {x_position} Y: {y_position}") + self._screen._ws.klippy.gcode_script(f'G0 X{x_position} Y{y_position} F3000') + elif "delta" in self._screen.printer.get_config_section("printer")['kinematics']: + logging.info("Detected delta kinematics calibrating at 0,0") + self._screen._ws.klippy.gcode_script('G0 X0 Y0 F3000') + else: + self._calculate_position() + + def _calculate_position(self): + logging.debug("Position not configured, probing the middle of the bed") + try: + xmax = float(self._screen.printer.get_config_section("stepper_x")['position_max']) + ymax = float(self._screen.printer.get_config_section("stepper_y")['position_max']) + except KeyError: + logging.error("Couldn't get max position from stepper_x and stepper_y") + return + x_position = xmax / 2 + y_position = ymax / 2 + logging.info(f"Center position X:{x_position} Y:{y_position}") + + # Find probe offset + klipper_cfg = self._screen.printer.get_config_section_list() + x_offset = y_offset = None + if "bltouch" in klipper_cfg: + bltouch = self._screen.printer.get_config_section("bltouch") + if "x_offset" in bltouch: + x_offset = float(bltouch['x_offset']) + if "y_offset" in bltouch: + y_offset = float(bltouch['y_offset']) + elif "probe" in klipper_cfg: + probe = self._screen.printer.get_config_section("probe") + if "x_offset" in probe: + x_offset = float(probe['x_offset']) + if "y_offset" in probe: + y_offset = float(probe['y_offset']) + if x_offset is not None and y_offset is not None: + logging.info(f"Probe offset X:{x_offset} Y:{y_offset}") + x_position = x_position - x_offset + y_position = y_position - y_offset + + logging.info(f"Moving to X:{x_position} Y:{y_position}") + self._screen._ws.klippy.gcode_script(f'G0 X{x_position} Y{y_position} F3000') def process_update(self, action, data): @@ -229,35 +220,37 @@ class ZCalibratePanel(ScreenPanel): if self._screen.printer.get_stat("toolhead", "homed_axes") != "xyz": self.widgets['zposition'].set_text("Z: ?") elif "toolhead" in data and "position" in data['toolhead']: - self.updatePosition(data['toolhead']['position']) + self.update_position(data['toolhead']['position']) elif action == "notify_gcode_response": data = data.lower() - logging.info(data) if "unknown" in data: self.buttons_not_calibrating() + logging.info(data) elif "save_config" in data: self.buttons_not_calibrating() self._screen.show_popup_message(_("Calibrated, save configuration to make it permanent"), level=1) elif "out of range" in data: - self._screen.show_popup_message("%s" % data) + self._screen.show_popup_message(data) self.buttons_not_calibrating() + logging.info(data) elif "fail" in data and "use testz" in data: self._screen.show_popup_message(_("Failed, adjust position first")) self.buttons_not_calibrating() + logging.info(data) elif "use testz" in data or "use abort" in data or "z position" in data: self.buttons_calibrating() return - def updatePosition(self, position): - self.widgets['zposition'].set_text("Z: " + str(round(position[2], 2))) + def update_position(self, position): + self.widgets['zposition'].set_text(f"Z: {position[2]:.2f}") if self.z_offset is not None: - self.widgets['zoffset'].set_text(str(round(position[2] + float(self.z_offset), 2))) + self.widgets['zoffset'].set_text(f"{position[2] - self.z_offset:.2f}") def change_distance(self, widget, distance): if self.distance == distance: return - ctx = self.widgets[str(self.distance)].get_style_context() + ctx = self.widgets[f'{self.distance}'].get_style_context() ctx.remove_class("distbutton_active") self.distance = distance @@ -266,11 +259,11 @@ class ZCalibratePanel(ScreenPanel): for i in self.distances: if i == self.distance: continue - self.widgets[str(i)].set_active(False) + self.widgets[f"{i}"].set_active(False) - def move(self, widget, dir): - dist = str(self.distance) if dir == "+" else "-" + str(self.distance) - logging.info("# Moving %s", KlippyGcodes.testz_move(dist)) + def move(self, widget, direction): + dist = f"{direction}{self.distance}" + logging.info(f"# Moving {KlippyGcodes.testz_move(dist)}") self._screen._ws.klippy.gcode_script(KlippyGcodes.testz_move(dist)) def abort(self, widget): diff --git a/screen.py b/screen.py index 563ae286..d93699ba 100644 --- a/screen.py +++ b/screen.py @@ -84,6 +84,9 @@ class KlipperScreen(Gtk.Window): reinit_count = 0 def __init__(self, args, version): + self.blanking_time = 600 + self.use_dpms = True + self.apiclient = None self.version = version configfile = os.path.normpath(os.path.expanduser(args.configfile)) @@ -91,10 +94,7 @@ class KlipperScreen(Gtk.Window): self._config = KlipperScreenConfig(configfile, self) self.lang = self._config.get_lang() - logging.debug("OS Language: %s" % os.getenv('LANG')) - - settings = Gtk.Settings.get_default() - logging.info("Font settings: %s" % settings.get_property('gtk-font-name')) + logging.debug(f"OS Language: {os.getenv('LANG')}") self.lang_ltr = True for lang in self.rtl_languages: @@ -104,19 +104,14 @@ class KlipperScreen(Gtk.Window): logging.debug("Enabling RTL mode") break - - Gtk.Window.__init__(self) monitor = Gdk.Display.get_default().get_primary_monitor() self.width = self._config.get_main_config().getint("width", monitor.get_geometry().width) self.height = self._config.get_main_config().getint("height", monitor.get_geometry().height) self.set_default_size(self.width, self.height) self.set_resizable(False) - if self.width < self.height: - self.vertical_mode = True - else: - self.vertical_mode = False - logging.info("Screen resolution: %sx%s" % (self.width, self.height)) + self.vertical_mode = self.width < self.height + logging.info(f"Screen resolution: {self.width}x{self.height}") self.theme = self._config.get_main_config().get('theme') self.show_cursor = self._config.get_main_config().getboolean("show_cursor", fallback=False) self.gtk = KlippyGtk(self, self.width, self.height, self.theme, self.show_cursor, @@ -140,7 +135,7 @@ class KlipperScreen(Gtk.Window): def initial_connection(self): printers = self._config.get_printers() default_printer = self._config.get_main_config().get('default_printer') - logging.debug("Default printer: %s" % default_printer) + logging.debug(f"Default printer: {default_printer}") if [True for p in printers if default_printer in p]: self.connect_printer(default_printer) elif len(printers) == 1: @@ -153,6 +148,11 @@ class KlipperScreen(Gtk.Window): self.connect_printer(name) def connect_printer(self, name): + data = { + "moonraker_host": "127.0.0.1", + "moonraker_port": "7125", + "moonraker_api_key": False + } self.connecting_to_printer = name @@ -191,7 +191,7 @@ class KlipperScreen(Gtk.Window): self._ws.close() self.connecting = True - logging.info("Connecting to printer: %s" % name) + logging.info(f"Connecting to printer: {name}") self.apiclient = KlippyRest(data["moonraker_host"], data["moonraker_port"], data["moonraker_api_key"]) self.printer = Printer({ @@ -241,7 +241,7 @@ class KlipperScreen(Gtk.Window): self.connecting = False self.connected_printer = name - logging.debug("Connected to printer: %s" % name) + logging.debug(f"Connected to printer: {name}") def ws_subscribe(self): requested_updates = { @@ -275,15 +275,15 @@ class KlipperScreen(Gtk.Window): def _load_panel(self, panel, *args): if panel not in self.load_panel: - logging.debug("Loading panel: %s" % panel) - panel_path = os.path.join(os.path.dirname(__file__), 'panels', "%s.py" % panel) - logging.info("Panel path: %s" % panel_path) + logging.debug(f"Loading panel: {panel}") + panel_path = os.path.join(os.path.dirname(__file__), 'panels', f"{panel}.py") + logging.info(f"Panel path: {panel_path}") if not os.path.exists(panel_path): msg = f"Panel {panel} does not exist" logging.info(msg) raise Exception(msg) - module = importlib.import_module("panels.%s" % panel) + module = importlib.import_module(f"panels.{panel}") if not hasattr(module, "create_panel"): msg = f"Cannot locate create_panel function for {panel}" logging.info(msg) @@ -292,15 +292,15 @@ class KlipperScreen(Gtk.Window): try: return self.load_panel[panel](*args) - except Exception: + except Exception as e: msg = f"Unable to create panel {panel}" logging.exception(msg) - raise Exception(msg) + raise Exception(msg) from e - def show_panel(self, panel_name, type, title, remove=None, pop=True, **kwargs): + def show_panel(self, panel_name, panel_type, title, remove=None, pop=True, **kwargs): if panel_name not in self.panels: try: - self.panels[panel_name] = self._load_panel(type, self, title) + self.panels[panel_name] = self._load_panel(panel_type, self, title) if kwargs != {}: self.panels[panel_name].initialize(panel_name, **kwargs) @@ -309,8 +309,8 @@ class KlipperScreen(Gtk.Window): except Exception: if panel_name in self.panels: del self.panels[panel_name] - logging.exception("Unable to load panel %s" % type) - self.show_error_modal("Unable to load panel %s" % type) + logging.exception(f"Unable to load panel {panel_type}") + self.show_error_modal(f"Unable to load panel {panel_type}") return if hasattr(self.panels[panel_name], "process_update"): @@ -322,10 +322,10 @@ class KlipperScreen(Gtk.Window): elif remove == 1: self._remove_current_panel(pop) - logging.debug("Attaching panel %s" % panel_name) + logging.debug(f"Attaching panel {panel_name}") self.base_panel.add_content(self.panels[panel_name]) - logging.debug("Showing back. count: %s" % len(self._cur_panels)) + logging.debug(f"Showing back. count: {len(self._cur_panels)}") if len(self._cur_panels) == 0: self.base_panel.show_back(False) else: @@ -342,7 +342,7 @@ class KlipperScreen(Gtk.Window): logging.exception("Error attaching panel") self._cur_panels.append(panel_name) - logging.debug("Current panel hierarchy: %s", str(self._cur_panels)) + logging.debug(f"Current panel hierarchy: {self._cur_panels}") def show_popup_message(self, message, level=3): if self.screensaver is not None: @@ -402,8 +402,9 @@ class KlipperScreen(Gtk.Window): label = Gtk.Label() label.set_markup( - ("%s \n\n" % err) + - _("Check /tmp/KlipperScreen.log for more information.\nPlease submit an issue on GitHub for help.")) + f"{err} \n\n" + + _("Check /tmp/KlipperScreen.log for more information.\nPlease submit an issue on GitHub for help.") + ) label.set_hexpand(True) label.set_halign(Gtk.Align.CENTER) label.set_vexpand(True) @@ -413,12 +414,13 @@ class KlipperScreen(Gtk.Window): self.gtk.Dialog(self, buttons, label, self.error_modal_response) - def error_modal_response(self, widget, response_id): + @staticmethod + def error_modal_response(widget, response_id): widget.destroy() def restart_warning(self, value): - logging.debug("Showing restart warning because: %s" % value) + logging.debug(f"Showing restart warning because: {value}") buttons = [ {"name": _("Cancel"), "response": Gtk.ResponseType.CANCEL}, @@ -448,27 +450,22 @@ class KlipperScreen(Gtk.Window): widget.destroy() def init_style(self): - css = open(os.path.join(klipperscreendir, "styles", "base.css")) - css_data = css.read() - css.close() - f = open(os.path.join(klipperscreendir, "styles", "base.conf")) - style_options = json.load(f) - f.close() + css_data = pathlib.Path(os.path.join(klipperscreendir, "styles", "base.css")).read_text() + with open(os.path.join(klipperscreendir, "styles", "base.conf")) as f: + style_options = json.load(f) # Load custom theme theme = os.path.join(klipperscreendir, "styles", self.theme) theme_style = os.path.join(theme, "style.css") theme_style_conf = os.path.join(theme, "style.conf") if os.path.exists(theme_style): - css = open(theme_style) - css_data += css.read() - css.close() + with open(theme_style) as css: + css_data += css.read() if os.path.exists(theme_style_conf): try: - f = open(theme_style_conf) - style_options.update(json.load(f)) - f.close() + with open(theme_style_conf) as f: + style_options.update(json.load(f)) except Exception: logging.error("Unable to parse custom template conf file.") @@ -482,7 +479,7 @@ class KlipperScreen(Gtk.Window): ) for i in range(len(style_options['graph_colors']['bed']['colors'])): css_data += "\n.graph_label_heater_bed%s {border-left-color: #%s}" % ( - "" if i + 1 == 1 else i + 1, + "" if i == 0 else i + 1, style_options['graph_colors']['bed']['colors'][i] ) for i in range(len(style_options['graph_colors']['fan']['colors'])): @@ -496,7 +493,7 @@ class KlipperScreen(Gtk.Window): style_options['graph_colors']['sensor']['colors'][i] ) - css_data = css_data.replace("KS_FONT_SIZE", str(self.gtk.get_font_size())) + css_data = css_data.replace("KS_FONT_SIZE", f"{self.gtk.get_font_size()}") style_provider = Gtk.CssProvider() style_provider.load_from_data(css_data.encode()) @@ -514,7 +511,7 @@ class KlipperScreen(Gtk.Window): return self.updating def _go_to_submenu(self, widget, name): - logging.info("#### Go to submenu " + str(name)) + logging.info(f"#### Go to submenu {name}") # self._remove_current_panel(False) # Find current menu item @@ -525,15 +522,15 @@ class KlipperScreen(Gtk.Window): else: menu = "__print" - logging.info("#### Menu " + str(menu)) + logging.info(f"#### Menu {menu}") disname = self._config.get_menu_name(menu, name) menuitems = self._config.get_menu_items(menu, name) if len(menuitems) == 0: logging.info("No items in menu, returning.") return - self.show_panel(self._cur_panels[-1] + '_' + name, "menu", disname, 1, False, display_name=disname, - items=menuitems) + self.show_panel(f'{self._cur_panels[-1]}_{name}', + "menu", disname, 1, False, display_name=disname, items=menuitems) def _remove_all_panels(self): while len(self._cur_panels) > 0: @@ -541,24 +538,25 @@ class KlipperScreen(Gtk.Window): self.show_all() def _remove_current_panel(self, pop=True, show=True): - if len(self._cur_panels) > 0: - self.base_panel.remove(self.panels[self._cur_panels[-1]].get_content()) - if hasattr(self.panels[self._cur_panels[-1]], "deactivate"): - self.panels[self._cur_panels[-1]].deactivate() - self.remove_subscription(self._cur_panels[-1]) - if pop is True: - self._cur_panels.pop() - if len(self._cur_panels) > 0: - self.base_panel.add_content(self.panels[self._cur_panels[-1]]) - self.base_panel.show_back(False if len(self._cur_panels) == 1 else True) - if hasattr(self.panels[self._cur_panels[-1]], "activate"): - self.panels[self._cur_panels[-1]].activate() - if hasattr(self.panels[self._cur_panels[-1]], "process_update"): - self.panels[self._cur_panels[-1]].process_update("notify_status_update", - self.printer.get_updates()) - self.add_subscription(self._cur_panels[-1]) - if show is True: - self.show_all() + if len(self._cur_panels) <= 0: + return + self.base_panel.remove(self.panels[self._cur_panels[-1]].get_content()) + if hasattr(self.panels[self._cur_panels[-1]], "deactivate"): + self.panels[self._cur_panels[-1]].deactivate() + self.remove_subscription(self._cur_panels[-1]) + if pop is True: + self._cur_panels.pop() + if len(self._cur_panels) > 0: + self.base_panel.add_content(self.panels[self._cur_panels[-1]]) + self.base_panel.show_back(len(self._cur_panels) != 1) + if hasattr(self.panels[self._cur_panels[-1]], "activate"): + self.panels[self._cur_panels[-1]].activate() + if hasattr(self.panels[self._cur_panels[-1]], "process_update"): + self.panels[self._cur_panels[-1]].process_update("notify_status_update", + self.printer.get_updates()) + self.add_subscription(self._cur_panels[-1]) + if show is True: + self.show_all() def _menu_go_back(self, widget=None): logging.info("#### Menu go back") @@ -648,7 +646,7 @@ class KlipperScreen(Gtk.Window): def set_dpms(self, use_dpms): self.use_dpms = use_dpms - logging.info("DPMS set to: %s" % self.use_dpms) + logging.info(f"DPMS set to: {self.use_dpms}") self.set_screenblanking_timeout(self._config.get_main_config().get('screen_blanking')) def set_screenblanking_timeout(self, time): @@ -657,7 +655,7 @@ class KlipperScreen(Gtk.Window): self.use_dpms = self._config.get_main_config().getboolean("use_dpms", fallback=True) if time == "off": - logging.debug("Screen blanking: %s" % time) + logging.debug(f"Screen blanking: {time}") if self.dpms_timeout is not None: GLib.source_remove(self.dpms_timeout) self.dpms_timeout = None @@ -667,7 +665,7 @@ class KlipperScreen(Gtk.Window): return self.blanking_time = abs(int(time)) - logging.debug("Changing screen blanking to: %d" % self.blanking_time) + logging.debug(f"Changing screen blanking to: {self.blanking_time}") if self.use_dpms and functions.dpms_loaded is True: os.system("xset -display :0 +dpms") if functions.get_DPMS_state() == functions.DPMS_State.Fail: @@ -675,7 +673,7 @@ class KlipperScreen(Gtk.Window): else: logging.debug("Using DPMS") os.system("xset -display :0 s off") - os.system("xset -display :0 dpms 0 %s 0" % self.blanking_time) + os.system(f"xset -display :0 dpms 0 {self.blanking_time} 0") if self.dpms_timeout is None: self.dpms_timeout = GLib.timeout_add_seconds(1, self.check_dpms_state) return @@ -690,22 +688,22 @@ class KlipperScreen(Gtk.Window): return def set_updating(self, updating=False): - if self.updating is True and updating is False: - if len(self.update_queue) > 0: - i = self.update_queue.pop() - self.update_queue = [] - i[0](i[1]) + if self.updating is True and updating is False and len(self.update_queue) > 0: + i = self.update_queue.pop() + self.update_queue = [] + i[0](i[1]) self.updating = updating def show_printer_select(self, widget=None): - logging.debug("Saving panel: %s" % self._cur_panels[0]) + logging.debug(f"Saving panel: {self._cur_panels[0]}") self.printer_select_prepanel = self._cur_panels[0] self.base_panel.show_heaters(False) self.base_panel.show_macro_shortcut(False) self.base_panel.show_printer_select(False) self.show_panel("printer_select", "printer_select", "Printer Select", 2) self.show_all() + self.base_panel.action_bar.hide() def state_execute(self, callback, prev_state): if self.is_updating(): @@ -718,7 +716,6 @@ class KlipperScreen(Gtk.Window): self.printer_select_callbacks = [self.state_disconnected] return - logging.debug("### Going to disconnected") self.base_panel.show_macro_shortcut(False) self.wake_screen() @@ -735,7 +732,6 @@ class KlipperScreen(Gtk.Window): self.printer_select_callbacks = [self.state_error] return - self.base_panel.show_macro_shortcut(False) self.wake_screen() msg = self.printer.get_stat("webhooks", "state_message") @@ -791,7 +787,6 @@ class KlipperScreen(Gtk.Window): self.printer_select_callbacks = [self.state_startup] return - self.printer_initializing(_("Klipper is attempting to start")) def state_shutdown(self, prev_state): @@ -799,7 +794,6 @@ class KlipperScreen(Gtk.Window): self.printer_select_callbacks = [self.state_shutdown] return - self.base_panel.show_macro_shortcut(False) self.wake_screen() msg = self.printer.get_stat("webhooks", "state_message") @@ -813,7 +807,6 @@ class KlipperScreen(Gtk.Window): def _websocket_callback(self, action, data): - if self.connecting is True: return @@ -832,7 +825,7 @@ class KlipperScreen(Gtk.Window): elif action == "notify_metadata_update": self.files.request_metadata(data['filename']) elif action == "notify_update_response": - logging.info("%s: %s" % (action, data)) + logging.info(f"{action}: {data}") elif action == "notify_power_changed": logging.debug("Power status changed: %s", data) self.printer.process_power_update(data) @@ -854,16 +847,17 @@ class KlipperScreen(Gtk.Window): if self._cur_panels[-1] in self.subscriptions: self.panels[self._cur_panels[-1]].process_update(action, data) - def _confirm_send_action(self, widget, text, method, params={}): - + def _confirm_send_action(self, widget, text, method, params=None): + if params is None: + params = {} buttons = [ {"name": _("Continue"), "response": Gtk.ResponseType.OK}, {"name": _("Cancel"), "response": Gtk.ResponseType.CANCEL} ] try: - env = Environment(extensions=["jinja2.ext.i18n"]) + env = Environment(extensions=["jinja2.ext.i18n"], autoescape=True) env.install_gettext_translations(self.lang) j2_temp = env.from_string(text) text = j2_temp.render() @@ -900,21 +894,22 @@ class KlipperScreen(Gtk.Window): self.panels['splash_screen'].update_text(text) def search_power_devices(self, power_devices): - if self.connected_printer is not None: - found_devices = [] - devices = self.printer.get_power_devices() - logging.debug("Power devices: %s", devices) - if devices is not None: - for device in devices: - for power_device in power_devices: - if device == power_device and power_device not in found_devices: - found_devices.append(power_device) - if len(found_devices) > 0: - logging.info("Found %s", found_devices) - return found_devices - else: - logging.info("Power devices not found") - return None + if self.connected_printer is None: + return + found_devices = [] + devices = self.printer.get_power_devices() + logging.debug("Power devices: %s", devices) + if devices is not None: + for device in devices: + for power_device in power_devices: + if device == power_device and power_device not in found_devices: + found_devices.append(power_device) + if found_devices: + logging.info("Found %s", found_devices) + return found_devices + else: + logging.info("Power devices not found") + return None def power_on(self, widget, devices): @@ -928,14 +923,12 @@ class KlipperScreen(Gtk.Window): def init_printer(self): - state = self.apiclient.get_server_info() if state is False: return False - else: - # Moonraker is ready, set a loop to init the printer - self.reinit_count += 1 - self.init_printer_timeout = GLib.timeout_add_seconds(3, self.init_printer) + # Moonraker is ready, set a loop to init the printer + self.reinit_count += 1 + self.init_printer_timeout = GLib.timeout_add_seconds(3, self.init_printer) self.shutdown = False powerdevs = self.apiclient.send_request("machine/device_power/devices") @@ -944,31 +937,23 @@ class KlipperScreen(Gtk.Window): if state['result']['klippy_connected'] is False: self.panels['splash_screen'].update_text( - _("Moonraker: connected") + - "\n\nKlipper: %s\n\n" % state['result']['klippy_state'] + - _("Retry #%s") % self.reinit_count) + _("Moonraker: connected") + + f"\n\nKlipper: {state['result']['klippy_state']}\n\n" + + _("Retry #%s") % self.reinit_count + ) return False printer_info = self.apiclient.get_printer_info() if printer_info is False: - msg = "Unable to get printer info from moonraker" - logging.info(msg) - self.panels['splash_screen'].update_text(msg) - return False + return self._update_splash_screen("Unable to get printer info from moonraker") + data = self.apiclient.send_request("printer/objects/query?" + "&".join(PRINTER_BASE_STATUS_OBJECTS)) if data is False: - msg = "Error getting printer object data" - logging.info(msg) - self.panels['splash_screen'].update_text(msg) - return False - data = data['result']['status'] + return self._update_splash_screen("Error getting printer object data") config = self.apiclient.send_request("printer/objects/query?configfile") if config is False: - msg = "Error getting printer config data" - logging.info(msg) - self.panels['splash_screen'].update_text(msg) - return False + return self._update_splash_screen("Error getting printer config data") # Reinitialize printer, in case the printer was shut down and anything has changed. self.printer.reinit(printer_info['result'], config['result']['status']) @@ -983,10 +968,7 @@ class KlipperScreen(Gtk.Window): data = self.apiclient.send_request("printer/objects/query?" + "&".join(PRINTER_BASE_STATUS_OBJECTS + extra_items)) if data is False: - msg = "Error getting printer object data with extra items" - logging.info(msg) - self.panels['splash_screen'].update_text(msg) - return False + return self._update_splash_screen("Error getting printer object data with extra items") tempstore = self.apiclient.send_request("server/temperature_store") if tempstore is not False: @@ -1001,6 +983,11 @@ class KlipperScreen(Gtk.Window): self.reinit_count = 0 return False + def _update_splash_screen(self, msg): + logging.info(msg) + self.panels['splash_screen'].update_text(msg) + return False + def printer_ready(self): self.close_popup_message() @@ -1032,8 +1019,8 @@ class KlipperScreen(Gtk.Window): stderr=subprocess.PIPE, env=env) xid = int(p.stdout.readline()) - logging.debug("XID %s" % xid) - logging.debug("PID %s" % p.pid) + logging.debug(f"XID {xid}") + logging.debug(f"PID {p.pid}") keyboard = Gtk.Socket() box = Gtk.Box(orientation=Gtk.Orientation.VERTICAL) @@ -1093,7 +1080,7 @@ def main(): functions.patch_threading_excepthook() - logging.info("KlipperScreen version: %s" % version) + logging.info(f"KlipperScreen version: {version}") win = KlipperScreen(args, version) win.connect("destroy", Gtk.main_quit) diff --git a/styles/base.css b/styles/base.css index 7c63adda..d78db796 100644 --- a/styles/base.css +++ b/styles/base.css @@ -242,18 +242,6 @@ trough { min-height: 3em; } -.extruder-0 { - color: #ff0000; -} - -.extruder-1 { - color: #00ff00; -} - -.extruder-2 { - color: #0000ff; -} - .fan_slider { margin: 0 1em 0 1em; color: white;