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:
parent
d9f48d14a7
commit
86ae87eafe
16 changed files with 251 additions and 208 deletions
|
@ -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)
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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",
|
||||
|
|
|
@ -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()
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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()
|
||||
|
|
|
@ -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()
|
||||
|
|
|
@ -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()
|
||||
|
||||
|
|
|
@ -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()
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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")
|
||||
|
|
|
@ -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(
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Reference in a new issue