removed CustomNode class, added nodeutils and NodeDraw to support defining the current node type to draw and reuse for custom nodes as well
This commit is contained in:
parent
7981340b13
commit
8ad9b7d728
9 changed files with 146 additions and 139 deletions
|
@ -9,12 +9,16 @@ from coretk.graph import CanvasGraph
|
||||||
from coretk.images import ImageEnum, Images
|
from coretk.images import ImageEnum, Images
|
||||||
from coretk.menuaction import MenuAction
|
from coretk.menuaction import MenuAction
|
||||||
from coretk.menubar import Menubar
|
from coretk.menubar import Menubar
|
||||||
|
from coretk.nodeutils import NodeUtils
|
||||||
from coretk.toolbar import Toolbar
|
from coretk.toolbar import Toolbar
|
||||||
|
|
||||||
|
|
||||||
class Application(tk.Frame):
|
class Application(tk.Frame):
|
||||||
def __init__(self, master=None):
|
def __init__(self, master=None):
|
||||||
super().__init__(master)
|
super().__init__(master)
|
||||||
|
# load node icons
|
||||||
|
NodeUtils.setup()
|
||||||
|
|
||||||
# widgets
|
# widgets
|
||||||
self.menubar = None
|
self.menubar = None
|
||||||
self.toolbar = None
|
self.toolbar = None
|
||||||
|
|
|
@ -7,13 +7,12 @@ import os
|
||||||
from core.api.grpc import client, core_pb2
|
from core.api.grpc import client, core_pb2
|
||||||
from coretk.dialogs.sessions import SessionsDialog
|
from coretk.dialogs.sessions import SessionsDialog
|
||||||
from coretk.emaneodelnodeconfig import EmaneModelNodeConfig
|
from coretk.emaneodelnodeconfig import EmaneModelNodeConfig
|
||||||
from coretk.images import NODE_WIDTH, Images
|
|
||||||
from coretk.interface import InterfaceManager
|
from coretk.interface import InterfaceManager
|
||||||
from coretk.mobilitynodeconfig import MobilityNodeConfig
|
from coretk.mobilitynodeconfig import MobilityNodeConfig
|
||||||
|
from coretk.nodeutils import NodeDraw
|
||||||
from coretk.servicenodeconfig import ServiceNodeConfig
|
from coretk.servicenodeconfig import ServiceNodeConfig
|
||||||
from coretk.wlannodeconfig import WlanNodeConfig
|
from coretk.wlannodeconfig import WlanNodeConfig
|
||||||
|
|
||||||
NETWORK_NODES = {"switch", "hub", "wlan", "rj45", "tunnel", "emane"}
|
|
||||||
DEFAULT_NODES = {"router", "host", "PC", "mdr", "prouter"}
|
DEFAULT_NODES = {"router", "host", "PC", "mdr", "prouter"}
|
||||||
OBSERVERS = {
|
OBSERVERS = {
|
||||||
"processes": "ps",
|
"processes": "ps",
|
||||||
|
@ -35,14 +34,6 @@ class CoreServer:
|
||||||
self.port = port
|
self.port = port
|
||||||
|
|
||||||
|
|
||||||
class CustomNode:
|
|
||||||
def __init__(self, name, image, image_file, services):
|
|
||||||
self.name = name
|
|
||||||
self.image = image
|
|
||||||
self.image_file = image_file
|
|
||||||
self.services = services
|
|
||||||
|
|
||||||
|
|
||||||
class Observer:
|
class Observer:
|
||||||
def __init__(self, name, cmd):
|
def __init__(self, name, cmd):
|
||||||
self.name = name
|
self.name = name
|
||||||
|
@ -96,12 +87,11 @@ class CoreClient:
|
||||||
|
|
||||||
# read custom nodes
|
# read custom nodes
|
||||||
for config in self.app.config.get("nodes", []):
|
for config in self.app.config.get("nodes", []):
|
||||||
|
name = config["name"]
|
||||||
image_file = config["image"]
|
image_file = config["image"]
|
||||||
image = Images.get_custom(image_file, NODE_WIDTH)
|
services = set(config["services"])
|
||||||
custom_node = CustomNode(
|
node_draw = NodeDraw.from_custom(name, image_file, services)
|
||||||
config["name"], image, image_file, set(config["services"])
|
self.custom_nodes[name] = node_draw
|
||||||
)
|
|
||||||
self.custom_nodes[custom_node.name] = custom_node
|
|
||||||
|
|
||||||
# read observers
|
# read observers
|
||||||
for config in self.app.config.get("observers", []):
|
for config in self.app.config.get("observers", []):
|
||||||
|
@ -448,6 +438,7 @@ class CoreClient:
|
||||||
self.emaneconfig_management.set_default_config(node_id)
|
self.emaneconfig_management.set_default_config(node_id)
|
||||||
|
|
||||||
# set default service configurations
|
# set default service configurations
|
||||||
|
# TODO: need to deal with this and custom node cases
|
||||||
if node_type == core_pb2.NodeType.DEFAULT:
|
if node_type == core_pb2.NodeType.DEFAULT:
|
||||||
self.serviceconfig_manager.node_default_services_configuration(
|
self.serviceconfig_manager.node_default_services_configuration(
|
||||||
node_id=node_id, node_model=model
|
node_id=node_id, node_model=model
|
||||||
|
|
|
@ -3,9 +3,9 @@ import tkinter as tk
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
from tkinter import ttk
|
from tkinter import ttk
|
||||||
|
|
||||||
from coretk.coreclient import CustomNode
|
|
||||||
from coretk.dialogs.dialog import Dialog
|
from coretk.dialogs.dialog import Dialog
|
||||||
from coretk.dialogs.icondialog import IconDialog
|
from coretk.dialogs.icondialog import IconDialog
|
||||||
|
from coretk.nodeutils import NodeDraw
|
||||||
from coretk.widgets import CheckboxList, ListboxScroll
|
from coretk.widgets import CheckboxList, ListboxScroll
|
||||||
|
|
||||||
|
|
||||||
|
@ -119,7 +119,9 @@ class CustomNodesDialog(Dialog):
|
||||||
frame.columnconfigure(0, weight=1)
|
frame.columnconfigure(0, weight=1)
|
||||||
entry = ttk.Entry(frame, textvariable=self.name)
|
entry = ttk.Entry(frame, textvariable=self.name)
|
||||||
entry.grid(sticky="ew")
|
entry.grid(sticky="ew")
|
||||||
self.image_button = ttk.Button(frame, text="Icon", command=self.click_icon)
|
self.image_button = ttk.Button(
|
||||||
|
frame, text="Icon", compound=tk.LEFT, command=self.click_icon
|
||||||
|
)
|
||||||
self.image_button.grid(sticky="ew")
|
self.image_button.grid(sticky="ew")
|
||||||
button = ttk.Button(frame, text="Services", command=self.click_services)
|
button = ttk.Button(frame, text="Services", command=self.click_services)
|
||||||
button.grid(sticky="ew")
|
button.grid(sticky="ew")
|
||||||
|
@ -180,12 +182,12 @@ class CustomNodesDialog(Dialog):
|
||||||
def click_save(self):
|
def click_save(self):
|
||||||
self.app.config["nodes"].clear()
|
self.app.config["nodes"].clear()
|
||||||
for name in sorted(self.app.core.custom_nodes):
|
for name in sorted(self.app.core.custom_nodes):
|
||||||
custom_node = self.app.core.custom_nodes[name]
|
node_draw = self.app.core.custom_nodes[name]
|
||||||
self.app.config["nodes"].append(
|
self.app.config["nodes"].append(
|
||||||
{
|
{
|
||||||
"name": custom_node.name,
|
"name": name,
|
||||||
"image": custom_node.image_file,
|
"image": node_draw.image_file,
|
||||||
"services": list(custom_node.services),
|
"services": list(node_draw.services),
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
logging.info("saving custom nodes: %s", self.app.config["nodes"])
|
logging.info("saving custom nodes: %s", self.app.config["nodes"])
|
||||||
|
@ -195,10 +197,9 @@ class CustomNodesDialog(Dialog):
|
||||||
def click_create(self):
|
def click_create(self):
|
||||||
name = self.name.get()
|
name = self.name.get()
|
||||||
if name not in self.app.core.custom_nodes:
|
if name not in self.app.core.custom_nodes:
|
||||||
custom_node = CustomNode(
|
image_file = Path(self.image_file).stem
|
||||||
name, self.image, Path(self.image_file).name, set(self.services)
|
node_draw = NodeDraw.from_custom(name, image_file, set(self.services))
|
||||||
)
|
self.app.core.custom_nodes[name] = node_draw
|
||||||
self.app.core.custom_nodes[name] = custom_node
|
|
||||||
self.nodes_list.listbox.insert(tk.END, name)
|
self.nodes_list.listbox.insert(tk.END, name)
|
||||||
self.reset_values()
|
self.reset_values()
|
||||||
|
|
||||||
|
@ -207,12 +208,12 @@ class CustomNodesDialog(Dialog):
|
||||||
if self.selected:
|
if self.selected:
|
||||||
previous_name = self.selected
|
previous_name = self.selected
|
||||||
self.selected = name
|
self.selected = name
|
||||||
custom_node = self.app.core.custom_nodes.pop(previous_name)
|
node_draw = self.app.core.custom_nodes.pop(previous_name)
|
||||||
custom_node.name = name
|
node_draw.model = name
|
||||||
custom_node.image = self.image
|
node_draw.image_file = Path(self.image_file).stem
|
||||||
custom_node.image_file = Path(self.image_file).stem
|
node_draw.image = self.image
|
||||||
custom_node.services = self.services
|
node_draw.services = self.services
|
||||||
self.app.core.custom_nodes[name] = custom_node
|
self.app.core.custom_nodes[name] = node_draw
|
||||||
self.nodes_list.listbox.delete(self.selected_index)
|
self.nodes_list.listbox.delete(self.selected_index)
|
||||||
self.nodes_list.listbox.insert(self.selected_index, name)
|
self.nodes_list.listbox.insert(self.selected_index, name)
|
||||||
self.nodes_list.listbox.selection_set(self.selected_index)
|
self.nodes_list.listbox.selection_set(self.selected_index)
|
||||||
|
@ -230,11 +231,11 @@ class CustomNodesDialog(Dialog):
|
||||||
if selection:
|
if selection:
|
||||||
self.selected_index = selection[0]
|
self.selected_index = selection[0]
|
||||||
self.selected = self.nodes_list.listbox.get(self.selected_index)
|
self.selected = self.nodes_list.listbox.get(self.selected_index)
|
||||||
custom_node = self.app.core.custom_nodes[self.selected]
|
node_draw = self.app.core.custom_nodes[self.selected]
|
||||||
self.name.set(custom_node.name)
|
self.name.set(node_draw.model)
|
||||||
self.services = custom_node.services
|
self.services = node_draw.services
|
||||||
self.image = custom_node.image
|
self.image = node_draw.image
|
||||||
self.image_file = custom_node.image_file
|
self.image_file = node_draw.image_file
|
||||||
self.image_button.config(image=self.image)
|
self.image_button.config(image=self.image)
|
||||||
self.edit_button.config(state=tk.NORMAL)
|
self.edit_button.config(state=tk.NORMAL)
|
||||||
self.delete_button.config(state=tk.NORMAL)
|
self.delete_button.config(state=tk.NORMAL)
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
import tkinter as tk
|
import tkinter as tk
|
||||||
from tkinter import filedialog, ttk
|
from tkinter import filedialog, ttk
|
||||||
|
|
||||||
|
from coretk import nodeutils
|
||||||
from coretk.appconfig import ICONS_PATH
|
from coretk.appconfig import ICONS_PATH
|
||||||
from coretk.dialogs.dialog import Dialog
|
from coretk.dialogs.dialog import Dialog
|
||||||
from coretk.images import Images
|
from coretk.images import Images
|
||||||
|
@ -54,7 +55,7 @@ class IconDialog(Dialog):
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
if file_path:
|
if file_path:
|
||||||
self.image = Images.create(file_path, 32, 32)
|
self.image = Images.create(file_path, nodeutils.ICON_SIZE)
|
||||||
self.image_label.config(image=self.image)
|
self.image_label.config(image=self.image)
|
||||||
self.file_path.set(file_path)
|
self.file_path.set(file_path)
|
||||||
|
|
||||||
|
|
|
@ -11,6 +11,7 @@ from coretk.graph_helper import GraphHelper, WlanAntennaManager
|
||||||
from coretk.images import Images
|
from coretk.images import Images
|
||||||
from coretk.linkinfo import LinkInfo, Throughput
|
from coretk.linkinfo import LinkInfo, Throughput
|
||||||
from coretk.nodedelete import CanvasComponentManagement
|
from coretk.nodedelete import CanvasComponentManagement
|
||||||
|
from coretk.nodeutils import NodeUtils
|
||||||
from coretk.wirelessconnection import WirelessConnection
|
from coretk.wirelessconnection import WirelessConnection
|
||||||
|
|
||||||
|
|
||||||
|
@ -37,9 +38,7 @@ class CanvasGraph(tk.Canvas):
|
||||||
kwargs["highlightthickness"] = 0
|
kwargs["highlightthickness"] = 0
|
||||||
super().__init__(master, cnf, **kwargs)
|
super().__init__(master, cnf, **kwargs)
|
||||||
self.mode = GraphMode.SELECT
|
self.mode = GraphMode.SELECT
|
||||||
self.draw_node_image = None
|
self.node_draw = None
|
||||||
self.draw_node_type = None
|
|
||||||
self.draw_node_model = None
|
|
||||||
self.selected = None
|
self.selected = None
|
||||||
self.node_context = None
|
self.node_context = None
|
||||||
self.nodes = {}
|
self.nodes = {}
|
||||||
|
@ -96,9 +95,7 @@ class CanvasGraph(tk.Canvas):
|
||||||
|
|
||||||
# set the private variables to default value
|
# set the private variables to default value
|
||||||
self.mode = GraphMode.SELECT
|
self.mode = GraphMode.SELECT
|
||||||
self.draw_node_image = None
|
self.node_draw = None
|
||||||
self.draw_node_type = None
|
|
||||||
self.draw_node_model = None
|
|
||||||
self.selected = None
|
self.selected = None
|
||||||
self.node_context = None
|
self.node_context = None
|
||||||
self.nodes.clear()
|
self.nodes.clear()
|
||||||
|
@ -157,7 +154,7 @@ class CanvasGraph(tk.Canvas):
|
||||||
continue
|
continue
|
||||||
|
|
||||||
# draw nodes on the canvas
|
# draw nodes on the canvas
|
||||||
image = Images.node_icon(core_node.type, core_node.model)
|
image = NodeUtils.node_icon(core_node.type, core_node.model)
|
||||||
position = core_node.position
|
position = core_node.position
|
||||||
node = CanvasNode(position.x, position.y, image, self.master, core_node)
|
node = CanvasNode(position.x, position.y, image, self.master, core_node)
|
||||||
self.nodes[node.id] = node
|
self.nodes[node.id] = node
|
||||||
|
@ -267,13 +264,7 @@ class CanvasGraph(tk.Canvas):
|
||||||
self.handle_edge_release(event)
|
self.handle_edge_release(event)
|
||||||
elif self.mode == GraphMode.NODE:
|
elif self.mode == GraphMode.NODE:
|
||||||
x, y = self.canvas_xy(event)
|
x, y = self.canvas_xy(event)
|
||||||
self.add_node(
|
self.add_node(x, y)
|
||||||
x,
|
|
||||||
y,
|
|
||||||
self.draw_node_image,
|
|
||||||
self.draw_node_type,
|
|
||||||
self.draw_node_model,
|
|
||||||
)
|
|
||||||
elif self.mode == GraphMode.PICKNODE:
|
elif self.mode == GraphMode.PICKNODE:
|
||||||
self.mode = GraphMode.NODE
|
self.mode = GraphMode.NODE
|
||||||
|
|
||||||
|
@ -404,12 +395,14 @@ class CanvasGraph(tk.Canvas):
|
||||||
# delete the related data from core
|
# delete the related data from core
|
||||||
self.core.delete_wanted_graph_nodes(node_ids, to_delete_edge_tokens)
|
self.core.delete_wanted_graph_nodes(node_ids, to_delete_edge_tokens)
|
||||||
|
|
||||||
def add_node(self, x, y, image, node_type, model):
|
def add_node(self, x, y):
|
||||||
plot_id = self.find_all()[0]
|
plot_id = self.find_all()[0]
|
||||||
logging.info("add node event: %s - %s", plot_id, self.selected)
|
logging.info("add node event: %s - %s", plot_id, self.selected)
|
||||||
if self.selected == plot_id:
|
if self.selected == plot_id:
|
||||||
core_node = self.core.create_node(int(x), int(y), node_type, model)
|
core_node = self.core.create_node(
|
||||||
node = CanvasNode(x, y, image, self.master, core_node)
|
int(x), int(y), self.node_draw.node_type, self.node_draw.model
|
||||||
|
)
|
||||||
|
node = CanvasNode(x, y, self.node_draw.image, self.master, core_node)
|
||||||
self.core.canvas_nodes[core_node.id] = node
|
self.core.canvas_nodes[core_node.id] = node
|
||||||
self.nodes[node.id] = node
|
self.nodes[node.id] = node
|
||||||
return node
|
return node
|
||||||
|
|
|
@ -1,9 +1,7 @@
|
||||||
import logging
|
|
||||||
from enum import Enum
|
from enum import Enum
|
||||||
|
|
||||||
from PIL import Image, ImageTk
|
from PIL import Image, ImageTk
|
||||||
|
|
||||||
from core.api.grpc import core_pb2
|
|
||||||
from coretk.appconfig import LOCAL_ICONS_PATH
|
from coretk.appconfig import LOCAL_ICONS_PATH
|
||||||
|
|
||||||
NODE_WIDTH = 32
|
NODE_WIDTH = 32
|
||||||
|
@ -35,45 +33,6 @@ class Images:
|
||||||
file_path = cls.images[name]
|
file_path = cls.images[name]
|
||||||
return cls.create(file_path, width, height)
|
return cls.create(file_path, width, height)
|
||||||
|
|
||||||
@classmethod
|
|
||||||
def node_icon(cls, node_type, node_model):
|
|
||||||
"""
|
|
||||||
Retrieve image based on type and model
|
|
||||||
:param core_pb2.NodeType node_type: core node type
|
|
||||||
:param string node_model: the node model
|
|
||||||
:return: core node icon
|
|
||||||
:rtype: PhotoImage
|
|
||||||
"""
|
|
||||||
image_enum = ImageEnum.ROUTER
|
|
||||||
if node_type == core_pb2.NodeType.SWITCH:
|
|
||||||
image_enum = ImageEnum.SWITCH
|
|
||||||
elif node_type == core_pb2.NodeType.HUB:
|
|
||||||
image_enum = ImageEnum.HUB
|
|
||||||
elif node_type == core_pb2.NodeType.WIRELESS_LAN:
|
|
||||||
image_enum = ImageEnum.WLAN
|
|
||||||
elif node_type == core_pb2.NodeType.EMANE:
|
|
||||||
image_enum = ImageEnum.EMANE
|
|
||||||
elif node_type == core_pb2.NodeType.RJ45:
|
|
||||||
image_enum = ImageEnum.RJ45
|
|
||||||
elif node_type == core_pb2.NodeType.TUNNEL:
|
|
||||||
image_enum = ImageEnum.TUNNEL
|
|
||||||
elif node_type == core_pb2.NodeType.DEFAULT:
|
|
||||||
if node_model == "router":
|
|
||||||
image_enum = ImageEnum.ROUTER
|
|
||||||
elif node_model == "host":
|
|
||||||
image_enum = ImageEnum.HOST
|
|
||||||
elif node_model == "PC":
|
|
||||||
image_enum = ImageEnum.PC
|
|
||||||
elif node_model == "mdr":
|
|
||||||
image_enum = ImageEnum.MDR
|
|
||||||
elif node_model == "prouter":
|
|
||||||
image_enum = ImageEnum.PROUTER
|
|
||||||
else:
|
|
||||||
logging.error("invalid node model: %s", node_model)
|
|
||||||
else:
|
|
||||||
logging.error("invalid node type: %s", node_type)
|
|
||||||
return Images.get(image_enum, NODE_WIDTH)
|
|
||||||
|
|
||||||
|
|
||||||
class ImageEnum(Enum):
|
class ImageEnum(Enum):
|
||||||
SWITCH = "lanswitch"
|
SWITCH = "lanswitch"
|
||||||
|
|
79
coretk/coretk/nodeutils.py
Normal file
79
coretk/coretk/nodeutils.py
Normal file
|
@ -0,0 +1,79 @@
|
||||||
|
from core.api.grpc.core_pb2 import NodeType
|
||||||
|
from coretk.images import ImageEnum, Images
|
||||||
|
|
||||||
|
ICON_SIZE = 32
|
||||||
|
|
||||||
|
|
||||||
|
class NodeDraw:
|
||||||
|
def __init__(self):
|
||||||
|
self.custom = False
|
||||||
|
self.image = None
|
||||||
|
self.image_enum = None
|
||||||
|
self.image_file = None
|
||||||
|
self.node_type = None
|
||||||
|
self.model = None
|
||||||
|
self.tooltip = None
|
||||||
|
self.services = set()
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def from_setup(cls, image_enum, node_type, model=None, tooltip=None):
|
||||||
|
node_draw = NodeDraw()
|
||||||
|
node_draw.image_enum = image_enum
|
||||||
|
node_draw.image = Images.get(image_enum, ICON_SIZE)
|
||||||
|
node_draw.node_type = node_type
|
||||||
|
node_draw.model = model
|
||||||
|
if tooltip is None:
|
||||||
|
tooltip = model
|
||||||
|
node_draw.tooltip = tooltip
|
||||||
|
return node_draw
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def from_custom(cls, name, image_file, services):
|
||||||
|
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.node_type = NodeType.DEFAULT
|
||||||
|
node_draw.services = services
|
||||||
|
node_draw.model = name
|
||||||
|
node_draw.tooltip = name
|
||||||
|
return node_draw
|
||||||
|
|
||||||
|
|
||||||
|
class NodeUtils:
|
||||||
|
NODES = []
|
||||||
|
NETWORK_NODES = []
|
||||||
|
NODE_ICONS = {}
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def node_icon(cls, node_type, model):
|
||||||
|
return cls.NODE_ICONS[(node_type, model)]
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def setup(cls):
|
||||||
|
nodes = [
|
||||||
|
(ImageEnum.ROUTER, NodeType.DEFAULT, "router"),
|
||||||
|
(ImageEnum.HOST, NodeType.DEFAULT, "host"),
|
||||||
|
(ImageEnum.PC, NodeType.DEFAULT, "PC"),
|
||||||
|
(ImageEnum.MDR, NodeType.DEFAULT, "mdr"),
|
||||||
|
(ImageEnum.PROUTER, NodeType.DEFAULT, "prouter"),
|
||||||
|
(ImageEnum.DOCKER, NodeType.DOCKER, "Docker"),
|
||||||
|
(ImageEnum.LXC, NodeType.LXC, "LXC"),
|
||||||
|
]
|
||||||
|
for image_enum, node_type, model in nodes:
|
||||||
|
node_draw = NodeDraw.from_setup(image_enum, node_type, model)
|
||||||
|
cls.NODES.append(node_draw)
|
||||||
|
cls.NODE_ICONS[(node_type, model)] = node_draw.image
|
||||||
|
|
||||||
|
network_nodes = [
|
||||||
|
(ImageEnum.HUB, NodeType.HUB, "ethernet hub"),
|
||||||
|
(ImageEnum.SWITCH, NodeType.SWITCH, "ethernet switch"),
|
||||||
|
(ImageEnum.WLAN, NodeType.WIRELESS_LAN, "wireless LAN"),
|
||||||
|
(ImageEnum.EMANE, NodeType.EMANE, "EMANE"),
|
||||||
|
(ImageEnum.RJ45, NodeType.RJ45, "rj45 physical interface tool"),
|
||||||
|
(ImageEnum.TUNNEL, NodeType.TUNNEL, "tunnel tool"),
|
||||||
|
]
|
||||||
|
for image_enum, node_type, tooltip in network_nodes:
|
||||||
|
node_draw = NodeDraw.from_setup(image_enum, node_type, tooltip=tooltip)
|
||||||
|
cls.NETWORK_NODES.append(node_draw)
|
||||||
|
cls.NODE_ICONS[(node_type, None)] = node_draw.image
|
|
@ -54,7 +54,12 @@ def load(style):
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
"TButton": {
|
"TButton": {
|
||||||
"configure": {"width": 8, "padding": (5, 1), "relief": tk.RAISED},
|
"configure": {
|
||||||
|
"width": 8,
|
||||||
|
"padding": (5, 1),
|
||||||
|
"relief": tk.RAISED,
|
||||||
|
"anchor": tk.CENTER,
|
||||||
|
},
|
||||||
"map": {
|
"map": {
|
||||||
"relief": [("pressed", tk.SUNKEN)],
|
"relief": [("pressed", tk.SUNKEN)],
|
||||||
"shiftrelief": [("pressed", 1)],
|
"shiftrelief": [("pressed", 1)],
|
||||||
|
|
|
@ -3,10 +3,10 @@ import tkinter as tk
|
||||||
from functools import partial
|
from functools import partial
|
||||||
from tkinter import ttk
|
from tkinter import ttk
|
||||||
|
|
||||||
from core.api.grpc import core_pb2
|
|
||||||
from coretk.dialogs.customnodes import CustomNodesDialog
|
from coretk.dialogs.customnodes import CustomNodesDialog
|
||||||
from coretk.graph import GraphMode
|
from coretk.graph import GraphMode
|
||||||
from coretk.images import ImageEnum, Images
|
from coretk.images import ImageEnum, Images
|
||||||
|
from coretk.nodeutils import NodeUtils
|
||||||
from coretk.tooltip import Tooltip
|
from coretk.tooltip import Tooltip
|
||||||
|
|
||||||
WIDTH = 32
|
WIDTH = 32
|
||||||
|
@ -129,33 +129,16 @@ class Toolbar(ttk.Frame):
|
||||||
def draw_node_picker(self):
|
def draw_node_picker(self):
|
||||||
self.hide_pickers()
|
self.hide_pickers()
|
||||||
self.node_picker = ttk.Frame(self.master)
|
self.node_picker = ttk.Frame(self.master)
|
||||||
nodes = [
|
|
||||||
(ImageEnum.ROUTER, core_pb2.NodeType.DEFAULT, "router"),
|
|
||||||
(ImageEnum.HOST, core_pb2.NodeType.DEFAULT, "host"),
|
|
||||||
(ImageEnum.PC, core_pb2.NodeType.DEFAULT, "PC"),
|
|
||||||
(ImageEnum.MDR, core_pb2.NodeType.DEFAULT, "mdr"),
|
|
||||||
(ImageEnum.PROUTER, core_pb2.NodeType.DEFAULT, "prouter"),
|
|
||||||
(ImageEnum.DOCKER, core_pb2.NodeType.DOCKER, "Docker"),
|
|
||||||
(ImageEnum.LXC, core_pb2.NodeType.LXC, "LXC"),
|
|
||||||
]
|
|
||||||
# draw default nodes
|
# draw default nodes
|
||||||
for image_enum, node_type, model in nodes:
|
for node_draw in NodeUtils.NODES:
|
||||||
image = icon(image_enum)
|
image = icon(node_draw.image_enum)
|
||||||
func = partial(
|
func = partial(self.update_button, self.node_button, image, node_draw)
|
||||||
self.update_button, self.node_button, image, node_type, model
|
self.create_picker_button(image, func, self.node_picker, node_draw.tooltip)
|
||||||
)
|
|
||||||
self.create_picker_button(image, func, self.node_picker, model)
|
|
||||||
# draw custom nodes
|
# draw custom nodes
|
||||||
for name in sorted(self.app.core.custom_nodes):
|
for name in sorted(self.app.core.custom_nodes):
|
||||||
custom_node = self.app.core.custom_nodes[name]
|
node_draw = self.app.core.custom_nodes[name]
|
||||||
image = custom_node.image
|
image = Images.get_custom(node_draw.image_file, WIDTH)
|
||||||
func = partial(
|
func = partial(self.update_button, self.node_button, image, node_draw)
|
||||||
self.update_button,
|
|
||||||
self.node_button,
|
|
||||||
image,
|
|
||||||
core_pb2.NodeType.DEFAULT,
|
|
||||||
name,
|
|
||||||
)
|
|
||||||
self.create_picker_button(image, func, self.node_picker, name)
|
self.create_picker_button(image, func, self.node_picker, name)
|
||||||
# draw edit node
|
# draw edit node
|
||||||
image = icon(ImageEnum.EDITNODE)
|
image = icon(ImageEnum.EDITNODE)
|
||||||
|
@ -227,15 +210,13 @@ class Toolbar(ttk.Frame):
|
||||||
dialog = CustomNodesDialog(self.app, self.app)
|
dialog = CustomNodesDialog(self.app, self.app)
|
||||||
dialog.show()
|
dialog.show()
|
||||||
|
|
||||||
def update_button(self, button, image, node_type, model=None):
|
def update_button(self, button, image, node_draw):
|
||||||
logging.info("update button(%s): %s", button, node_type)
|
logging.info("update button(%s): %s", button, node_draw)
|
||||||
self.hide_pickers()
|
self.hide_pickers()
|
||||||
button.configure(image=image)
|
button.configure(image=image)
|
||||||
button.image = image
|
button.image = image
|
||||||
self.app.canvas.mode = GraphMode.NODE
|
self.app.canvas.mode = GraphMode.NODE
|
||||||
self.app.canvas.draw_node_image = image
|
self.app.canvas.node_draw = node_draw
|
||||||
self.app.canvas.draw_node_type = node_type
|
|
||||||
self.app.canvas.draw_node_model = model
|
|
||||||
|
|
||||||
def hide_pickers(self):
|
def hide_pickers(self):
|
||||||
logging.info("hiding pickers")
|
logging.info("hiding pickers")
|
||||||
|
@ -271,21 +252,13 @@ class Toolbar(ttk.Frame):
|
||||||
"""
|
"""
|
||||||
self.hide_pickers()
|
self.hide_pickers()
|
||||||
self.network_picker = ttk.Frame(self.master)
|
self.network_picker = ttk.Frame(self.master)
|
||||||
nodes = [
|
for node_draw in NodeUtils.NETWORK_NODES:
|
||||||
(ImageEnum.HUB, core_pb2.NodeType.HUB, "ethernet hub"),
|
image = icon(node_draw.image_enum)
|
||||||
(ImageEnum.SWITCH, core_pb2.NodeType.SWITCH, "ethernet switch"),
|
|
||||||
(ImageEnum.WLAN, core_pb2.NodeType.WIRELESS_LAN, "wireless LAN"),
|
|
||||||
(ImageEnum.EMANE, core_pb2.NodeType.EMANE, "EMANE"),
|
|
||||||
(ImageEnum.RJ45, core_pb2.NodeType.RJ45, "rj45 physical interface tool"),
|
|
||||||
(ImageEnum.TUNNEL, core_pb2.NodeType.TUNNEL, "tunnel tool"),
|
|
||||||
]
|
|
||||||
for image_enum, node_type, tooltip in nodes:
|
|
||||||
image = icon(image_enum)
|
|
||||||
self.create_picker_button(
|
self.create_picker_button(
|
||||||
image,
|
image,
|
||||||
partial(self.update_button, self.network_button, image, node_type),
|
partial(self.update_button, self.network_button, image, node_draw),
|
||||||
self.network_picker,
|
self.network_picker,
|
||||||
tooltip,
|
node_draw.tooltip,
|
||||||
)
|
)
|
||||||
self.design_select(self.network_button)
|
self.design_select(self.network_button)
|
||||||
self.network_button.after(
|
self.network_button.after(
|
||||||
|
@ -294,7 +267,8 @@ class Toolbar(ttk.Frame):
|
||||||
|
|
||||||
def create_network_button(self):
|
def create_network_button(self):
|
||||||
"""
|
"""
|
||||||
Create link-layer node button and the options that represent different link-layer node types
|
Create link-layer node button and the options that represent different
|
||||||
|
link-layer node types.
|
||||||
|
|
||||||
:return: nothing
|
:return: nothing
|
||||||
"""
|
"""
|
||||||
|
|
Loading…
Add table
Reference in a new issue