Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
34 changes: 31 additions & 3 deletions panels/base_panel.py
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,8 @@ def __init__(self, screen, title=None):
self.titlebar_items = []
self.titlebar_name_type = None
self.current_extruder = None
self.title_printer = ""
self.title_panel = ""
self.last_usage_report = datetime.now()
self.usage_report = 0
# Action bar buttons
Expand Down Expand Up @@ -90,6 +92,7 @@ def __init__(self, screen, title=None):
self.control['temp_box'] = Gtk.Box(spacing=10)

self.titlelbl = Gtk.Label(hexpand=True, halign=Gtk.Align.CENTER, ellipsize=Pango.EllipsizeMode.END)
self.titlelbl.connect("size-allocate", self.update_title_visibility)

self.control['time'] = Gtk.Label(label="00:00 AM")
self.control['time_box'] = Gtk.Box(halign=Gtk.Align.END)
Expand Down Expand Up @@ -370,14 +373,17 @@ def show_printer_select(self, show=True):
def set_title(self, title):
self.titlebar.get_style_context().remove_class("message_popup_error")
if (
self._screen.connecting_to_printer != "Printer"
self._screen.connecting_to_printer
and self._screen.connecting_to_printer != "Printer"
and 'printer_select' not in self._screen._cur_panels
):
printer = self._screen.connecting_to_printer
else:
printer = ""
if not title:
self.titlelbl.set_label(f"{printer}")
self.title_printer = printer
self.title_panel = ""
self.update_title_visibility()
return
try:
env = Environment(extensions=["jinja2.ext.i18n"], autoescape=True)
Expand All @@ -387,7 +393,29 @@ def set_title(self, title):
except Exception as e:
logging.debug(f"Error parsing jinja for title: {title}\n{e}")

self.titlelbl.set_label(f"{printer} {title}")
self.title_printer = printer
self.title_panel = title
self.update_title_visibility()

def update_title_visibility(self, *args):
if self.titlebar.get_style_context().has_class("message_popup_error"):
return False
if not self.title_panel:
label = self.title_printer or ""
else:
label = f"{self.title_printer} {self.title_panel}".strip()
if self.title_printer and self._screen.vertical_mode:
allocation = self.titlelbl.get_allocation()
if allocation.width and not self.title_fits(label, allocation.width):
label = self.title_panel
if self.titlelbl.get_label() != label:
self.titlelbl.set_label(label)
return False

def title_fits(self, text, width):
layout = self.titlelbl.create_pango_layout(text)
text_width, _ = layout.get_pixel_size()
return text_width <= width

def update_time(self):
now = datetime.now()
Expand Down
19 changes: 12 additions & 7 deletions panels/gcodes.py
Original file line number Diff line number Diff line change
Expand Up @@ -221,12 +221,13 @@ def create_item(self, item):
# Определяем позиции кнопок в зависимости от типа элемента
button_col = 2
if 'filename' in item:
file_on_usb = is_file_on_usb(f"gcodes/{path}")
icon.connect("clicked", self.confirm_print, path)
image_args = (path, icon, self.thumbsize / 2, True, "file")
delete.connect("clicked", self.confirm_delete_file, f"gcodes/{path}")
rename.connect("clicked", self.show_rename, f"gcodes/{path}")
# Показываем кнопку переноса только если файл находится на USB
if is_file_on_usb(f"gcodes/{path}"):
if file_on_usb:
move = Gtk.Button(hexpand=False, vexpand=False, can_focus=False, always_show_image=True)
move.get_style_context().add_class("color3")
move.set_image(self._gtk.Image("sd", self.list_button_size, self.list_button_size))
Expand All @@ -244,8 +245,9 @@ def create_item(self, item):
action.set_vexpand(False)
action.set_halign(Gtk.Align.END)
if self._screen.width >= 400:
row.attach(action, button_col, 0, 1, 2)
else:
if not file_on_usb:
row.attach(action, button_col, 0, 1, 2)
elif not file_on_usb:
icon.get_style_context().add_class("color3")
row.attach(icon, button_col, 0, 1, 2)
elif 'dirname' in item:
Expand Down Expand Up @@ -489,16 +491,15 @@ def confirm_print(self, widget, filename):
buttons = [
{"name": _("Delete"), "response": Gtk.ResponseType.REJECT, "style": 'dialog-error'},
{"name": action, "response": Gtk.ResponseType.OK, "style": 'dialog-primary'},
*([{"name": _("Settings"), "response": Gtk.ResponseType.HELP, "style": 'dialog-secondary'}]
*([{"name": _("Settings"), "response": Gtk.ResponseType.HELP, "style": 'dialog-info'}]
if show_start_settings else []),
{"name": _("Cancel"), "response": Gtk.ResponseType.CANCEL, "style": 'dialog-secondary'}
]

buttons_usb = [
{"name": _("Delete"), "response": Gtk.ResponseType.REJECT, "style": 'dialog-error'},
{"name": _("Resave"), "response": Gtk.ResponseType.APPLY, "style": 'dialog-secondary'},
{"name": action, "response": Gtk.ResponseType.OK, "style": 'dialog-primary'},
*([{"name": _("Settings"), "response": Gtk.ResponseType.HELP, "style": 'dialog-secondary'}]
{"name": _("Resave"), "response": Gtk.ResponseType.APPLY, "style": 'dialog-primary'},
*([{"name": _("Settings"), "response": Gtk.ResponseType.HELP, "style": 'dialog-info'}]
if show_start_settings else []),
{"name": _("Cancel"), "response": Gtk.ResponseType.CANCEL, "style": 'dialog-secondary'}
]
Expand Down Expand Up @@ -553,6 +554,10 @@ def confirm_print_response(self, dialog, response_id, filename):
self._screen.show_panel("print_start_settings")
return
elif response_id == Gtk.ResponseType.OK:
if is_file_on_usb(f"gcodes/{filename}"):
logging.warning(f"Refusing to print from removable storage: {filename}")
self._screen.show_popup_message(_("Move the file to internal storage before printing"), level=2)
return
logging.info(f"Starting print: {filename}")
self._screen._ws.klippy.print_start(filename)
elif response_id == Gtk.ResponseType.APPLY:
Expand Down
63 changes: 49 additions & 14 deletions panels/network.py
Original file line number Diff line number Diff line change
Expand Up @@ -64,11 +64,27 @@ def __init__(self, screen, title):

self.interface = self.sdbus_nm.get_primary_interface()
logging.info(f"Primary interface: {self.interface}")
self.is_ap_mode = False

self.labels['interface'] = Gtk.Label(hexpand=True)
self.labels['ip'] = Gtk.Label(hexpand=True)
self.labels['interface'] = Gtk.Label(
hexpand=True,
halign=Gtk.Align.START,
wrap=True,
wrap_mode=Pango.WrapMode.WORD_CHAR,
)
self.labels['interface'].set_xalign(0)
self.labels['interface'].set_max_width_chars(30 if self._screen.vertical_mode else 60)
self.labels['interface'].set_no_show_all(True)
self.labels['ip'] = Gtk.Label(
hexpand=True,
halign=Gtk.Align.START,
wrap=True,
wrap_mode=Pango.WrapMode.WORD_CHAR,
)
self.labels['ip'].set_xalign(0)
self.labels['ip'].set_max_width_chars(30 if self._screen.vertical_mode else 60)
if self.interface is not None:
self.labels['interface'].set_text(_("Interface") + f': {self.interface}')
self.update_interface_display()
self.labels['ip'].set_text(f"IP: {self.sdbus_nm.get_ip_address()}")

self.reload_button = self._gtk.Button("refresh", None, "color1", self.bts)
Expand All @@ -84,11 +100,17 @@ def __init__(self, screen, title):
)
self.wifi_toggle.connect("notify::active", self.toggle_wifi)

sbox = Gtk.Box(hexpand=True, vexpand=False)
sbox.add(self.labels['interface'])
sbox.add(self.labels['ip'])
sbox.add(self.reload_button)
sbox.add(self.wifi_toggle)
info_box = Gtk.Box(orientation=Gtk.Orientation.VERTICAL, hexpand=True, vexpand=False)
info_box.add(self.labels['interface'])
info_box.add(self.labels['ip'])

controls_box = Gtk.Box(spacing=5, hexpand=False, vexpand=False)
controls_box.add(self.reload_button)
controls_box.add(self.wifi_toggle)

sbox = Gtk.Box(spacing=5, hexpand=True, vexpand=False)
sbox.add(info_box)
sbox.pack_end(controls_box, False, False, 0)

scroll = self._gtk.ScrolledWindow()
self.labels['main_box'] = Gtk.Box(orientation=Gtk.Orientation.VERTICAL, vexpand=True)
Expand All @@ -99,7 +121,6 @@ def __init__(self, screen, title):
# AP-related attributes (used only if show_ap_toggle is True)
self.ap_ssid = self._config.get_main_config().get('ap_ssid', 'zboltprinter')
self.ap_password = self._config.get_main_config().get('ap_password', 'zboltprinter')
self.is_ap_mode = False

if self.sdbus_nm.wifi:
self.labels['main_box'].pack_start(sbox, False, False, 5)
Expand All @@ -120,8 +141,7 @@ def __init__(self, screen, title):
ap_container.add(self.ap_label)
ap_container.add(self.ap_toggle)

# Insert AP container at the beginning of sbox
sbox.pack_start(ap_container, False, False, 5)
controls_box.pack_start(ap_container, False, False, 5)

# Check initial AP mode state and restore if needed
if self.sdbus_nm.is_access_point_mode():
Expand Down Expand Up @@ -183,6 +203,8 @@ def add_network(self, bssid):
buttons = Gtk.Box(spacing=5)

name = Gtk.Label(hexpand=True, halign=Gtk.Align.START, wrap=True, wrap_mode=Pango.WrapMode.WORD_CHAR)
name.set_xalign(0)
name.set_justify(Gtk.Justification.LEFT)
if bssid == self.sdbus_nm.get_connected_bssid():
ssid += ' (' + _("Connected") + ')'
name.set_markup(f"<big><b>{ssid}</b></big>")
Expand All @@ -194,6 +216,8 @@ def add_network(self, bssid):
buttons.add(connect)

info = Gtk.Label(halign=Gtk.Align.START)
info.set_xalign(0)
info.set_justify(Gtk.Justification.LEFT)
labels = Gtk.Box(orientation=Gtk.Orientation.VERTICAL, vexpand=True,
halign=Gtk.Align.START, valign=Gtk.Align.CENTER)
labels.add(name)
Expand Down Expand Up @@ -394,18 +418,20 @@ def show_add_network(self, widget, ssid):

def update_all_networks(self):
self.interface = self.sdbus_nm.get_primary_interface()
self.labels['interface'].set_text(_("Interface") + f': {self.interface}')
self.update_ip_display()

# Check if AP mode changed externally
ap_mode = self.sdbus_nm.is_access_point_mode()
if ap_mode != self.is_ap_mode:
self.is_ap_mode = ap_mode
self.ap_toggle.set_active(ap_mode)
if hasattr(self, "ap_toggle"):
self.ap_toggle.set_active(ap_mode)
self.update_ip_display()
if ap_mode:
self.update_ap_display()
return True

self.update_ip_display()

# If in AP mode, don't update network list
if self.is_ap_mode:
return True
Expand Down Expand Up @@ -464,6 +490,14 @@ def update_single_network_info(self):
self.labels['networkinfo'].show_all()
return True

def update_interface_display(self):
if self.is_ap_mode:
self.labels['interface'].hide()
return
if self.interface is not None:
self.labels['interface'].set_text(_("Interface") + f': {self.interface}')
self.labels['interface'].show()

def reload_networks(self, widget=None):
if self.is_ap_mode:
return
Expand Down Expand Up @@ -620,6 +654,7 @@ def update_ap_display(self):

def update_ip_display(self):
"""Update IP address display"""
self.update_interface_display()
if self.is_ap_mode:
ip_info = self.sdbus_nm.get_ap_mode_ips()
wifi_ip = ip_info.get("wifi", "?")
Expand Down
43 changes: 31 additions & 12 deletions panels/system.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,14 @@
import os
import subprocess
import shutil
import threading
import zipfile
from datetime import datetime

import gi

gi.require_version("Gtk", "3.0")
from gi.repository import Gtk
from gi.repository import Gtk, GLib
from ks_includes.screen_panel import ScreenPanel


Expand Down Expand Up @@ -272,7 +273,29 @@ def _first_key(d, *keys, default=None):
f.write(f"- Total filament used: {filament_mm_str} ({filament_m_str})\n")

def export_logs(self, widget):
self._gtk.Button_busy(widget, True)
threading.Thread(target=self._export_logs_thread, args=(widget,), daemon=True).start()

def _export_logs_thread(self, widget):
"""Экспортирует журналы на съемный носитель"""
messages = []
try:
messages = self._export_logs()
except Exception as e:
logging.error(f"Error exporting logs: {e}")
messages = [(_("Error exporting logs") + f": {str(e)}", 3)]
finally:
GLib.idle_add(self._finish_export_logs, widget, messages)

def _finish_export_logs(self, widget, messages):
self._gtk.Button_busy(widget, False)
for message, level in messages:
self._screen.show_popup_message(message, level=level)
return False

def _export_logs(self):
"""Экспортирует журналы на съемный носитель"""
messages = []
# Ищем примонтированное устройство
mounted_device = self.find_mounted_device()

Expand All @@ -285,9 +308,8 @@ def export_logs(self, widget):
export_dest_dir = mounted_device
else:
export_dest_dir = logs_dir
self._screen.show_popup_message(
_("No removable device found") + "\n" + _("Saving to logs folder"),
level=2
messages.append(
(_("No removable device found") + "\n" + _("Saving to logs folder"), 2)
)
logging.warning(
"No mounted device found in /home/pi/printer_data/gcodes/. Saving to ~/printer_data/logs"
Expand Down Expand Up @@ -388,9 +410,8 @@ def export_logs(self, widget):
shutil.rmtree(temp_dir)

# Показываем уведомление об успехе
self._screen.show_popup_message(
_("Logs saved successfully") + f"\n{dest_zip_path}",
level=1
messages.append(
(_("Logs saved successfully") + f"\n{dest_zip_path}", 1)
)

# Отмонтируем устройство
Expand All @@ -410,17 +431,15 @@ def export_logs(self, widget):
logging.error(f"Error unmounting device: {e}")

except Exception as e:
logging.error(f"Error exporting logs: {e}")
self._screen.show_popup_message(
_("Error exporting logs") + f": {str(e)}",
level=3
)
# Удаляем временную директорию в случае ошибки
if os.path.exists(temp_dir):
try:
shutil.rmtree(temp_dir)
except Exception:
pass
raise

return messages

def process_update(self, action, data):
if not self.sysinfo:
Expand Down
Loading