settings: Create settings panel for KlipperScreen settings
This commit is contained in:
parent
b2b3127183
commit
642fe8a52e
@ -140,6 +140,11 @@ confirm:
|
|||||||
|
|
||||||
{{ gettext('Klipper will reboot') }}
|
{{ gettext('Klipper will reboot') }}
|
||||||
|
|
||||||
|
[menu __main config settings]
|
||||||
|
name: {{ gettext('Settings') }}
|
||||||
|
icon: settings
|
||||||
|
panel: settings
|
||||||
|
|
||||||
[menu __print]
|
[menu __print]
|
||||||
name: {{ gettext('Print Control') }}
|
name: {{ gettext('Print Control') }}
|
||||||
|
|
||||||
|
@ -16,27 +16,67 @@ class ConfigError(Exception):
|
|||||||
class KlipperScreenConfig:
|
class KlipperScreenConfig:
|
||||||
config = None
|
config = None
|
||||||
configfile_name = "KlipperScreen.conf"
|
configfile_name = "KlipperScreen.conf"
|
||||||
|
do_not_edit_line = "#~# --- Do not edit below this line. This section is auto generated --- #~#"
|
||||||
|
do_not_edit_prefix = "#~#"
|
||||||
|
|
||||||
|
def __init__(self, configfile, lang=None):
|
||||||
|
_ = lang.gettext
|
||||||
|
|
||||||
|
self.configurable_options = [
|
||||||
|
{"invert_x": {"section": "main", "name": _("Invert X"), "type": "binary", "value": "False"}},
|
||||||
|
{"invert_y": {"section": "main", "name": _("Invert Y"), "type": "binary", "value": "False"}},
|
||||||
|
{"invert_z": {"section": "main", "name": _("Invert Z"), "type": "binary", "value": "False"}}
|
||||||
|
]
|
||||||
|
|
||||||
def __init__(self, configfile):
|
|
||||||
self.default_config_path = "%s/ks_includes/%s" % (os.getcwd(), self.configfile_name)
|
self.default_config_path = "%s/ks_includes/%s" % (os.getcwd(), self.configfile_name)
|
||||||
self.config = configparser.ConfigParser()
|
self.config = configparser.ConfigParser()
|
||||||
self.config_path = self.get_config_file_location(configfile)
|
self.config_path = self.get_config_file_location(configfile)
|
||||||
|
logger.debug("Config path location: %s" % self.config_path)
|
||||||
|
self.defined_config = None
|
||||||
|
|
||||||
try:
|
try:
|
||||||
self.config.read(self.default_config_path)
|
self.config.read(self.default_config_path)
|
||||||
if self.config_path != self.default_config_path:
|
if self.config_path != self.default_config_path:
|
||||||
|
user_def, saved_def = self.separate_saved_config(self.config_path)
|
||||||
self.defined_config = configparser.ConfigParser()
|
self.defined_config = configparser.ConfigParser()
|
||||||
self.defined_config.read(self.config_path)
|
self.defined_config.read_string(user_def)
|
||||||
self.log_config(self.defined_config)
|
self.log_config(self.defined_config)
|
||||||
|
self.config.read_string(user_def)
|
||||||
self.config.read(self.config_path)
|
if saved_def != None:
|
||||||
|
self.config.read_string(saved_def)
|
||||||
except KeyError:
|
except KeyError:
|
||||||
raise ConfigError(f"Error reading config: {self.config_path}")
|
raise ConfigError(f"Error reading config: {self.config_path}")
|
||||||
|
|
||||||
self.get_menu_items("__main")
|
self.get_menu_items("__main")
|
||||||
|
for item in self.configurable_options:
|
||||||
|
name = list(item)[0]
|
||||||
|
vals = item[name]
|
||||||
|
if vals['section'] not in self.config.sections():
|
||||||
|
self.config.add_section(vals['section'])
|
||||||
|
if name not in list(self.config[vals['section']]):
|
||||||
|
self.config.set(vals['section'], name, vals['value'])
|
||||||
#self.build_main_menu(self.config)
|
#self.build_main_menu(self.config)
|
||||||
|
|
||||||
|
def separate_saved_config(self, config_path):
|
||||||
|
user_def = []
|
||||||
|
saved_def = None
|
||||||
|
found_saved = False
|
||||||
|
if not path.exists(config_path):
|
||||||
|
return [None, None]
|
||||||
|
with open(config_path) as file:
|
||||||
|
for line in file:
|
||||||
|
line = line.replace('\n','')
|
||||||
|
if line == self.do_not_edit_line:
|
||||||
|
found_saved = True
|
||||||
|
saved_def = []
|
||||||
|
continue
|
||||||
|
if found_saved == 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):])
|
||||||
|
return ["\n".join(user_def), None if saved_def == None else "\n".join(saved_def)]
|
||||||
|
|
||||||
def get_config_file_location(self, file):
|
def get_config_file_location(self, file):
|
||||||
if not path.exists(file):
|
if not path.exists(file):
|
||||||
file = "%s/%s" % (os.getcwd(), self.configfile_name)
|
file = "%s/%s" % (os.getcwd(), self.configfile_name)
|
||||||
@ -46,6 +86,12 @@ class KlipperScreenConfig:
|
|||||||
logger.info("Found configuration file at: %s" % file)
|
logger.info("Found configuration file at: %s" % file)
|
||||||
return file
|
return file
|
||||||
|
|
||||||
|
def get_config(self):
|
||||||
|
return self.config
|
||||||
|
|
||||||
|
def get_configurable_options(self):
|
||||||
|
return self.configurable_options
|
||||||
|
|
||||||
def get_main_config(self):
|
def get_main_config(self):
|
||||||
return self.config['main']
|
return self.config['main']
|
||||||
|
|
||||||
@ -56,7 +102,6 @@ class KlipperScreenConfig:
|
|||||||
if subsection != "":
|
if subsection != "":
|
||||||
subsection = subsection + " "
|
subsection = subsection + " "
|
||||||
index = "menu %s %s" % (menu, subsection)
|
index = "menu %s %s" % (menu, subsection)
|
||||||
logger.debug("Getting menu items for: %s" % index)
|
|
||||||
items = [i[len(index):] for i in self.config.sections() if i.startswith(index)]
|
items = [i[len(index):] for i in self.config.sections() if i.startswith(index)]
|
||||||
menu_items = []
|
menu_items = []
|
||||||
for item in items:
|
for item in items:
|
||||||
@ -68,7 +113,6 @@ class KlipperScreenConfig:
|
|||||||
|
|
||||||
def get_menu_name(self, menu="__main", subsection=""):
|
def get_menu_name(self, menu="__main", subsection=""):
|
||||||
name = ("menu %s %s" % (menu, subsection)) if subsection != "" else ("menu %s" % menu)
|
name = ("menu %s %s" % (menu, subsection)) if subsection != "" else ("menu %s" % menu)
|
||||||
logger.debug("Menu name: %s" % name)
|
|
||||||
if name not in self.config:
|
if name not in self.config:
|
||||||
return False
|
return False
|
||||||
return self.config[name].get('name')
|
return self.config[name].get('name')
|
||||||
@ -77,7 +121,6 @@ class KlipperScreenConfig:
|
|||||||
def get_preheat_options(self):
|
def get_preheat_options(self):
|
||||||
index = "preheat "
|
index = "preheat "
|
||||||
items = [i[len(index):] for i in self.config.sections() if i.startswith(index)]
|
items = [i[len(index):] for i in self.config.sections() if i.startswith(index)]
|
||||||
logger.debug("Items: %s" % items)
|
|
||||||
|
|
||||||
preheat_options = {}
|
preheat_options = {}
|
||||||
for item in items:
|
for item in items:
|
||||||
@ -88,6 +131,63 @@ class KlipperScreenConfig:
|
|||||||
def get_printer_power_name(self):
|
def get_printer_power_name(self):
|
||||||
return self.config['settings'].get("printer_power_name", "printer")
|
return self.config['settings'].get("printer_power_name", "printer")
|
||||||
|
|
||||||
|
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:
|
||||||
|
name = list(item)[0]
|
||||||
|
opt = item[name]
|
||||||
|
curval = self.config[opt['section']].get(name)
|
||||||
|
if curval != opt["value"] or (
|
||||||
|
self.defined_config != None and opt['section'] in self.defined_config.sections() and
|
||||||
|
self.defined_config[opt['section']].get(name,None) not in (None, curval)):
|
||||||
|
if opt['section'] not in save_config.sections():
|
||||||
|
save_config.add_section(opt['section'])
|
||||||
|
save_config.set(opt['section'], name, str(curval))
|
||||||
|
|
||||||
|
if "displayed_macros" in self.config.sections():
|
||||||
|
for item in self.config.options('displayed_macros'):
|
||||||
|
value = self.config['displayed_macros'].getboolean(item, fallback=True)
|
||||||
|
if value == False or (self.defined_config != None and
|
||||||
|
"displayed_macros" in self.defined_config.sections() and
|
||||||
|
self.defined_config['displayed_macros'].getboolean(item, fallback=True) == False and
|
||||||
|
self.defined_config['displayed_macros'].getboolean(item, fallback=True) != value):
|
||||||
|
if "displayed_macros" not in save_config.sections():
|
||||||
|
save_config.add_section("displayed_macros")
|
||||||
|
save_config.set("displayed_macros", item, str(value))
|
||||||
|
|
||||||
|
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])
|
||||||
|
|
||||||
|
if self.config_path == self.default_config_path:
|
||||||
|
user_def = ""
|
||||||
|
saved_def = None
|
||||||
|
else:
|
||||||
|
user_def, saved_def = self.separate_saved_config(self.config_path)
|
||||||
|
|
||||||
|
extra_lb = "\n" if saved_def != None else ""
|
||||||
|
contents = "%s\n%s%s\n%s\n%s\n%s\n" % (user_def, self.do_not_edit_line, extra_lb,
|
||||||
|
self.do_not_edit_prefix, "\n".join(save_output), self.do_not_edit_prefix)
|
||||||
|
|
||||||
|
if self.config_path != self.default_config_path:
|
||||||
|
path = self.config_path
|
||||||
|
else:
|
||||||
|
path = os.path.expanduser("~/KlipperScreen.conf")
|
||||||
|
|
||||||
|
try:
|
||||||
|
file = open(path, 'w')
|
||||||
|
file.write(contents)
|
||||||
|
file.close()
|
||||||
|
except:
|
||||||
|
logger.error("Error writing configuration file")
|
||||||
|
|
||||||
|
def set(self, section, name, value):
|
||||||
|
self.config.set(section, name, value)
|
||||||
|
|
||||||
|
|
||||||
def log_config(self, config):
|
def log_config(self, config):
|
||||||
lines = [
|
lines = [
|
||||||
|
181
panels/settings.py
Normal file
181
panels/settings.py
Normal file
@ -0,0 +1,181 @@
|
|||||||
|
import gi
|
||||||
|
import logging
|
||||||
|
|
||||||
|
gi.require_version("Gtk", "3.0")
|
||||||
|
from gi.repository import Gtk, Gdk, GLib, Pango
|
||||||
|
|
||||||
|
from ks_includes.KlippyGcodes import KlippyGcodes
|
||||||
|
from ks_includes.screen_panel import ScreenPanel
|
||||||
|
|
||||||
|
logger = logging.getLogger("KlipperScreen.Settings")
|
||||||
|
|
||||||
|
def create_panel(*args):
|
||||||
|
return SettingsPanel(*args)
|
||||||
|
|
||||||
|
class SettingsPanel(ScreenPanel):
|
||||||
|
def initialize(self, panel_name):
|
||||||
|
_ = self.lang.gettext
|
||||||
|
self.settings = {}
|
||||||
|
self.macros = {}
|
||||||
|
self.menu_cur = 'main_box'
|
||||||
|
self.menu = ['main_box']
|
||||||
|
|
||||||
|
self.labels['main_box'] = self.create_box('main')
|
||||||
|
self.labels['macros_box'] = self.create_box('macros')
|
||||||
|
|
||||||
|
options = self._config.get_configurable_options()
|
||||||
|
for option in options:
|
||||||
|
name = list(option)[0]
|
||||||
|
self.add_option('main', self.settings, name, option[name])
|
||||||
|
|
||||||
|
self.add_option('main', self.settings, "macros", {
|
||||||
|
"name": _("Displayed Macros"),
|
||||||
|
"type": "menu",
|
||||||
|
"menu": "macros"
|
||||||
|
})
|
||||||
|
|
||||||
|
for macro in self._printer.get_config_section_list("gcode_macro "):
|
||||||
|
macro = macro[12:]
|
||||||
|
self.macros[macro] = {
|
||||||
|
"name": macro,
|
||||||
|
"section": "displayed_macros",
|
||||||
|
"type": "macro"
|
||||||
|
}
|
||||||
|
|
||||||
|
for macro in list(self.macros):
|
||||||
|
self.add_option('macros', self.macros, macro, self.macros[macro])
|
||||||
|
|
||||||
|
logger.debug("Macros: %s" % self.macros)
|
||||||
|
|
||||||
|
self.control['back'].disconnect_by_func(self._screen._menu_go_back)
|
||||||
|
self.control['back'].connect("clicked", self.back)
|
||||||
|
self.content.add(self.labels['main_box'])
|
||||||
|
|
||||||
|
def activate(self):
|
||||||
|
while len(self.menu) > 1:
|
||||||
|
self.unload_menu()
|
||||||
|
|
||||||
|
def back(self, widget):
|
||||||
|
if len(self.menu) > 1:
|
||||||
|
self.unload_menu()
|
||||||
|
else:
|
||||||
|
self._screen._menu_go_back()
|
||||||
|
|
||||||
|
def create_box(self, name):
|
||||||
|
# Create a scroll window for the macros
|
||||||
|
scroll = Gtk.ScrolledWindow()
|
||||||
|
scroll.set_property("overlay-scrolling", False)
|
||||||
|
scroll.set_vexpand(True)
|
||||||
|
|
||||||
|
# Create a grid for all macros
|
||||||
|
self.labels[name] = Gtk.Grid()
|
||||||
|
scroll.add(self.labels[name])
|
||||||
|
|
||||||
|
# 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)
|
||||||
|
return box
|
||||||
|
|
||||||
|
def add_option(self, boxname, opt_array, opt_name, option):
|
||||||
|
frame = Gtk.Frame()
|
||||||
|
frame.set_property("shadow-type",Gtk.ShadowType.NONE)
|
||||||
|
frame.get_style_context().add_class("frame-item")
|
||||||
|
|
||||||
|
name = Gtk.Label()
|
||||||
|
name.set_markup("<big><b>%s</b></big>" % (option['name']))
|
||||||
|
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)
|
||||||
|
|
||||||
|
#open = self._gtk.ButtonImage("open",None,"color3")
|
||||||
|
#open.connect("clicked", self.run_gcode_macro, macro)
|
||||||
|
#open.set_hexpand(False)
|
||||||
|
#open.set_halign(Gtk.Align.END)
|
||||||
|
|
||||||
|
labels = Gtk.Box(orientation=Gtk.Orientation.VERTICAL)
|
||||||
|
labels.add(name)
|
||||||
|
|
||||||
|
dev = Gtk.Box(orientation=Gtk.Orientation.HORIZONTAL, spacing=5)
|
||||||
|
dev.set_hexpand(True)
|
||||||
|
dev.set_vexpand(False)
|
||||||
|
dev.set_valign(Gtk.Align.CENTER)
|
||||||
|
|
||||||
|
dev.add(labels)
|
||||||
|
if option['type'] == "binary" or option['type'] == "macro":
|
||||||
|
box = Gtk.Box()
|
||||||
|
box.set_vexpand(False)
|
||||||
|
switch = Gtk.Switch()
|
||||||
|
switch.set_hexpand(False)
|
||||||
|
switch.set_vexpand(False)
|
||||||
|
if option['type'] == "macro":
|
||||||
|
switch.set_active(self._config.get_config().getboolean(option['section'], opt_name, fallback=True))
|
||||||
|
else:
|
||||||
|
switch.set_active(self._config.get_config().getboolean(option['section'], opt_name))
|
||||||
|
switch.connect("notify::active", self.switch_config_option, option['section'], opt_name)
|
||||||
|
switch.set_property("width-request", round(self._gtk.get_image_width()*2.5))
|
||||||
|
switch.set_property("height-request", round(self._gtk.get_image_height()*1.25))
|
||||||
|
box.add(switch)
|
||||||
|
dev.add(box)
|
||||||
|
elif option['type'] == "menu":
|
||||||
|
open = self._gtk.ButtonImage("open",None,"color3")
|
||||||
|
open.connect("clicked", self.load_menu, option['menu'])
|
||||||
|
open.set_hexpand(False)
|
||||||
|
open.set_halign(Gtk.Align.END)
|
||||||
|
dev.add(open)
|
||||||
|
|
||||||
|
frame.add(dev)
|
||||||
|
|
||||||
|
opt_array[opt_name] = {
|
||||||
|
"row": frame
|
||||||
|
}
|
||||||
|
|
||||||
|
opts = sorted(opt_array)
|
||||||
|
pos = opts.index(opt_name)
|
||||||
|
|
||||||
|
self.labels[boxname].insert_row(pos)
|
||||||
|
self.labels[boxname].attach(opt_array[opt_name]['row'], 0, pos, 1, 1)
|
||||||
|
self.labels[boxname].show_all()
|
||||||
|
|
||||||
|
def load_menu(self, widget, name):
|
||||||
|
if ("%s_box" % name) not in self.labels:
|
||||||
|
return
|
||||||
|
|
||||||
|
for child in self.content.get_children():
|
||||||
|
self.content.remove(child)
|
||||||
|
|
||||||
|
self.menu.append('%s_box' % name)
|
||||||
|
self.content.add(self.labels[self.menu[-1]])
|
||||||
|
self.content.show_all()
|
||||||
|
|
||||||
|
def unload_menu(self, widget=None):
|
||||||
|
logger.debug("self.menu: %s" % self.menu)
|
||||||
|
if len(self.menu) <= 1 or self.menu[-2] not in self.labels:
|
||||||
|
return
|
||||||
|
|
||||||
|
self.menu.pop()
|
||||||
|
for child in self.content.get_children():
|
||||||
|
self.content.remove(child)
|
||||||
|
self.content.add(self.labels[self.menu[-1]])
|
||||||
|
self.content.show_all()
|
||||||
|
|
||||||
|
def switch_config_option(self, switch, gparam, section, option):
|
||||||
|
logger.debug("[%s] %s toggled %s" % (section, option, 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()
|
||||||
|
|
||||||
|
def add_gcode_option(self):
|
||||||
|
macros = self._screen.printer.get_gcode_macros()
|
||||||
|
for x in macros:
|
||||||
|
self.add_gcode_macro("macros", self.macros, x, {
|
||||||
|
"name": x[12:],
|
||||||
|
"type": binary
|
||||||
|
})
|
||||||
|
|
||||||
|
def run_gcode_macro(self, widget, macro):
|
||||||
|
self._screen._ws.klippy.gcode_script(macro)
|
11
screen.py
11
screen.py
@ -77,8 +77,8 @@ class KlipperScreen(Gtk.Window):
|
|||||||
args = parser.parse_args()
|
args = parser.parse_args()
|
||||||
configfile = os.path.normpath(os.path.expanduser(args.configfile))
|
configfile = os.path.normpath(os.path.expanduser(args.configfile))
|
||||||
|
|
||||||
|
self.lang = gettext.translation('KlipperScreen', localedir='ks_includes/locales', fallback=True)
|
||||||
self._config = KlipperScreenConfig(configfile)
|
self._config = KlipperScreenConfig(configfile, self.lang)
|
||||||
self.printer = Printer({
|
self.printer = Printer({
|
||||||
"software_version": "Unknown"
|
"software_version": "Unknown"
|
||||||
}, {
|
}, {
|
||||||
@ -92,6 +92,7 @@ class KlipperScreen(Gtk.Window):
|
|||||||
'is_active': False
|
'is_active': False
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
self.printer.set_callbacks({
|
self.printer.set_callbacks({
|
||||||
"disconnected": self.state_disconnected,
|
"disconnected": self.state_disconnected,
|
||||||
"error": self.state_error,
|
"error": self.state_error,
|
||||||
@ -102,7 +103,7 @@ class KlipperScreen(Gtk.Window):
|
|||||||
})
|
})
|
||||||
|
|
||||||
logger.debug("OS Language: %s" % os.getenv('LANG'))
|
logger.debug("OS Language: %s" % os.getenv('LANG'))
|
||||||
self.lang = gettext.translation('KlipperScreen', localedir='ks_includes/locales', fallback=True)
|
|
||||||
self.lang_ltr = True
|
self.lang_ltr = True
|
||||||
for lang in self.rtl_languages:
|
for lang in self.rtl_languages:
|
||||||
if os.getenv('LANG').lower().startswith(lang):
|
if os.getenv('LANG').lower().startswith(lang):
|
||||||
@ -116,6 +117,10 @@ class KlipperScreen(Gtk.Window):
|
|||||||
self._config.get_main_config_option("moonraker_port"),
|
self._config.get_main_config_option("moonraker_port"),
|
||||||
self._config.get_main_config_option("moonraker_api_key", False))
|
self._config.get_main_config_option("moonraker_api_key", False))
|
||||||
|
|
||||||
|
powerdevs = self.apiclient.send_request("machine/device_power/devices")
|
||||||
|
if powerdevs != False:
|
||||||
|
self.printer.configure_power_devices(powerdevs['result'])
|
||||||
|
|
||||||
Gtk.Window.__init__(self)
|
Gtk.Window.__init__(self)
|
||||||
self.width = self._config.get_main_config().getint("width", Gdk.Screen.get_width(Gdk.Screen.get_default()))
|
self.width = self._config.get_main_config().getint("width", Gdk.Screen.get_width(Gdk.Screen.get_default()))
|
||||||
self.height = self._config.get_main_config().getint("height", Gdk.Screen.get_height(Gdk.Screen.get_default()))
|
self.height = self._config.get_main_config().getint("height", Gdk.Screen.get_height(Gdk.Screen.get_default()))
|
||||||
|
Loading…
x
Reference in New Issue
Block a user