pygui: revamped config to leverage classes mapped to yaml, removes need for using keys all over and type hinting on glasses, future changes should support defaults better

This commit is contained in:
Blake Harnden 2020-05-08 00:16:25 -07:00
parent d9f48d14a7
commit 86ae87eafe
16 changed files with 251 additions and 208 deletions

View file

@ -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", "<<ThemeChanged>>", themes.theme_change_menu)
self.master.bind("<<ThemeChanged>>", 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)

View file

@ -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)

View file

@ -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",

View file

@ -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()

View file

@ -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,

View file

@ -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)

View file

@ -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()

View file

@ -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()

View file

@ -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()

View file

@ -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()

View file

@ -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(
"<FocusOut>", 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:

View file

@ -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")

View file

@ -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(

View file

@ -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

View file

@ -93,7 +93,7 @@ class Menubar(tk.Menu):
)
self.app.bind_all("<Control-o>", 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)

View file

@ -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