Merge pull request #444 from coreemu/enhancement/pygui-config
Enhancement/pygui config
This commit is contained in:
commit
944040608e
16 changed files with 251 additions and 209 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,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)
|
||||
|
|
|
@ -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