From 3d6eed9d9526b77472ba7df29014b5768c594026 Mon Sep 17 00:00:00 2001 From: zkk <1007518571@qq.com> Date: Mon, 16 Dec 2024 16:33:34 +0800 Subject: [PATCH] =?UTF-8?q?=E5=96=B7=E5=A4=B4=E5=81=8F=E7=A7=BB=E5=80=BC?= =?UTF-8?q?=E6=A0=A1=E5=87=86=E5=8A=9F=E8=83=BD=E7=9A=84=E5=AE=9E=E7=8E=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- config/main_menu.conf | 5 + panels/nozzle_offset.py | 322 ++++++++++++++++++++++++++ panels/offset_fine_tune.py | 214 +++++++++++++++++ screen.py | 8 +- styles/dark/images/nozzle_offset.svg | 26 +++ styles/dark/images/offset_z.svg | 1 + styles/light/images/nozzle_offset.svg | 31 +++ styles/light/images/offset_z.svg | 1 + 8 files changed, 607 insertions(+), 1 deletion(-) create mode 100644 panels/nozzle_offset.py create mode 100644 panels/offset_fine_tune.py create mode 100644 styles/dark/images/nozzle_offset.svg create mode 100644 styles/dark/images/offset_z.svg create mode 100644 styles/light/images/nozzle_offset.svg create mode 100644 styles/light/images/offset_z.svg diff --git a/config/main_menu.conf b/config/main_menu.conf index ad9a637d..0958b535 100644 --- a/config/main_menu.conf +++ b/config/main_menu.conf @@ -34,6 +34,11 @@ name: {{ gettext('Z Calibrate') }} icon: z-farther panel: zcalibrate +[menu __main more nozzle_offset] +name: {{ gettext('Nozzle Offset') }} +icon: nozzle_offset +panel: nozzle_offset + [menu __main more limits] name: {{ gettext('Limits') }} icon: fine-tune diff --git a/panels/nozzle_offset.py b/panels/nozzle_offset.py new file mode 100644 index 00000000..3b1a4b86 --- /dev/null +++ b/panels/nozzle_offset.py @@ -0,0 +1,322 @@ +import logging + +import gi + +gi.require_version("Gtk", "3.0") +from gi.repository import Gtk, Pango + +from ks_includes.KlippyGcodes import KlippyGcodes +from ks_includes.screen_panel import ScreenPanel + + +class Panel(ScreenPanel): + widgets = {} + distances = [".01", ".05", ".1", ".5", "1", "5"] + distance = distances[-2] + + def __init__(self, screen, title): + title = title or _("Nozzle Offset") + super().__init__(screen, title) + + self.start_z_calibrate = False + self.z_hop_speed = 15.0 + self.z_hop = 5.0 + self.showing_input_box = False + + self.offset_data = [ + (_("Z Offset"), "z_offset_val", "0"), + (_("X Offset"), "x_offset_val", "0"), + (_("Y Offset"), "y_offset_val", "0"), + ] + + for label_text, offset_key, value_text in self.offset_data: + self.widgets[offset_key[:8]] = Gtk.Label(label=label_text) + self.widgets[offset_key] = Gtk.Label(label=value_text) + event_box = Gtk.EventBox() + event_box.add(self.widgets[offset_key]) + event_box.connect("button-release-event", self.change_offset, label_text, self.widgets[offset_key]) + setattr(self, f"{offset_key[0]}_event_box", event_box) + + pos = Gtk.Grid(row_homogeneous=True, column_homogeneous=True) + pos.attach(self.widgets["z_offset"], 0, 1, 2, 1) + pos.attach(self.z_event_box, 0, 2, 2, 1) + pos.attach(self.widgets["x_offset"], 0, 3, 1, 1) + pos.attach(self.x_event_box, 0, 4, 1, 1) + pos.attach(self.widgets["y_offset"], 1, 3, 1, 1) + pos.attach(self.y_event_box, 1, 4, 1, 1) + for label in pos.get_children(): + if isinstance(label, Gtk.Label): + label.set_ellipsize(Pango.EllipsizeMode.END) + self.buttons = { + "z+": self._gtk.Button("z-farther", _("Lower Bed"), "color4"), + "z-": self._gtk.Button("z-closer", _("Raise Bed"), "color1"), + "start_z_offset": self._gtk.Button("offset_z", _("Z offset Calibrate"), "color3"), + "start_xy_offset": self._gtk.Button("resume", _("XY offset Calibrate"), "color3"), + "complete": self._gtk.Button("complete", _("Save"), "color3"), + "cancel": self._gtk.Button("cancel", _("Cancel"), "color2"), + } + self.buttons["z+"].connect("clicked", self.move, "z", "+") + self.buttons["z-"].connect("clicked", self.move, "z", "-") + self.buttons["complete"].connect("clicked", self.accept) + script = {"script": "ABORT"} + self.buttons["cancel"].connect("clicked", self.cancel) + + self.popover = Gtk.Popover(position=Gtk.PositionType.BOTTOM) + script = {"script": "_NOZZLE_Z_OFFSET_CALIBRATE"} + self.buttons["start_z_offset"].connect("clicked", self.nozzle_z_offset) + script = {"script": "_NOZZLE_XY_OFFSET_CALIBRATE"} + self.buttons["start_xy_offset"].connect("clicked", self.nozzle_xy_offset) + + distgrid = Gtk.Grid() + for j, i in enumerate(self.distances): + self.widgets[i] = self._gtk.Button(label=i) + self.widgets[i].set_direction(Gtk.TextDirection.LTR) + self.widgets[i].connect("clicked", self.change_distance, i) + ctx = self.widgets[i].get_style_context() + ctx.add_class("horizontal_togglebuttons") + if i == self.distance: + ctx.add_class("horizontal_togglebuttons_active") + distgrid.attach(self.widgets[i], j, 0, 1, 1) + + 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) + + self.grid = Gtk.Grid(column_homogeneous=True) + if self._screen.vertical_mode: + if self._config.get_config()["main"].getboolean("invert_z", False): + self.grid.attach(self.buttons["z+"], 0, 1, 1, 1) + self.grid.attach(self.buttons["z-"], 0, 0, 1, 1) + else: + self.grid.attach(self.buttons["z+"], 0, 0, 1, 1) + self.grid.attach(self.buttons["z-"], 0, 1, 1, 1) + self.grid.attach(self.buttons["start_z_offset"], 1, 0, 1, 1) + self.grid.attach(pos, 1, 1, 2, 1) + self.grid.attach(self.buttons["start_xy_offset"], 2, 0, 1, 1) + self.grid.attach(self.buttons["complete"], 3, 0, 1, 1) + self.grid.attach(self.buttons["cancel"], 3, 1, 1, 1) + self.grid.attach(distances, 0, 2, 4, 1) + else: + if self._config.get_config()["main"].getboolean("invert_z", False): + self.grid.attach(self.buttons["z+"], 0, 2, 1, 1) + self.grid.attach(self.buttons["z-"], 0, 1, 1, 1) + else: + self.grid.attach(self.buttons["z+"], 0, 1, 1, 1) + self.grid.attach(self.buttons["z-"], 0, 2, 1, 1) + self.grid.attach(self.buttons["start_z_offset"], 0, 0, 2, 1) + self.grid.attach(self.buttons["start_xy_offset"], 2, 0, 2, 1) + self.grid.attach(pos, 1, 1, 2, 2) + self.grid.attach(self.buttons["complete"], 3, 1, 1, 1) + self.grid.attach(self.buttons["cancel"], 3, 2, 1, 1) + self.grid.attach(distances, 0, 3, 4, 1) + self.content.add(self.grid) + + def nozzle_z_offset(self, widget): + text = ( + _("Start testing the Z offset value of the second nozzle?\n") + + "\n\n" + + _("Please ensure that the Z Calibrate has been performed") + ) + label = Gtk.Label(wrap=True, vexpand=True) + label.set_markup(text) + buttons = [ + {"name": _("Accept"), "response": Gtk.ResponseType.OK, "style": "dialog-info"}, + {"name": _("Cancel"), "response": Gtk.ResponseType.CANCEL, "style": "dialog-error"}, + ] + self._gtk.Dialog(_("Calibrate Nozzle Z Offset"), buttons, label, self.confirm_nozzle_z_offset) + + def confirm_nozzle_z_offset(self, dialog, response_id): + self._gtk.remove_dialog(dialog) + if response_id == Gtk.ResponseType.OK: + self.start_z_calibrate = True + self.buttons_calibration_start() + self._screen._send_action( + self.buttons["start_z_offset"], "printer.gcode.script", {"script": "_NOZZLE_Z_OFFSET_CALIBRATE"} + ) + + def nozzle_xy_offset(self, widget): + text = ( + _("This operation is about to print the model") + + "\n\n" + + _("Please load two different colored PLA filaments!") + ) + + label = Gtk.Label(wrap=True, vexpand=True) + label.set_markup(text) + buttons = [ + {"name": _("Accept"), "response": Gtk.ResponseType.OK, "style": "dialog-info"}, + {"name": _("Cancel"), "response": Gtk.ResponseType.CANCEL, "style": "dialog-error"}, + ] + self._gtk.Dialog(_("Calibrate Nozzle XY Offset"), buttons, label, self.confirm_nozzle_xy_offset) + + def confirm_nozzle_xy_offset(self, dialog, response_id): + self._gtk.remove_dialog(dialog) + if response_id == Gtk.ResponseType.OK: + self._screen.offset_fine_tune_mode = True + self.buttons_calibration_start() + self._screen._send_action( + self.buttons["start_z_offset"], "printer.gcode.script", {"script": "_NOZZLE_XY_OFFSET_CALIBRATE"} + ) + + def change_offset(self, widget, event, title_label, offset_label): + self._create_input_box(title_label, offset_label) + + def _create_input_box(self, title_label, offset_label): + current_val = offset_label.get_text() + title_label += " " + _("Current value:") + f"{current_val}" + for child in self.content.get_children(): + self.content.remove(child) + lbl = Gtk.Label(label=title_label, halign=Gtk.Align.START, hexpand=False) + self.labels["entry"] = Gtk.Entry(hexpand=True) + self.labels["entry"].connect("focus-in-event", self._screen.show_keyboard) + save = self._gtk.Button("complete", _("Save"), "color3") + save.set_hexpand(False) + save.connect("clicked", self.store_value, offset_label) + box = Gtk.Box() + box.pack_start(self.labels["entry"], True, True, 5) + box.pack_start(save, False, False, 5) + self.labels["input_box"] = Gtk.Box( + orientation=Gtk.Orientation.VERTICAL, spacing=5, hexpand=True, vexpand=True, valign=Gtk.Align.CENTER + ) + self.labels["input_box"].pack_start(lbl, True, True, 5) + self.labels["input_box"].pack_start(box, True, True, 5) + self.content.add(self.labels["input_box"]) + self.labels["entry"].grab_focus_without_selecting() + self.showing_input_box = True + + def hide_input_box(self): + self._screen.remove_keyboard() + for child in self.content.get_children(): + self.content.remove(child) + self.content.add(self.grid) + self.content.show() + self.showing_input_box = False + + def store_value(self, widget, offset_label): + val_text = self.labels["entry"].get_text() + try: + val = round(float(val_text), 3) + name = None + for label_text, offset_key, _ in self.offset_data: + if offset_label == self.widgets[offset_key]: + name = offset_key + break + if name is not None: + name = "nozzle_" + name + self.set_nozzle_offset(name, val) + if self.showing_input_box: + self.hide_input_box() + except ValueError: + self._screen.show_popup_message(_("Please enter a valid number")) + + def set_nozzle_offset(self, option, value): + script = KlippyGcodes.set_save_variables(option, value) + self._screen._send_action(None, "printer.gcode.script", {"script": script}) + logging.info(f"Set {option}:{value}") + + def back(self): + if self.showing_input_box: + self.hide_input_box() + return True + return False + + def _add_button(self, label, method, pobox): + popover_button = self._gtk.Button(label=label) + pobox.pack_start(popover_button, True, True, 5) + + def on_popover_clicked(self, widget): + self.popover.set_relative_to(widget) + self.popover.show_all() + + def activate(self): + is_sensitive = self.buttons["start_z_offset"].get_sensitive() + if is_sensitive: + self.buttons_not_z_calibration() + else: + self.buttons_calibration_start() + + def deactivate(self): + if self.start_z_calibrate: + self.start_z_calibrate = False + + def process_update(self, action, data): + + if action == "notify_gcode_response": + if self.start_z_calibrate and "extruder1" in data: + self.buttons_z_calibration() + elif "action:resumed" in data: + return + if action != "notify_status_update": + return + if "save_variables" in data and "variables" in data["save_variables"]: + variables = data["save_variables"]["variables"] + nozzle_offsets = ["nozzle_z_offset_val", "nozzle_x_offset_val", "nozzle_y_offset_val"] + + for offset in nozzle_offsets: + if offset in variables: + self.widgets[f'{offset.split("_")[1]}_offset_val'].set_text(f"{variables[offset]}") + + if "gcode_move" in data or "toolhead" in data and "homed_axes" in data["toolhead"]: + homed_axes = self._printer.get_stat("toolhead", "homed_axes") + + if "z" in homed_axes: + self.pos_z = round(data["gcode_move"]["gcode_position"][2], 3) + if self.start_z_calibrate: + self.widgets["z_offset_val"].set_text(f"{self.pos_z}") + + def change_distance(self, widget, distance): + logging.info(f"### Distance {distance}") + self.widgets[f"{self.distance}"].get_style_context().remove_class("horizontal_togglebuttons_active") + self.widgets[f"{distance}"].get_style_context().add_class("horizontal_togglebuttons_active") + self.distance = distance + + def move(self, widget, axis, direction): + dist = f"{direction}{self.distance}" + script = f"{KlippyGcodes.MOVE_RELATIVE}\nG0 {axis}{dist} F300" + self._screen._send_action(widget, "printer.gcode.script", {"script": script}) + if self._printer.get_stat("gcode_move", "absolute_coordinates"): + self._screen._ws.klippy.gcode_script("G90") + + def accept(self, widget): + logging.info("Accepting nozzle Z offset") + script = f"SET_GCODE_OFFSET Z={self.pos_z}" + self._screen._send_action(None, "printer.gcode.script", {"script": script}) + script = f"G91\n G0 Z5 F6000" + self._screen._send_action(None, "printer.gcode.script", {"script": script}) + + self.set_nozzle_offset("nozzle_z_offset_val", self.pos_z) + self.buttons_not_z_calibration() + self.start_z_calibrate = False + + def cancel(self, widget): + self.start_z_calibrate = False + self.buttons_not_z_calibration() + variables = self._printer.get_stat("save_variables", "variables") + if "nozzle_z_offset_val" in variables: + self.widgets["z_offset_val"].set_text(f"{variables['nozzle_z_offset_val']}") + + def buttons_calibration_start(self): + self.buttons["start_z_offset"].set_sensitive(False) + self.buttons["start_xy_offset"].set_sensitive(False) + + self.buttons["z+"].set_sensitive(False) + self.buttons["z-"].set_sensitive(False) + self.buttons["complete"].set_sensitive(False) + self.buttons["cancel"].set_sensitive(False) + + def buttons_z_calibration(self): + self.buttons["start_z_offset"].set_sensitive(False) + self.buttons["start_xy_offset"].set_sensitive(False) + self.buttons["z+"].set_sensitive(True) + self.buttons["z-"].set_sensitive(True) + self.buttons["complete"].set_sensitive(True) + self.buttons["cancel"].set_sensitive(True) + + def buttons_not_z_calibration(self): + self.buttons["start_z_offset"].set_sensitive(True) + self.buttons["start_xy_offset"].set_sensitive(True) + self.buttons["z+"].set_sensitive(False) + self.buttons["z-"].set_sensitive(False) + self.buttons["complete"].set_sensitive(False) + self.buttons["cancel"].set_sensitive(False) diff --git a/panels/offset_fine_tune.py b/panels/offset_fine_tune.py new file mode 100644 index 00000000..e479096b --- /dev/null +++ b/panels/offset_fine_tune.py @@ -0,0 +1,214 @@ +import re +import logging +import gi + +gi.require_version("Gtk", "3.0") +from gi.repository import Gtk +from ks_includes.KlippyGcodes import KlippyGcodes +from ks_includes.screen_panel import ScreenPanel + + +class Panel(ScreenPanel): + distances = [".01", ".05", "0.1"] + distance = distances[-2] + + def __init__(self, screen, title): + title = title or _("offset fine tune") + super().__init__(screen, title) + + self.state = "standby" + + if self.ks_printer_cfg is not None: + dis = self.ks_printer_cfg.get("move_distances", "") + if re.match(r"^[0-9,\.\s]+$", dis): + dis = [str(i.strip()) for i in dis.split(",")] + if 1 < len(dis) <= 7: + self.distances = dis + self.distance = self.distances[-2] + + self.labels["qr_code_box"] = Gtk.Grid(row_homogeneous=True, column_homogeneous=True) + qr_code = self._gtk.Image("wiki_qr_code", self._gtk.content_width * 0.46, self._gtk.content_height * 0.46) + qr_code_url = Gtk.Label(label="https://www.creatbot.com/en/faqs.html") + self.labels["qr_code_box"].attach(qr_code, 0, 0, 1, 3) + self.labels["qr_code_box"].attach(qr_code_url, 0, 2, 1, 1) + + self.action_btn = {} + self.action_btn["fine_tune"] = self._gtk.Button("fine-tune", scale=0.7) + self.action_btn["pause"] = self._gtk.Button("pause", scale=0.8) + self.action_btn["resume"] = self._gtk.Button("resume", scale=0.8) + self.action_btn["stop"] = self._gtk.Button("stop", scale=0.8) + + self.action_btn["fine_tune"].connect("clicked", self.menu_item_clicked, {"panel": "fine_tune"}) + self.action_btn["pause"].connect("clicked", self.pause) + self.action_btn["resume"].connect("clicked", self.resume) + self.action_btn["stop"].connect("clicked", self.cancel) + + self.labels["action_menu"] = Gtk.Grid(row_homogeneous=True, column_homogeneous=True) + self.labels["action_menu"].attach(self.action_btn["pause"], 0, 0, 1, 1) + self.labels["action_menu"].attach(self.action_btn["stop"], 1, 0, 1, 1) + self.labels["action_menu"].attach(self.action_btn["fine_tune"], 2, 0, 1, 1) + + self.buttons = { + "x+": self._gtk.Button("arrow-right", "X+", "color1"), + "x-": self._gtk.Button("arrow-left", "X-", "color1"), + "y+": self._gtk.Button("arrow-up", "Y+", "color2"), + "y-": self._gtk.Button("arrow-down", "Y-", "color2"), + "z+": self._gtk.Button("z-farther", "Z+", "color3"), + "z-": self._gtk.Button("z-closer", "Z-", "color3"), + } + self.buttons["x+"].connect("clicked", self.move, "X", "+") + self.buttons["x-"].connect("clicked", self.move, "X", "-") + self.buttons["y+"].connect("clicked", self.move, "Y", "+") + self.buttons["y-"].connect("clicked", self.move, "Y", "-") + self.buttons["z+"].connect("clicked", self.move, "Z", "+") + self.buttons["z-"].connect("clicked", self.move, "Z", "-") + + grid = Gtk.Grid(row_homogeneous=True, column_homogeneous=True) + if self._screen.vertical_mode: + if self._screen.lang_ltr: + grid.attach(self.buttons["x+"], 2, 1, 1, 1) + grid.attach(self.buttons["x-"], 0, 1, 1, 1) + grid.attach(self.buttons["z+"], 2, 2, 1, 1) + grid.attach(self.buttons["z-"], 0, 2, 1, 1) + else: + grid.attach(self.buttons["x+"], 0, 1, 1, 1) + grid.attach(self.buttons["x-"], 2, 1, 1, 1) + grid.attach(self.buttons["z+"], 0, 2, 1, 1) + grid.attach(self.buttons["z-"], 2, 2, 1, 1) + + grid.attach(self.buttons["y+"], 1, 0, 1, 1) + grid.attach(self.buttons["y-"], 1, 2, 1, 1) + + else: + if self._screen.lang_ltr: + grid.attach(self.buttons["x+"], 2, 1, 1, 1) + grid.attach(self.buttons["x-"], 0, 1, 1, 1) + else: + grid.attach(self.buttons["x+"], 0, 1, 1, 1) + grid.attach(self.buttons["x-"], 2, 1, 1, 1) + grid.attach(self.buttons["y+"], 1, 0, 1, 1) + grid.attach(self.buttons["y-"], 1, 2, 1, 1) + grid.attach(self.buttons["z-"], 3, 0, 1, 1) + grid.attach(self.buttons["z+"], 3, 2, 1, 1) + + distgrid = Gtk.Grid() + for j, i in enumerate(self.distances): + self.labels[i] = self._gtk.Button(label=i) + self.labels[i].set_direction(Gtk.TextDirection.LTR) + self.labels[i].connect("clicked", self.change_distance, i) + ctx = self.labels[i].get_style_context() + ctx.add_class("horizontal_togglebuttons") + if i == self.distance: + ctx.add_class("horizontal_togglebuttons_active") + distgrid.attach(self.labels[i], j, 0, 1, 1) + + for p in ("x_offset_val", "y_offset_val", "z_offset_val"): + self.labels[p] = Gtk.Label(f"{p[0].upper()} " + _("Offset") + ": 0") + self.labels["move_dist"] = Gtk.Label(label=_("Move Distance (mm)")) + + bottomgrid = Gtk.Grid(row_homogeneous=True, column_homogeneous=True) + bottomgrid.set_direction(Gtk.TextDirection.LTR) + bottomgrid.attach(self.labels["x_offset_val"], 0, 0, 1, 1) + bottomgrid.attach(self.labels["y_offset_val"], 1, 0, 1, 1) + bottomgrid.attach(self.labels["z_offset_val"], 2, 0, 1, 1) + bottomgrid.attach(self.labels["move_dist"], 0, 1, 3, 1) + + self.labels["move_menu"] = Gtk.Grid(row_homogeneous=True, column_homogeneous=True) + self.labels["move_menu"].attach(self.labels["qr_code_box"], 0, 0, 2, 4) + self.labels["move_menu"].attach(grid, 2, 0, 2, 3) + self.labels["move_menu"].attach(bottomgrid, 2, 3, 2, 1) + self.labels["move_menu"].attach(distgrid, 2, 4, 2, 1) + self.labels["move_menu"].attach(self.labels["action_menu"], 0, 4, 2, 1) + + self.content.add(self.labels["move_menu"]) + + def process_update(self, action, data): + if action != "notify_status_update": + return + if "save_variables" in data and "variables" in data["save_variables"]: + variables = data["save_variables"]["variables"] + nozzle_offsets = ["nozzle_z_offset_val", "nozzle_x_offset_val", "nozzle_y_offset_val"] + + for offset in nozzle_offsets: + if offset in variables: + axis = offset.split("_")[1] + self.labels[f"{axis}_offset_val"].set_text( + f"{axis.upper()} " + _("Offset") + f": {variables[offset]}" + ) + if "print_stats" in data: + if "state" in data["print_stats"]: + self.state = data["print_stats"]["state"] + self.show_buttons_for_state() + + def pause(self, widget): + self.disable_button("pause") + self._screen._ws.klippy.print_pause() + self._screen.show_all() + + def resume(self, widget): + self.disable_button("resume") + self._screen._ws.klippy.print_resume() + self._screen.show_all() + + def cancel(self, widget): + buttons = [ + {"name": _("Cancel Print"), "response": Gtk.ResponseType.OK, "style": "dialog-error"}, + {"name": _("Go Back"), "response": Gtk.ResponseType.CANCEL, "style": "dialog-info"}, + ] + label = Gtk.Label(hexpand=True, vexpand=True, wrap=True) + label.set_markup(_("Are you sure you wish to cancel this test?")) + self._gtk.Dialog(_("Cancel"), buttons, label, self.cancel_confirm) + + def cancel_confirm(self, dialog, response_id): + self._gtk.remove_dialog(dialog) + if response_id == Gtk.ResponseType.OK: + self.disable_button("pause", "resume", "stop", "fine_tune") + self._screen._ws.klippy.print_cancel() + logging.debug("Canceling print test") + return + if response_id == Gtk.ResponseType.CANCEL: + self.enable_button("pause", "stop", "fine_tune") + return + + def disable_button(self, *args): + for arg in args: + self.action_btn[arg].set_sensitive(False) + + def show_buttons_for_state(self): + self.labels["action_menu"].remove_row(0) + self.labels["action_menu"].insert_row(0) + if self.state == "paused": + self.labels["action_menu"].attach(self.action_btn["resume"], 0, 0, 1, 1) + self.labels["action_menu"].attach(self.action_btn["stop"], 1, 0, 1, 1) + self.labels["action_menu"].attach(self.action_btn["fine_tune"], 2, 0, 1, 1) + else: + self.labels["action_menu"].attach(self.action_btn["pause"], 0, 0, 1, 1) + self.labels["action_menu"].attach(self.action_btn["stop"], 1, 0, 1, 1) + self.labels["action_menu"].attach(self.action_btn["fine_tune"], 2, 0, 1, 1) + self.content.show_all() + + def change_distance(self, widget, distance): + logging.info(f"### Distance {distance}") + self.labels[f"{self.distance}"].get_style_context().remove_class("horizontal_togglebuttons_active") + self.labels[f"{distance}"].get_style_context().add_class("horizontal_togglebuttons_active") + self.distance = distance + + def move(self, widget, axis, direction): + axis = axis.lower() + offset_name = f"nozzle_{axis}_offset_val" + data = self._printer.data + last_val = 0 + if "save_variables" in data and "variables" in data["save_variables"]: + variables = data["save_variables"]["variables"] + last_val = variables.get(offset_name, 0) + try: + expression = f"{last_val} {direction} {self.distance}" + result = eval(expression) + self.set_nozzle_offset(offset_name, round(float(result), 2)) + except Exception as e: + logging.error(f"Error setting {offset_name}: eval failed with expression '{expression}'. Exception: {e}") + + def set_nozzle_offset(self, option, value): + script = KlippyGcodes.set_save_variables(option, value) + self._screen._send_action(None, "printer.gcode.script", {"script": script}) + logging.info(f"Set {option}:{value}") diff --git a/screen.py b/screen.py index 99562310..67b3dcc5 100755 --- a/screen.py +++ b/screen.py @@ -83,6 +83,7 @@ class KlipperScreen(Gtk.Window): GLib.set_prgname('KlipperScreen') self.blanking_time = 600 self.use_dpms = True + self.offset_fine_tune_mode = False self.apiclient = None self.dialogs = [] self.confirm = None @@ -780,7 +781,10 @@ class KlipperScreen(Gtk.Window): self.show_panel("extrude") def state_printing(self): - self.show_panel("job_status", remove_all=True) + if not self.offset_fine_tune_mode: + self.show_panel("job_status", remove_all=True) + else: + self.show_panel("offset_fine_tune", remove_all=True) def state_ready(self, wait=True): # Do not return to main menu if completing a job, timeouts/user input will return @@ -797,6 +801,8 @@ class KlipperScreen(Gtk.Window): else: self.show_panel("main_menu", remove_all=True, items=self._config.get_menu_items("__main")) self._ws.klippy.gcode_script("UPDATE_DELAYED_GCODE ID=_CHECK_POWER_LOSS_RECOVERY DURATION=0.1") + if self.offset_fine_tune_mode: + self.offset_fine_tune_mode = False def state_startup(self): self.printer_initializing(_("Klipper is attempting to start")) diff --git a/styles/dark/images/nozzle_offset.svg b/styles/dark/images/nozzle_offset.svg new file mode 100644 index 00000000..fffa9b85 --- /dev/null +++ b/styles/dark/images/nozzle_offset.svg @@ -0,0 +1,26 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/styles/dark/images/offset_z.svg b/styles/dark/images/offset_z.svg new file mode 100644 index 00000000..e1822abd --- /dev/null +++ b/styles/dark/images/offset_z.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/styles/light/images/nozzle_offset.svg b/styles/light/images/nozzle_offset.svg new file mode 100644 index 00000000..f422b836 --- /dev/null +++ b/styles/light/images/nozzle_offset.svg @@ -0,0 +1,31 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/styles/light/images/offset_z.svg b/styles/light/images/offset_z.svg new file mode 100644 index 00000000..e1822abd --- /dev/null +++ b/styles/light/images/offset_z.svg @@ -0,0 +1 @@ + \ No newline at end of file