diff --git a/ks_includes/config.py b/ks_includes/config.py index 71d17cc4..b3006911 100644 --- a/ks_includes/config.py +++ b/ks_includes/config.py @@ -161,7 +161,7 @@ class KlipperScreenConfig: bools = ( 'invert_x', 'invert_y', 'invert_z', '24htime', 'only_heaters', 'show_cursor', 'confirm_estop', 'autoclose_popups', 'use_dpms', 'use_default_menu', 'side_macro_shortcut', 'use-matchbox-keyboard', - 'show_heater_power', "show_scroll_steppers", "auto_open_extrude" + 'show_heater_power', "show_scroll_steppers", "auto_open_extrude" , 'onboarding' ) strs = ( 'default_printer', 'language', 'print_sort_dir', 'theme', 'screen_blanking_printing', 'font_size', @@ -319,6 +319,7 @@ class KlipperScreenConfig: {"print_sort_dir": {"section": "main", "type": None, "value": "name_asc"}}, {"print_view": {"section": "main", "type": None, "value": "thumbs"}}, {"language": {"section": "main", "name": _("Language"), "type": None, "value": "system_lang"}}, + {"onboarding": {"section": "main", "type": None, "value": "False"}}, ] self.configurable_options.extend(panel_options) diff --git a/panels/base_panel.py b/panels/base_panel.py index 38fc0906..00bf3f55 100644 --- a/panels/base_panel.py +++ b/panels/base_panel.py @@ -30,11 +30,12 @@ class BasePanel(ScreenPanel): self.control['back'].set_no_show_all(True) self.control['home'] = self._gtk.Button('main', scale=abscale) self.control['home'].connect("clicked", self._screen._menu_go_back, True) + self.control['home'].set_no_show_all(True) self.move = { "panel": "move", } self.control['move'] = self._gtk.Button('move', scale=abscale) - self.control['move'].connect("clicked", self.menu_item_clicked, self.move) + self.control['move'].connect("clicked", self.menu_item_clicked, self.move) self.control['move'].set_no_show_all(True) self.extrude = { "panel": "extrude", @@ -82,7 +83,6 @@ class BasePanel(ScreenPanel): self.action_bar.set_hexpand(False) self.action_bar.set_vexpand(True) self.action_bar.get_style_context().add_class('action_bar') - self.action_bar.set_size_request(self._gtk.action_bar_width, self._gtk.action_bar_height) self.action_bar.add(self.control['back']) self.action_bar.add(self.control['home']) self.action_bar.add(self.control['move']) @@ -229,10 +229,15 @@ class BasePanel(ScreenPanel): panels_has_back = ['gcodes', 'temperature'] cur_panel_count = len(self._screen._cur_panels) is_last_panel_in_back_list = self._screen._cur_panels[-1] in panels_has_back - if cur_panel_count > 2 or is_last_panel_in_back_list: - self.control['back'].set_visible(True) + + should_show_back = (cur_panel_count > 2 or is_last_panel_in_back_list or + (self._screen._cur_panels[0] != 'main_menu' and cur_panel_count >= 2)) + self.control['back'].set_visible(should_show_back) + if any(child.get_visible() for child in self.action_bar.get_children()): + self.show_action_bar() else: - self.control['back'].set_visible(False) + self.hide_action_bar() + self.current_panel = panel self.set_title(panel.title) self.content.add(panel.content) @@ -321,7 +326,7 @@ class BasePanel(ScreenPanel): def set_control_sensitive(self, value=True, control='home'): self.control[control].set_sensitive(value) - + def show_shortcut(self, show=True): show = ( show @@ -335,6 +340,14 @@ class BasePanel(ScreenPanel): self.set_control_sensitive(self._screen._cur_panels[-1] != self.files['panel'], control='files') self.set_control_sensitive(self._screen._cur_panels[-1] != self.more['panel'], control='more') + def show_action_bar(self): + self.action_bar.set_size_request(self._gtk.action_bar_width, self._gtk.action_bar_height) + self.control['home'].set_visible(True) + + def hide_action_bar(self): + self.action_bar.set_size_request(-1, -1) + self.control['home'].set_visible(False) + def show_printer_select(self, show=True): self.control['printer_select'].set_visible( show and 'printer_select' not in self._screen._cur_panels diff --git a/panels/gcodes.py b/panels/gcodes.py index 771251bd..987e75de 100644 --- a/panels/gcodes.py +++ b/panels/gcodes.py @@ -67,6 +67,7 @@ class Panel(ScreenPanel): self.loading_msg = _('Loading...') self.labels['path'] = Gtk.Label(label=self.loading_msg, vexpand=True, no_show_all=True) + self.labels['path'].set_ellipsize(Pango.EllipsizeMode.END) self.labels['path'].show() self.thumbsize = self._gtk.img_scale * self._gtk.button_image_scale * 2.5 logging.info(f"Thumbsize: {self.thumbsize}") diff --git a/panels/job_status.py b/panels/job_status.py index 2b8cf420..515afa6a 100644 --- a/panels/job_status.py +++ b/panels/job_status.py @@ -166,7 +166,7 @@ class Panel(ScreenPanel): 'extra': extruder}) self.buttons['extruder'][extruder].set_halign(Gtk.Align.START) - self.labels['temp_grid'] = Gtk.Grid() + self.labels['temp_grid'] = Gtk.Grid(column_homogeneous=True) nlimit = 3 if self._screen.width <= 500 else 4 n = 0 if nlimit > 2 and len(self._printer.get_tools()) == 2: @@ -179,6 +179,7 @@ class Panel(ScreenPanel): self.labels['temp_grid'].attach(self.buttons['extruder'][self.current_extruder], n, 0, 1, 1) n += 1 self.buttons['heater'] = {} + n = 0 for dev in self._printer.get_heaters(): if n >= nlimit: break @@ -194,7 +195,7 @@ class Panel(ScreenPanel): self.buttons['heater'][dev].connect("clicked", self.menu_item_clicked, {"panel": "numpad", "extra": dev}) self.buttons['heater'][dev].set_halign(Gtk.Align.START) - self.labels['temp_grid'].attach(self.buttons['heater'][dev], n, 0, 1, 1) + self.labels['temp_grid'].attach(self.buttons['heater'][dev], n, 1, 1, 1) n += 1 extra_item = not self._show_heater_power if self.ks_printer_cfg is not None: @@ -218,7 +219,7 @@ class Panel(ScreenPanel): self.buttons['heater'][device].connect("clicked", self.menu_item_clicked, {"panel": "numpad"}) self.buttons['heater'][device].set_halign(Gtk.Align.START) - self.labels['temp_grid'].attach(self.buttons['heater'][device], n, 0, 1, 1) + self.labels['temp_grid'].attach(self.buttons['heater'][device], n, 1, 1, 1) n += 1 break @@ -232,10 +233,10 @@ class Panel(ScreenPanel): info = Gtk.Grid(row_homogeneous=True) info.get_style_context().add_class("printing-info") - info.attach(self.labels['temp_grid'], 0, 0, 1, 1) - info.attach(szfe, 0, 1, 1, 2) - info.attach(self.buttons['elapsed'], 0, 3, 1, 1) - info.attach(self.buttons['left'], 0, 4, 1, 1) + info.attach(self.labels['temp_grid'], 0, 0, 1, 2) + info.attach(szfe, 0, 2, 1, 2) + info.attach(self.buttons['elapsed'], 0, 4, 1, 1) + info.attach(self.buttons['left'], 0, 5, 1, 1) self.status_grid = info def create_extrusion_grid(self, widget=None): diff --git a/panels/language_select.py b/panels/language_select.py new file mode 100644 index 00000000..296ae123 --- /dev/null +++ b/panels/language_select.py @@ -0,0 +1,61 @@ +import logging +import gi + +gi.require_version("Gtk", "3.0") +from gi.repository import Gtk, GLib +from ks_includes.screen_panel import ScreenPanel + +class Panel(ScreenPanel): + def __init__(self, screen, title): + title = title or "Select Language" + super().__init__(screen, title) + self.language_map = { + 'cs': 'Čeština', + 'da': 'Dansk', + 'de': 'Deutsch', + 'de_formal': 'Höfliches Deutsch', + 'en': 'English', + 'es': 'Español', + 'et': 'Eesti', + 'fr': 'Français', + 'he': 'עברית', + 'hu': 'Magyar', + 'it': 'Italiano', + 'jp': '日本語', + 'ko': '한국어', + 'lt': 'Lietuvių', + 'nl': 'Nederlands', + 'pl': 'Polski', + 'pt': 'Português', + 'pt_BR': 'Português (Brasil)', + 'ru': 'Русский', + 'sl': 'Slovenščina', + 'sv': 'Svenska', + 'tr': 'Türkçe', + 'uk': 'Українська', + 'vi': 'Tiếng Việt', + 'zh_CN': '简体中文', + 'zh_TW': '繁體中文', + } + self.langs = {} + self.labels['lang_menu'] = self._gtk.ScrolledWindow() + self.labels['lang'] = Gtk.Grid() + self.labels['lang_menu'].add(self.labels['lang']) + self.labels['lang'].set_margin_start(50) + for lang in self._config.lang_list: + name = self.language_map.get(lang) + if name: + self.langs[lang] = { + "name": name, + "type": "button", + "callback": self.change_language, + } + self.add_option("lang", self.langs, lang, self.langs[lang]) + self.content.add(self.labels["lang_menu"]) + self.content.show_all() + + def change_language(self, widget, lang): + reverse_language_map = {v: k for k, v in self.language_map.items()} + language_code = reverse_language_map.get(lang, 'en') + self._screen.change_language(widget, language_code) + self._screen.initial_connection() diff --git a/panels/onboarding.py b/panels/onboarding.py new file mode 100644 index 00000000..3c1daf54 --- /dev/null +++ b/panels/onboarding.py @@ -0,0 +1,69 @@ +import logging +import os +import gi + +gi.require_version("Gtk", "3.0") +from gi.repository import Gtk, Pango +from ks_includes.screen_panel import ScreenPanel + + +class Panel(ScreenPanel): + + def __init__(self, screen, title): + title = title or _('Welcome') + super().__init__(screen, title) + + buttons = [ + {"name": _("Next"), "response": Gtk.ResponseType.YES, "style": 'dialog-secondary'} + ] + + image = self._gtk.Image( + "retainer", self._gtk.content_width * 0.3, self._gtk.content_height * 0.5 + ) + start_text = _("1. For first use, refer to the accompanying diagram to disassemble the fixed components of the X, Y, and Z axes.") + space = "\n\n" + end_text = _("2. Once the disassembly is complete, click the 'Next' button to proceed.") + label = Gtk.Label(hexpand=True, vexpand=True, wrap=True, wrap_mode=Pango.WrapMode.WORD_CHAR) + label.set_markup(f"{start_text + space + end_text}\n") + box = Gtk.Box(orientation=Gtk.Orientation.HORIZONTAL, vexpand=True) + image.set_margin_start(60) + image.set_margin_top(80) + box.pack_start(image, False, True, 0) + box.pack_start(label, False, False, 20) + + self._gtk.Dialog(f'Welcome', buttons, box, self.confirm_print_response) + + def create_raise_platform(self): + buttons = [ + {"name": _("Raise Platform"), "response": Gtk.ResponseType.OK}, + {"name": _("Finish"), "response": Gtk.ResponseType.APPLY, "style": 'dialog-secondary'} + ] + + image = self._gtk.Image( + "take_out", self._gtk.content_width * 0.3, self._gtk.content_height * 0.5 + ) + + start_text = _("1. Ensure that all fixed components have been properly removed before proceeding.") + center_text = _("2. Press the 'Raise Platform' button to lift the platform and remove the items underneath.") + end_text = _("3. Once the operation is complete, click the \'Finish\' button to conclude the process.") + space = "\n\n" + label = Gtk.Label(hexpand=True, vexpand=True, wrap=True, wrap_mode=Pango.WrapMode.WORD_CHAR) + label.set_markup(f"{start_text + space + center_text + space + end_text}\n") + box = Gtk.Box(orientation=Gtk.Orientation.HORIZONTAL, vexpand=True) + image.set_margin_start(60) + image.set_margin_top(80) + box.pack_start(image, False, True, 0) + box.pack_start(label, False, False, 20) + + self._gtk.Dialog(f'Test', buttons, box, self.confirm_print_response) + + def confirm_print_response(self, dialog, response_id): + if response_id == Gtk.ResponseType.YES: + self._gtk.remove_dialog(dialog) + self.create_raise_platform() + elif response_id == Gtk.ResponseType.OK: + self._screen._ws.klippy.gcode_script("SET_KINEMATIC_POSITION Z=5\nG28") + elif response_id == Gtk.ResponseType.APPLY: + self._screen.show_panel("main_menu", remove_all=True, items=self._config.get_menu_items("__main")) + self._config.set("main", "onboarding", "False") + self._config.save_user_config_options() diff --git a/panels/settings.py b/panels/settings.py index 09bc678b..5b0f6d05 100644 --- a/panels/settings.py +++ b/panels/settings.py @@ -24,15 +24,50 @@ class Panel(ScreenPanel): name = list(option)[0] self.add_option('settings', self.settings, name, option[name]) + self.language_map = { + 'cs': 'Čeština', + 'da': 'Dansk', + 'de': 'Deutsch', + 'de_formal': 'Höfliches Deutsch', + 'en': 'English', + 'es': 'Español', + 'et': 'Eesti', + 'fr': 'Français', + 'he': 'עברית', + 'hu': 'Magyar', + 'it': 'Italiano', + 'jp': '日本語', + 'ko': '한국어', + 'lt': 'Lietuvių', + 'nl': 'Nederlands', + 'pl': 'Polski', + 'pt': 'Português', + 'pt_BR': 'Português (Brasil)', + 'ru': 'Русский', + 'sl': 'Slovenščina', + 'sv': 'Svenska', + 'tr': 'Türkçe', + 'uk': 'Українська', + 'vi': 'Tiếng Việt', + 'zh_CN': '简体中文', + 'zh_TW': '繁體中文', + } + self.labels['lang_menu'] = self._gtk.ScrolledWindow() self.labels['lang'] = Gtk.Grid() self.labels['lang_menu'].add(self.labels['lang']) - for lang in ["system_lang", *self._config.lang_list]: + for lang in self._config.lang_list: + name = self.language_map.get(lang) self.langs[lang] = { - "name": lang, + "name": name, "type": "button", - "callback": self._screen.change_language, + "callback": self.change_language, } self.add_option("lang", self.langs, lang, self.langs[lang]) self.content.add(self.labels['settings_menu']) + + def change_language(self, widget, lang): + reverse_language_map = {v: k for k, v in self.language_map.items()} + language_code = reverse_language_map.get(lang, 'en') + self._screen.change_language(widget, language_code) \ No newline at end of file diff --git a/panels/splash_screen.py b/panels/splash_screen.py index da0352b8..4c8f4a36 100644 --- a/panels/splash_screen.py +++ b/panels/splash_screen.py @@ -50,7 +50,7 @@ class Panel(ScreenPanel): scroll.add(self.labels["text"]) info = Gtk.Box() - info.pack_start(image, False, True, 8) + info.pack_start(image, False, True, 50) info.pack_end(scroll, True, True, 8) main = Gtk.Box(orientation=Gtk.Orientation.VERTICAL) diff --git a/panels/system.py b/panels/system.py index 9b57bbf7..e0f53e9e 100644 --- a/panels/system.py +++ b/panels/system.py @@ -17,6 +17,8 @@ class Panel(ScreenPanel): self.current_row = 0 self.mem_multiplier = None self.model_config = None + self.info_panel = None + self.select_model = False self.scales = {} self.labels = {} self.models = {} @@ -34,15 +36,20 @@ class Panel(ScreenPanel): screen.printer.system_info = self.sysinfo['system_info'] self.sysinfo = self.sysinfo['system_info'] logging.debug(self.sysinfo) + if self.sysinfo: - self.content.add(self.create_layout()) + self.info_panel = self.create_layout() else: self.content.add(Gtk.Label(label=_("No info available"), vexpand=True)) def back(self): + if self.select_model: + self.hide_select_model() + return True if not self.sysinfo: self._screen.panels_reinit.append("system") return False + def create_layout(self): self.labels["cpu_usage"] = Gtk.Label(label="", xalign=0) self.grid.attach(self.labels["cpu_usage"], 0, self.current_row, 1, 1) @@ -70,6 +77,11 @@ class Panel(ScreenPanel): scroll = self._gtk.ScrolledWindow() scroll.add(self.grid) self.content.add(scroll) + return scroll + + def create_select_model(self): + if "model_menu" in self.labels: + return if self.model_config is None: self.model_config = ModelConfig() self.labels["model_menu"] = self._gtk.ScrolledWindow() @@ -91,9 +103,10 @@ class Panel(ScreenPanel): self.add_option( "model", self.models, model_name, self.models[model_name] ) - return scroll + def change_model(self, widget, event): self.model_config.generate_config(event) + def on_model_click(self, widget, event): current_time = time.time() if (current_time - self.last_click_time) <= self.click_threshold: @@ -101,9 +114,22 @@ class Panel(ScreenPanel): else: self.click_count = 0 self.last_click_time = current_time - if self.click_count == self.target_clicks: + if self.click_count >= self.target_clicks: + for child in self.content.get_children(): + self.content.remove(child) self.click_count = 0 - self.load_menu(self, "model", _("model select")) + self.create_select_model() + self.content.add(self.labels["model_menu"]) + self.content.show_all() + self.select_model = True + + def hide_select_model(self): + for child in self.content.get_children(): + self.content.remove(child) + if self.info_panel: + self.content.add(self.info_panel) + self.content.show_all() + self.select_model = False def set_mem_multiplier(self, data): memory_units = data.get("memory_units", "kB").lower() @@ -122,12 +148,13 @@ class Panel(ScreenPanel): label = Gtk.Label(label=text, use_markup=True, xalign=0, wrap=True) self.grid.attach(label, column, self.current_row, 1, 1) self.current_row += 1 + def machine_info(self): self.add_label_to_grid(self.prettify("device"), 0, bold=True) self.current_row -= 1 self.add_label_to_grid("Maker: CreatBot", 1) event_box = Gtk.EventBox() - event_box.connect("button-press-event", self.on_model_click) + event_box.connect("button-release-event", self.on_model_click) mode = self._screen.connecting_to_printer.split("-")[0] label = Gtk.Label(label=f"Model: {mode}", use_markup=True, xalign=0, wrap=True) self.grid.attach(event_box, 1, self.current_row, 1, 1) diff --git a/screen.py b/screen.py index 9c152c17..99562310 100755 --- a/screen.py +++ b/screen.py @@ -167,7 +167,10 @@ class KlipperScreen(Gtk.Window): self.base_panel.activate() self.set_screenblanking_timeout(self._config.get_main_config().get('screen_blanking')) self.log_notification("KlipperScreen Started", 1) - self.initial_connection() + + lang = self._config.get_main_config().get("language", 'system_lang') + (self.show_language_select() if lang == 'system_lang' else self.initial_connection()) + def state_execute(self, state, callback): self.close_screensaver() @@ -716,9 +719,16 @@ class KlipperScreen(Gtk.Window): self.reset_screensaver_timeout() return + def show_language_select(self, widget=None): + self.show_panel("language_select", remove_all=True) + + def show_onboarding(self, widget=None): + self.show_panel("onboarding", remove_all=True) + def show_printer_select(self, widget=None): - self.base_panel.show_heaters(False) - self.show_panel("printer_select", remove_all=True) + if 'printer_select' not in self._cur_panels: + self.base_panel.show_heaters(False) + self.show_panel("printer_select", remove_all=True) def websocket_connection_cancel(self): self.printer_initializing( @@ -781,8 +791,12 @@ class KlipperScreen(Gtk.Window): self.printer.state = "not ready" return self.files.refresh_files() - 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") + guided = self._config.get_main_config().get("onboarding", False) + if guided == 'True': + self.show_onboarding() + 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") def state_startup(self): self.printer_initializing(_("Klipper is attempting to start")) @@ -938,7 +952,8 @@ class KlipperScreen(Gtk.Window): def printer_initializing(self, msg, go_to_splash=False): if 'splash_screen' not in self.panels or go_to_splash: - self.show_panel("splash_screen", remove_all=True) + if self._cur_panels != ['splash_screen']: + self.show_panel("splash_screen", remove_all=True) self.panels['splash_screen'].update_text(msg) self.log_notification(msg, 0) diff --git a/styles/dark/images/retainer.svg b/styles/dark/images/retainer.svg new file mode 100644 index 00000000..b31fc957 --- /dev/null +++ b/styles/dark/images/retainer.svg @@ -0,0 +1,19 @@ + + + + + + + + + + + + + + + + + + + diff --git a/styles/dark/images/take_out.svg b/styles/dark/images/take_out.svg new file mode 100644 index 00000000..2c91f69b --- /dev/null +++ b/styles/dark/images/take_out.svg @@ -0,0 +1,21 @@ + + + + + + + + + + + + + + + + + + + + +