Merge pull request #444 from coreemu/enhancement/pygui-config

Enhancement/pygui config
This commit is contained in:
bharnden 2020-05-08 08:21:05 -07:00 committed by GitHub
commit 944040608e
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
16 changed files with 251 additions and 209 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,10 +1,10 @@
import os
import shutil
from pathlib import Path
from typing import List, Optional
import yaml
# gui home paths
from core.gui import themes
HOME_PATH = Path.home().joinpath(".coretk")
@ -37,11 +37,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 +44,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 +196,7 @@ def find_terminal():
return None
def check_directory():
def check_directory() -> None:
if HOME_PATH.exists():
return
HOME_PATH.mkdir()
@ -85,45 +218,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