diff --git a/daemon/core/gui/app.py b/daemon/core/gui/app.py index de0a5260..5ca95ab5 100644 --- a/daemon/core/gui/app.py +++ b/daemon/core/gui/app.py @@ -43,7 +43,7 @@ class Application(ttk.Frame): # setup self.guiconfig = appconfig.read() - self.app_scale = self.guiconfig["scale"] + self.app_scale = self.guiconfig.scale self.setup_scaling() self.style = ttk.Style() self.setup_theme() @@ -65,7 +65,7 @@ class Application(ttk.Frame): themes.load(self.style) self.master.bind_class("Menu", "<>", themes.theme_change_menu) self.master.bind("<>", themes.theme_change) - self.style.theme_use(self.guiconfig["preferences"]["theme"]) + self.style.theme_use(self.guiconfig.preferences.theme) def setup_app(self): self.master.title("CORE") @@ -103,8 +103,8 @@ class Application(ttk.Frame): self.menubar = Menubar(self.master, self) def draw_canvas(self): - width = self.guiconfig["preferences"]["width"] - height = self.guiconfig["preferences"]["height"] + width = self.guiconfig.preferences.width + height = self.guiconfig.preferences.height canvas_frame = ttk.Frame(self.right_frame) canvas_frame.rowconfigure(0, weight=1) canvas_frame.columnconfigure(0, weight=1) diff --git a/daemon/core/gui/appconfig.py b/daemon/core/gui/appconfig.py index c19fb029..d1d9bcc2 100644 --- a/daemon/core/gui/appconfig.py +++ b/daemon/core/gui/appconfig.py @@ -1,6 +1,7 @@ import os import shutil from pathlib import Path +from typing import List, Optional import yaml @@ -37,11 +38,6 @@ TERMINALS = { "gnome-terminal": "gnome-terminal --window --", } EDITORS = ["$EDITOR", "vim", "emacs", "gedit", "nano", "vi"] -DEFAULT_IP4S = ["10.0.0.0", "192.168.0.0", "172.16.0.0"] -DEFAULT_IP4 = DEFAULT_IP4S[0] -DEFAULT_IP6S = ["2001::", "2002::", "a::"] -DEFAULT_IP6 = DEFAULT_IP6S[0] -DEFAULT_MAC = "00:00:00:aa:00:00" class IndentDumper(yaml.Dumper): @@ -49,13 +45,151 @@ class IndentDumper(yaml.Dumper): return super().increase_indent(flow, False) -def copy_files(current_path, new_path): +class CustomNode(yaml.YAMLObject): + yaml_tag = "!CustomNode" + yaml_loader = yaml.SafeLoader + + def __init__(self, name: str, image: str, services: List[str]) -> None: + self.name = name + self.image = image + self.services = services + + +class CoreServer(yaml.YAMLObject): + yaml_tag = "!CoreServer" + yaml_loader = yaml.SafeLoader + + def __init__(self, name: str, address: str) -> None: + self.name = name + self.address = address + + +class Observer(yaml.YAMLObject): + yaml_tag = "!Observer" + yaml_loader = yaml.SafeLoader + + def __init__(self, name: str, cmd: str) -> None: + self.name = name + self.cmd = cmd + + +class PreferencesConfig(yaml.YAMLObject): + yaml_tag = "!PreferencesConfig" + yaml_loader = yaml.SafeLoader + + def __init__( + self, + editor: str = EDITORS[1], + terminal: str = None, + theme: str = themes.THEME_DARK, + gui3d: str = "/usr/local/bin/std3d.sh", + width: int = 1000, + height: int = 750, + ) -> None: + self.theme = theme + self.editor = editor + self.terminal = terminal + self.gui3d = gui3d + self.width = width + self.height = height + + +class LocationConfig(yaml.YAMLObject): + yaml_tag = "!LocationConfig" + yaml_loader = yaml.SafeLoader + + def __init__( + self, + x: float = 0.0, + y: float = 0.0, + z: float = 0.0, + lat: float = 47.5791667, + lon: float = -122.132322, + alt: float = 2.0, + scale: float = 150.0, + ) -> None: + self.x = x + self.y = y + self.z = z + self.lat = lat + self.lon = lon + self.alt = alt + self.scale = scale + + +class IpConfigs(yaml.YAMLObject): + yaml_tag = "!IpConfigs" + yaml_loader = yaml.SafeLoader + + def __init__( + self, + ip4: str = None, + ip6: str = None, + ip4s: List[str] = None, + ip6s: List[str] = None, + ) -> None: + if ip4s is None: + ip4s = ["10.0.0.0", "192.168.0.0", "172.16.0.0"] + self.ip4s = ip4s + if ip6s is None: + ip6s = ["2001::", "2002::", "a::"] + self.ip6s = ip6s + if ip4 is None: + ip4 = self.ip4s[0] + self.ip4 = ip4 + if ip6 is None: + ip6 = self.ip6s[0] + self.ip6 = ip6 + + +class GuiConfig(yaml.YAMLObject): + yaml_tag = "!GuiConfig" + yaml_loader = yaml.SafeLoader + + def __init__( + self, + preferences: PreferencesConfig = None, + location: LocationConfig = None, + servers: List[CoreServer] = None, + nodes: List[CustomNode] = None, + recentfiles: List[str] = None, + observers: List[Observer] = None, + scale: float = 1.0, + ips: IpConfigs = None, + mac: str = "00:00:00:aa:00:00", + ) -> None: + if preferences is None: + preferences = PreferencesConfig() + self.preferences = preferences + if location is None: + location = LocationConfig() + self.location = location + if servers is None: + servers = [] + self.servers = servers + if nodes is None: + nodes = [] + self.nodes = nodes + if recentfiles is None: + recentfiles = [] + self.recentfiles = recentfiles + if observers is None: + observers = [] + self.observers = observers + self.scale = scale + if ips is None: + ips = IpConfigs() + self.ips = ips + self.mac = mac + + +def copy_files(current_path, new_path) -> None: for current_file in current_path.glob("*"): new_file = new_path.joinpath(current_file.name) shutil.copy(current_file, new_file) -def find_terminal(): +def find_terminal() -> Optional[str]: for term in sorted(TERMINALS): cmd = TERMINALS[term] if shutil.which(term): @@ -63,7 +197,7 @@ def find_terminal(): return None -def check_directory(): +def check_directory() -> None: if HOME_PATH.exists(): return HOME_PATH.mkdir() @@ -85,45 +219,16 @@ def check_directory(): editor = EDITORS[0] else: editor = EDITORS[1] - config = { - "preferences": { - "theme": themes.THEME_DARK, - "editor": editor, - "terminal": terminal, - "gui3d": "/usr/local/bin/std3d.sh", - "width": 1000, - "height": 750, - }, - "location": { - "x": 0.0, - "y": 0.0, - "z": 0.0, - "lat": 47.5791667, - "lon": -122.132322, - "alt": 2.0, - "scale": 150.0, - }, - "servers": [], - "nodes": [], - "recentfiles": [], - "observers": [], - "scale": 1.0, - "ips": { - "ip4": DEFAULT_IP4, - "ip6": DEFAULT_IP6, - "ip4s": DEFAULT_IP4S, - "ip6s": DEFAULT_IP6S, - }, - "mac": DEFAULT_MAC, - } + preferences = PreferencesConfig(editor, terminal) + config = GuiConfig(preferences=preferences) save(config) -def read(): +def read() -> GuiConfig: with CONFIG_PATH.open("r") as f: return yaml.load(f, Loader=yaml.SafeLoader) -def save(config): +def save(config: GuiConfig) -> None: with CONFIG_PATH.open("w") as f: yaml.dump(config, f, Dumper=IndentDumper, default_flow_style=False) diff --git a/daemon/core/gui/coreclient.py b/daemon/core/gui/coreclient.py index 950d7013..bc9cdc37 100644 --- a/daemon/core/gui/coreclient.py +++ b/daemon/core/gui/coreclient.py @@ -34,19 +34,6 @@ if TYPE_CHECKING: GUI_SOURCE = "gui" -class CoreServer: - def __init__(self, name: str, address: str, port: int): - self.name = name - self.address = address - self.port = port - - -class Observer: - def __init__(self, name: str, cmd: str): - self.name = name - self.cmd = cmd - - class CoreClient: def __init__(self, app: "Application", proxy: bool): """ @@ -126,22 +113,17 @@ class CoreClient: self.observer = value def read_config(self): - # read distributed server - for config in self.app.guiconfig.get("servers", []): - server = CoreServer(config["name"], config["address"], config["port"]) + # read distributed servers + for server in self.app.guiconfig.servers: self.servers[server.name] = server # read custom nodes - for config in self.app.guiconfig.get("nodes", []): - name = config["name"] - image_file = config["image"] - services = set(config["services"]) - node_draw = NodeDraw.from_custom(name, image_file, services) - self.custom_nodes[name] = node_draw + for custom_node in self.app.guiconfig.nodes: + node_draw = NodeDraw.from_custom(custom_node) + self.custom_nodes[custom_node.name] = node_draw # read observers - for config in self.app.guiconfig.get("observers", []): - observer = Observer(config["name"], config["cmd"]) + for observer in self.app.guiconfig.observers: self.custom_observers[observer.name] = observer def handle_events(self, event: core_pb2.Event): @@ -367,8 +349,8 @@ class CoreClient: self.app.canvas.adjust_to_dim.set(fit_image) wallpaper_style = canvas_config.get("wallpaper-style", 1) self.app.canvas.scale_option.set(wallpaper_style) - width = self.app.guiconfig["preferences"]["width"] - height = self.app.guiconfig["preferences"]["height"] + width = self.app.guiconfig.preferences.width + height = self.app.guiconfig.preferences.height dimensions = canvas_config.get("dimensions", [width, height]) self.app.canvas.redraw_canvas(dimensions) wallpaper = canvas_config.get("wallpaper") @@ -418,15 +400,15 @@ class CoreClient: try: response = self.client.create_session() logging.info("created session: %s", response) - location_config = self.app.guiconfig["location"] + location_config = self.app.guiconfig.location self.location = core_pb2.SessionLocation( - x=location_config["x"], - y=location_config["y"], - z=location_config["z"], - lat=location_config["lat"], - lon=location_config["lon"], - alt=location_config["alt"], - scale=location_config["scale"], + x=location_config.x, + y=location_config.y, + z=location_config.z, + lat=location_config.lat, + lon=location_config.lon, + alt=location_config.alt, + scale=location_config.scale, ) self.join_session(response.session_id, query_location=False) except grpc.RpcError as e: @@ -585,7 +567,7 @@ class CoreClient: def launch_terminal(self, node_id: int): try: - terminal = self.app.guiconfig["preferences"]["terminal"] + terminal = self.app.guiconfig.preferences.terminal if not terminal: messagebox.showerror( "Terminal Error", diff --git a/daemon/core/gui/dialogs/canvassizeandscale.py b/daemon/core/gui/dialogs/canvassizeandscale.py index 3c3b8540..5a042468 100644 --- a/daemon/core/gui/dialogs/canvassizeandscale.py +++ b/daemon/core/gui/dialogs/canvassizeandscale.py @@ -241,16 +241,16 @@ class SizeAndScaleDialog(Dialog): location.alt = self.alt.get() location.scale = self.scale.get() if self.save_default.get(): - location_config = self.app.guiconfig["location"] - location_config["x"] = location.x - location_config["y"] = location.y - location_config["z"] = location.z - location_config["lat"] = location.lat - location_config["lon"] = location.lon - location_config["alt"] = location.alt - location_config["scale"] = location.scale - preferences = self.app.guiconfig["preferences"] - preferences["width"] = width - preferences["height"] = height + location_config = self.app.guiconfig.location + location_config.x = location.x + location_config.y = location.y + location_config.z = location.z + location_config.lat = location.lat + location_config.lon = location.lon + location_config.alt = location.alt + location_config.scale = location.scale + preferences = self.app.guiconfig.preferences + preferences.width = width + preferences.height = height self.app.save_config() self.destroy() diff --git a/daemon/core/gui/dialogs/customnodes.py b/daemon/core/gui/dialogs/customnodes.py index 28f33ffe..56012780 100644 --- a/daemon/core/gui/dialogs/customnodes.py +++ b/daemon/core/gui/dialogs/customnodes.py @@ -5,7 +5,7 @@ from tkinter import ttk from typing import TYPE_CHECKING, Set from core.gui import nodeutils -from core.gui.appconfig import ICONS_PATH +from core.gui.appconfig import ICONS_PATH, CustomNode from core.gui.dialogs.dialog import Dialog from core.gui.images import Images from core.gui.nodeutils import NodeDraw @@ -201,17 +201,12 @@ class CustomNodesDialog(Dialog): self.services.update(dialog.current_services) def click_save(self): - self.app.guiconfig["nodes"].clear() - for name in sorted(self.app.core.custom_nodes): + self.app.guiconfig.nodes.clear() + for name in self.app.core.custom_nodes: node_draw = self.app.core.custom_nodes[name] - self.app.guiconfig["nodes"].append( - { - "name": name, - "image": node_draw.image_file, - "services": list(node_draw.services), - } - ) - logging.info("saving custom nodes: %s", self.app.guiconfig["nodes"]) + custom_node = CustomNode(name, node_draw.image_file, node_draw.services) + self.app.guiconfig.nodes.append(custom_node) + logging.info("saving custom nodes: %s", self.app.guiconfig.nodes) self.app.save_config() self.destroy() @@ -219,7 +214,8 @@ class CustomNodesDialog(Dialog): name = self.name.get() if name not in self.app.core.custom_nodes: image_file = Path(self.image_file).stem - node_draw = NodeDraw.from_custom(name, image_file, set(self.services)) + custom_node = CustomNode(name, image_file, list(self.services)) + node_draw = NodeDraw.from_custom(custom_node) logging.info( "created new custom node (%s), image file (%s), services: (%s)", name, diff --git a/daemon/core/gui/dialogs/find.py b/daemon/core/gui/dialogs/find.py index 8f0094d4..25da4b19 100644 --- a/daemon/core/gui/dialogs/find.py +++ b/daemon/core/gui/dialogs/find.py @@ -45,7 +45,7 @@ class FindDialog(Dialog): ) self.tree.grid(sticky="nsew", pady=PADY) style = ttk.Style() - heading_size = int(self.app.guiconfig["scale"] * 10) + heading_size = int(self.app.guiconfig.scale * 10) style.configure("Treeview.Heading", font=(None, heading_size, "bold")) self.tree.column("nodeid", stretch=tk.YES, anchor="center") self.tree.heading("nodeid", text="Node ID") @@ -124,7 +124,7 @@ class FindDialog(Dialog): canvas_node = self.app.core.canvas_nodes[node_id] x0, y0, x1, y1 = self.app.canvas.bbox(canvas_node.id) - dist = 5 * self.app.guiconfig["scale"] + dist = 5 * self.app.guiconfig.scale self.app.canvas.create_oval( x0 - dist, y0 - dist, @@ -132,7 +132,7 @@ class FindDialog(Dialog): y1 + dist, tags="find", outline="red", - width=3.0 * self.app.guiconfig["scale"], + width=3.0 * self.app.guiconfig.scale, ) _x, _y, _, _ = self.app.canvas.bbox(canvas_node.id) diff --git a/daemon/core/gui/dialogs/ipdialog.py b/daemon/core/gui/dialogs/ipdialog.py index 3c6944ab..62f5d0ba 100644 --- a/daemon/core/gui/dialogs/ipdialog.py +++ b/daemon/core/gui/dialogs/ipdialog.py @@ -4,7 +4,6 @@ from typing import TYPE_CHECKING import netaddr -from core.gui import appconfig from core.gui.dialogs.dialog import Dialog from core.gui.themes import FRAME_PAD, PADX, PADY from core.gui.widgets import ListboxScroll @@ -16,11 +15,10 @@ if TYPE_CHECKING: class IpConfigDialog(Dialog): def __init__(self, app: "Application") -> None: super().__init__(app, "IP Configuration") - ip_config = self.app.guiconfig.setdefault("ips") - self.ip4 = ip_config.setdefault("ip4", appconfig.DEFAULT_IP4) - self.ip6 = ip_config.setdefault("ip6", appconfig.DEFAULT_IP6) - self.ip4s = ip_config.setdefault("ip4s", appconfig.DEFAULT_IP4S) - self.ip6s = ip_config.setdefault("ip6s", appconfig.DEFAULT_IP6S) + self.ip4 = self.app.guiconfig.ips.ip4 + self.ip6 = self.app.guiconfig.ips.ip6 + self.ip4s = self.app.guiconfig.ips.ip4s + self.ip6s = self.app.guiconfig.ips.ip6s self.ip4_entry = None self.ip4_listbox = None self.ip6_entry = None @@ -143,11 +141,11 @@ class IpConfigDialog(Dialog): for index in range(self.ip6_listbox.listbox.size()): ip6 = self.ip6_listbox.listbox.get(index) ip6s.append(ip6) - ip_config = self.app.guiconfig["ips"] - ip_config["ip4"] = self.ip4 - ip_config["ip6"] = self.ip6 - ip_config["ip4s"] = ip4s - ip_config["ip6s"] = ip6s + ip_config = self.app.guiconfig.ips + ip_config.ip4 = self.ip4 + ip_config.ip6 = self.ip6 + ip_config.ip4s = ip4s + ip_config.ip6s = ip6s self.app.core.interfaces_manager.update_ips(self.ip4, self.ip6) self.app.save_config() self.destroy() diff --git a/daemon/core/gui/dialogs/macdialog.py b/daemon/core/gui/dialogs/macdialog.py index 18a330ba..caca9fd0 100644 --- a/daemon/core/gui/dialogs/macdialog.py +++ b/daemon/core/gui/dialogs/macdialog.py @@ -4,7 +4,6 @@ from typing import TYPE_CHECKING import netaddr -from core.gui import appconfig from core.gui.dialogs.dialog import Dialog from core.gui.themes import PADX, PADY @@ -15,7 +14,7 @@ if TYPE_CHECKING: class MacConfigDialog(Dialog): def __init__(self, app: "Application") -> None: super().__init__(app, "MAC Configuration") - mac = self.app.guiconfig.get("mac", appconfig.DEFAULT_MAC) + mac = self.app.guiconfig.mac self.mac_var = tk.StringVar(value=mac) self.draw() @@ -57,6 +56,6 @@ class MacConfigDialog(Dialog): messagebox.showerror("MAC Error", f"{mac} is an invalid mac") else: self.app.core.interfaces_manager.mac = netaddr.EUI(mac) - self.app.guiconfig["mac"] = mac + self.app.guiconfig.mac = mac self.app.save_config() self.destroy() diff --git a/daemon/core/gui/dialogs/observers.py b/daemon/core/gui/dialogs/observers.py index 4ec03185..6911e1b8 100644 --- a/daemon/core/gui/dialogs/observers.py +++ b/daemon/core/gui/dialogs/observers.py @@ -2,7 +2,7 @@ import tkinter as tk from tkinter import messagebox, ttk from typing import TYPE_CHECKING -from core.gui.coreclient import Observer +from core.gui.appconfig import Observer from core.gui.dialogs.dialog import Dialog from core.gui.themes import PADX, PADY from core.gui.widgets import ListboxScroll @@ -89,11 +89,9 @@ class ObserverDialog(Dialog): button.grid(row=0, column=1, sticky="ew") def click_save_config(self): - observers = [] - for name in sorted(self.app.core.custom_observers): - observer = self.app.core.custom_observers[name] - observers.append({"name": observer.name, "cmd": observer.cmd}) - self.app.guiconfig["observers"] = observers + self.app.guiconfig.observers.clear() + for observer in self.app.core.custom_observers.values(): + self.app.guiconfig.observers.append(observer) self.app.save_config() self.destroy() diff --git a/daemon/core/gui/dialogs/preferences.py b/daemon/core/gui/dialogs/preferences.py index c650f42a..9c9ba16f 100644 --- a/daemon/core/gui/dialogs/preferences.py +++ b/daemon/core/gui/dialogs/preferences.py @@ -19,11 +19,11 @@ class PreferencesDialog(Dialog): def __init__(self, app: "Application"): super().__init__(app, "Preferences") self.gui_scale = tk.DoubleVar(value=self.app.app_scale) - preferences = self.app.guiconfig["preferences"] - self.editor = tk.StringVar(value=preferences["editor"]) - self.theme = tk.StringVar(value=preferences["theme"]) - self.terminal = tk.StringVar(value=preferences["terminal"]) - self.gui3d = tk.StringVar(value=preferences["gui3d"]) + preferences = self.app.guiconfig.preferences + self.editor = tk.StringVar(value=preferences.editor) + self.theme = tk.StringVar(value=preferences.theme) + self.terminal = tk.StringVar(value=preferences.terminal) + self.gui3d = tk.StringVar(value=preferences.gui3d) self.draw() def draw(self): @@ -110,15 +110,14 @@ class PreferencesDialog(Dialog): self.app.style.theme_use(theme) def click_save(self): - preferences = self.app.guiconfig["preferences"] - preferences["terminal"] = self.terminal.get() - preferences["editor"] = self.editor.get() - preferences["gui3d"] = self.gui3d.get() - preferences["theme"] = self.theme.get() + preferences = self.app.guiconfig.preferences + preferences.terminal = self.terminal.get() + preferences.editor = self.editor.get() + preferences.gui3d = self.gui3d.get() + preferences.theme = self.theme.get() self.gui_scale.set(round(self.gui_scale.get(), 2)) app_scale = self.gui_scale.get() - self.app.guiconfig["scale"] = app_scale - + self.app.guiconfig.scale = app_scale self.app.save_config() self.scale_adjust() self.destroy() diff --git a/daemon/core/gui/dialogs/servers.py b/daemon/core/gui/dialogs/servers.py index 62bcc675..7ca96e9f 100644 --- a/daemon/core/gui/dialogs/servers.py +++ b/daemon/core/gui/dialogs/servers.py @@ -2,7 +2,7 @@ import tkinter as tk from tkinter import ttk from typing import TYPE_CHECKING -from core.gui.coreclient import CoreServer +from core.gui.appconfig import CoreServer from core.gui.dialogs.dialog import Dialog from core.gui.themes import FRAME_PAD, PADX, PADY from core.gui.widgets import ListboxScroll @@ -20,7 +20,6 @@ class ServersDialog(Dialog): super().__init__(app, "CORE Servers") self.name = tk.StringVar(value=DEFAULT_NAME) self.address = tk.StringVar(value=DEFAULT_ADDRESS) - self.port = tk.IntVar(value=DEFAULT_PORT) self.servers = None self.selected_index = None self.selected = None @@ -54,31 +53,17 @@ class ServersDialog(Dialog): frame.grid(pady=PADY, sticky="ew") frame.columnconfigure(1, weight=1) frame.columnconfigure(3, weight=1) - frame.columnconfigure(5, weight=1) label = ttk.Label(frame, text="Name") - label.grid(row=0, column=0, sticky="w", padx=PADX, pady=PADY) + label.grid(row=0, column=0, sticky="w", padx=PADX) entry = ttk.Entry(frame, textvariable=self.name) entry.grid(row=0, column=1, sticky="ew") label = ttk.Label(frame, text="Address") - label.grid(row=0, column=2, sticky="w", padx=PADX, pady=PADY) + label.grid(row=0, column=2, sticky="w", padx=PADX) entry = ttk.Entry(frame, textvariable=self.address) entry.grid(row=0, column=3, sticky="ew") - label = ttk.Label(frame, text="Port") - label.grid(row=0, column=4, sticky="w", padx=PADX, pady=PADY) - entry = ttk.Entry( - frame, - textvariable=self.port, - validate="key", - validatecommand=(self.app.validation.positive_int, "%P"), - ) - entry.bind( - "", lambda event: self.app.validation.focus_out(event, "50051") - ) - entry.grid(row=0, column=5, sticky="ew") - def draw_servers_buttons(self): frame = ttk.Frame(self.top) frame.grid(pady=PADY, sticky="ew") @@ -113,13 +98,9 @@ class ServersDialog(Dialog): button.grid(row=0, column=1, sticky="ew") def click_save_configuration(self): - servers = [] - for name in sorted(self.app.core.servers): - server = self.app.core.servers[name] - servers.append( - {"name": server.name, "address": server.address, "port": server.port} - ) - self.app.guiconfig["servers"] = servers + self.app.guiconfig.servers.clear() + for server in self.app.core.servers.values(): + self.app.guiconfig.servers.append(server) self.app.save_config() self.destroy() @@ -127,8 +108,7 @@ class ServersDialog(Dialog): name = self.name.get() if name not in self.app.core.servers: address = self.address.get() - port = self.port.get() - server = CoreServer(name, address, port) + server = CoreServer(name, address) self.app.core.servers[name] = server self.servers.insert(tk.END, name) @@ -140,7 +120,6 @@ class ServersDialog(Dialog): server = self.app.core.servers.pop(previous_name) server.name = name server.address = self.address.get() - server.port = self.port.get() self.app.core.servers[name] = server self.servers.delete(self.selected_index) self.servers.insert(self.selected_index, name) @@ -154,7 +133,6 @@ class ServersDialog(Dialog): self.selected_index = None self.name.set(DEFAULT_NAME) self.address.set(DEFAULT_ADDRESS) - self.port.set(DEFAULT_PORT) self.servers.selection_clear(0, tk.END) self.save_button.config(state=tk.DISABLED) self.delete_button.config(state=tk.DISABLED) @@ -167,7 +145,6 @@ class ServersDialog(Dialog): server = self.app.core.servers[self.selected] self.name.set(server.name) self.address.set(server.address) - self.port.set(server.port) self.save_button.config(state=tk.NORMAL) self.delete_button.config(state=tk.NORMAL) else: diff --git a/daemon/core/gui/dialogs/sessions.py b/daemon/core/gui/dialogs/sessions.py index 160854a6..9aa71a13 100644 --- a/daemon/core/gui/dialogs/sessions.py +++ b/daemon/core/gui/dialogs/sessions.py @@ -70,7 +70,7 @@ class SessionsDialog(Dialog): selectmode=tk.BROWSE, ) style = ttk.Style() - heading_size = int(self.app.guiconfig["scale"] * 10) + heading_size = int(self.app.guiconfig.scale * 10) style.configure("Treeview.Heading", font=(None, heading_size, "bold")) self.tree.grid(sticky="nsew") self.tree.column("id", stretch=tk.YES, anchor="center") diff --git a/daemon/core/gui/graph/graph.py b/daemon/core/gui/graph/graph.py index 6913dd58..220e122f 100644 --- a/daemon/core/gui/graph/graph.py +++ b/daemon/core/gui/graph/graph.py @@ -1002,10 +1002,10 @@ class CanvasGraph(tk.Canvas): if NodeUtils.is_custom( canvas_node.core_node.type, canvas_node.core_node.model ): - for custom_node in self.app.guiconfig["nodes"]: - if custom_node["name"] == canvas_node.core_node.model: + for custom_node in self.app.guiconfig.nodes: + if custom_node.name == canvas_node.core_node.model: img = Images.get_custom( - custom_node["image"], int(ICON_SIZE * self.app.app_scale) + custom_node.image, int(ICON_SIZE * self.app.app_scale) ) else: image_enum = TypeToImage.get( diff --git a/daemon/core/gui/interface.py b/daemon/core/gui/interface.py index 6f5f5fff..0ff018c7 100644 --- a/daemon/core/gui/interface.py +++ b/daemon/core/gui/interface.py @@ -4,7 +4,6 @@ from typing import TYPE_CHECKING, Any, List, Optional, Set, Tuple import netaddr from netaddr import EUI, IPNetwork -from core.gui import appconfig from core.gui.nodeutils import NodeUtils if TYPE_CHECKING: @@ -44,14 +43,13 @@ class Subnets: class InterfaceManager: def __init__(self, app: "Application") -> None: self.app = app - ip_config = self.app.guiconfig.get("ips", {}) - ip4 = ip_config.get("ip4", appconfig.DEFAULT_IP4) - ip6 = ip_config.get("ip6", appconfig.DEFAULT_IP6) + ip4 = self.app.guiconfig.ips.ip4 + ip6 = self.app.guiconfig.ips.ip6 self.ip4_mask = 24 self.ip6_mask = 64 self.ip4_subnets = IPNetwork(f"{ip4}/{self.ip4_mask}") self.ip6_subnets = IPNetwork(f"{ip6}/{self.ip6_mask}") - mac = self.app.guiconfig.get("mac", appconfig.DEFAULT_MAC) + mac = self.app.guiconfig.mac self.mac = EUI(mac, dialect=netaddr.mac_unix_expanded) self.current_mac = None self.current_subnets = None diff --git a/daemon/core/gui/menubar.py b/daemon/core/gui/menubar.py index c3ed071a..2e07ed0a 100644 --- a/daemon/core/gui/menubar.py +++ b/daemon/core/gui/menubar.py @@ -93,7 +93,7 @@ class Menubar(tk.Menu): ) self.app.bind_all("", self.click_open_xml) self.recent_menu = tk.Menu(menu) - for i in self.app.guiconfig["recentfiles"]: + for i in self.app.guiconfig.recentfiles: self.recent_menu.add_command( label=i, command=partial(self.open_recent_files, i) ) @@ -298,7 +298,7 @@ class Menubar(tk.Menu): def update_recent_files(self) -> None: self.recent_menu.delete(0, tk.END) - for i in self.app.guiconfig["recentfiles"]: + for i in self.app.guiconfig.recentfiles: self.recent_menu.add_command( label=i, command=partial(self.open_recent_files, i) ) @@ -350,7 +350,7 @@ class Menubar(tk.Menu): dialog.show() def add_recent_file_to_gui_config(self, file_path) -> None: - recent_files = self.app.guiconfig["recentfiles"] + recent_files = self.app.guiconfig.recentfiles num_files = len(recent_files) if num_files == 0: recent_files.insert(0, file_path) diff --git a/daemon/core/gui/nodeutils.py b/daemon/core/gui/nodeutils.py index 24c01f06..4c2cec07 100644 --- a/daemon/core/gui/nodeutils.py +++ b/daemon/core/gui/nodeutils.py @@ -1,7 +1,8 @@ import logging -from typing import TYPE_CHECKING, Dict, List, Optional, Set, Union +from typing import TYPE_CHECKING, List, Optional, Set from core.api.grpc.core_pb2 import Node, NodeType +from core.gui.appconfig import CustomNode, GuiConfig from core.gui.images import ImageEnum, Images, TypeToImage if TYPE_CHECKING: @@ -41,16 +42,16 @@ class NodeDraw: return node_draw @classmethod - def from_custom(cls, name: str, image_file: str, services: Set[str]): + def from_custom(cls, custom_node: CustomNode): node_draw = NodeDraw() node_draw.custom = True - node_draw.image_file = image_file - node_draw.image = Images.get_custom(image_file, ICON_SIZE) + node_draw.image_file = custom_node.image + node_draw.image = Images.get_custom(custom_node.image, ICON_SIZE) node_draw.node_type = NodeType.DEFAULT - node_draw.services = services - node_draw.label = name - node_draw.model = name - node_draw.tooltip = name + node_draw.services = custom_node.services + node_draw.label = custom_node.name + node_draw.model = custom_node.name + node_draw.tooltip = custom_node.name return node_draw @@ -97,11 +98,7 @@ class NodeUtils: @classmethod def node_icon( - cls, - node_type: NodeType, - model: str, - gui_config: Dict[str, List[Dict[str, str]]], - scale=1.0, + cls, node_type: NodeType, model: str, gui_config: GuiConfig, scale=1.0 ) -> "ImageTk.PhotoImage": image_enum = TypeToImage.get(node_type, model) @@ -114,10 +111,7 @@ class NodeUtils: @classmethod def node_image( - cls, - core_node: "core_pb2.Node", - gui_config: Dict[str, List[Dict[str, str]]], - scale=1.0, + cls, core_node: "core_pb2.Node", gui_config: GuiConfig, scale=1.0 ) -> "ImageTk.PhotoImage": image = cls.node_icon(core_node.type, core_node.model, gui_config, scale) if core_node.icon: @@ -132,20 +126,17 @@ class NodeUtils: return node_type == NodeType.DEFAULT and model not in cls.NODE_MODELS @classmethod - def get_custom_node_services( - cls, gui_config: Dict[str, List[Dict[str, str]]], name: str - ) -> List[str]: - for m in gui_config["nodes"]: - if m["name"] == name: - return m["services"] + def get_custom_node_services(cls, gui_config: GuiConfig, name: str) -> List[str]: + for custom_node in gui_config.nodes: + if custom_node.name == name: + return custom_node.services return [] @classmethod - def get_image_file(cls, gui_config, name: str) -> Union[str, None]: - if "nodes" in gui_config: - for m in gui_config["nodes"]: - if m["name"] == name: - return m["image"] + def get_image_file(cls, gui_config: GuiConfig, name: str) -> Optional[str]: + for custom_node in gui_config.nodes: + if custom_node.name == name: + return custom_node.image return None @classmethod