tweaks to retrieving images/icons, updates to toolbar to use ttk widgets
This commit is contained in:
parent
b96f8ff999
commit
14187ba79c
10 changed files with 221 additions and 234 deletions
|
@ -1,5 +1,6 @@
|
|||
import logging
|
||||
import tkinter as tk
|
||||
from tkinter import ttk
|
||||
|
||||
from coretk import appconfig
|
||||
from coretk.coreclient import CoreClient
|
||||
|
@ -36,7 +37,7 @@ class Application(tk.Frame):
|
|||
self.master.title("CORE")
|
||||
self.master.geometry("1000x800")
|
||||
self.master.protocol("WM_DELETE_WINDOW", self.on_closing)
|
||||
image = Images.get(ImageEnum.CORE)
|
||||
image = Images.get(ImageEnum.CORE, 16)
|
||||
self.master.tk.call("wm", "iconphoto", self.master._w, image)
|
||||
self.pack(fill=tk.BOTH, expand=True)
|
||||
|
||||
|
@ -53,17 +54,17 @@ class Application(tk.Frame):
|
|||
self, self.core, background="#cccccc", scrollregion=(0, 0, 1200, 1000)
|
||||
)
|
||||
self.canvas.pack(fill=tk.BOTH, expand=True)
|
||||
scroll_x = tk.Scrollbar(
|
||||
scroll_x = ttk.Scrollbar(
|
||||
self.canvas, orient=tk.HORIZONTAL, command=self.canvas.xview
|
||||
)
|
||||
scroll_x.pack(side=tk.BOTTOM, fill=tk.X)
|
||||
scroll_y = tk.Scrollbar(self.canvas, command=self.canvas.yview)
|
||||
scroll_y = ttk.Scrollbar(self.canvas, command=self.canvas.yview)
|
||||
scroll_y.pack(side=tk.RIGHT, fill=tk.Y)
|
||||
self.canvas.configure(xscrollcommand=scroll_x.set)
|
||||
self.canvas.configure(yscrollcommand=scroll_y.set)
|
||||
|
||||
def draw_status(self):
|
||||
self.statusbar = tk.Frame(self)
|
||||
self.statusbar = ttk.Frame(self)
|
||||
self.statusbar.pack(side=tk.BOTTOM, fill=tk.X)
|
||||
|
||||
def on_closing(self):
|
||||
|
|
|
@ -8,7 +8,7 @@ from core.api.grpc import client, core_pb2
|
|||
from coretk.coretocanvas import CoreToCanvasMapping
|
||||
from coretk.dialogs.sessions import SessionsDialog
|
||||
from coretk.emaneodelnodeconfig import EmaneModelNodeConfig
|
||||
from coretk.images import Images
|
||||
from coretk.images import NODE_WIDTH, Images
|
||||
from coretk.interface import Interface, InterfaceManager
|
||||
from coretk.mobilitynodeconfig import MobilityNodeConfig
|
||||
from coretk.wlannodeconfig import WlanNodeConfig
|
||||
|
@ -137,7 +137,7 @@ class CoreClient:
|
|||
# read custom nodes
|
||||
for config in self.app.config.get("nodes", []):
|
||||
image_file = config["image"]
|
||||
image = Images.get_custom(image_file)
|
||||
image = Images.get_custom(image_file, NODE_WIDTH)
|
||||
custom_node = CustomNode(
|
||||
config["name"], image, image_file, set(config["services"])
|
||||
)
|
||||
|
|
|
@ -13,7 +13,7 @@ class Dialog(tk.Toplevel):
|
|||
self.modal = modal
|
||||
self.title(title)
|
||||
self.protocol("WM_DELETE_WINDOW", self.destroy)
|
||||
image = Images.get(ImageEnum.CORE)
|
||||
image = Images.get(ImageEnum.CORE, 16)
|
||||
self.tk.call("wm", "iconphoto", self._w, image)
|
||||
|
||||
def show(self):
|
||||
|
|
|
@ -182,25 +182,31 @@ class EmaneConfiguration(Dialog):
|
|||
|
||||
def draw_option_buttons(self, parent):
|
||||
f = ttk.Frame(parent)
|
||||
f.grid(row=4, column=0, sticky="nsew")
|
||||
f.columnconfigure(0, weight=1)
|
||||
f.columnconfigure(1, weight=1)
|
||||
|
||||
image = Images.get(ImageEnum.EDITNODE, 16)
|
||||
b = ttk.Button(
|
||||
f,
|
||||
text=self.emane_models[0] + " options",
|
||||
image=Images.get(ImageEnum.EDITNODE),
|
||||
image=image,
|
||||
compound=tk.RIGHT,
|
||||
command=self.draw_model_options,
|
||||
)
|
||||
b.image = image
|
||||
b.grid(row=0, column=0, padx=10, pady=2, sticky="nsew")
|
||||
|
||||
image = Images.get(ImageEnum.EDITNODE, 16)
|
||||
b = ttk.Button(
|
||||
f,
|
||||
text="EMANE options",
|
||||
image=Images.get(ImageEnum.EDITNODE),
|
||||
image=image,
|
||||
compound=tk.RIGHT,
|
||||
command=self.draw_emane_options,
|
||||
)
|
||||
b.image = image
|
||||
b.grid(row=0, column=1, padx=10, pady=2, sticky="nsew")
|
||||
f.grid(row=4, column=0, sticky="nsew")
|
||||
|
||||
def combobox_select(self, event):
|
||||
"""
|
||||
|
@ -271,7 +277,7 @@ class EmaneConfiguration(Dialog):
|
|||
|
||||
b = ttk.Button(
|
||||
f,
|
||||
image=Images.get(ImageEnum.EDITNODE),
|
||||
image=Images.get(ImageEnum.EDITNODE, 8),
|
||||
text="EMANE Wiki",
|
||||
compound=tk.RIGHT,
|
||||
command=lambda: webbrowser.open_new(
|
||||
|
|
|
@ -54,7 +54,7 @@ class IconDialog(Dialog):
|
|||
),
|
||||
)
|
||||
if file_path:
|
||||
self.image = Images.create(file_path)
|
||||
self.image = Images.create(file_path, 32, 32)
|
||||
self.image_label.config(image=self.image)
|
||||
self.file_path.set(file_path)
|
||||
|
||||
|
|
|
@ -73,30 +73,36 @@ class SessionsDialog(Dialog):
|
|||
for i in range(4):
|
||||
frame.columnconfigure(i, weight=1)
|
||||
frame.grid(row=3, sticky="ew")
|
||||
|
||||
image = Images.get(ImageEnum.DOCUMENTNEW, 16)
|
||||
b = ttk.Button(
|
||||
frame,
|
||||
image=Images.get(ImageEnum.DOCUMENTNEW),
|
||||
text="New",
|
||||
compound=tk.LEFT,
|
||||
command=self.click_new,
|
||||
frame, image=image, text="New", compound=tk.LEFT, command=self.click_new
|
||||
)
|
||||
b.image = image
|
||||
b.grid(row=0, padx=2, sticky="ew")
|
||||
|
||||
image = Images.get(ImageEnum.FILEOPEN, 16)
|
||||
b = ttk.Button(
|
||||
frame,
|
||||
image=Images.get(ImageEnum.FILEOPEN),
|
||||
image=image,
|
||||
text="Connect",
|
||||
compound=tk.LEFT,
|
||||
command=self.click_connect,
|
||||
)
|
||||
b.image = image
|
||||
b.grid(row=0, column=1, padx=2, sticky="ew")
|
||||
|
||||
image = Images.get(ImageEnum.EDITDELETE, 16)
|
||||
b = ttk.Button(
|
||||
frame,
|
||||
image=Images.get(ImageEnum.EDITDELETE),
|
||||
image=image,
|
||||
text="Shutdown",
|
||||
compound=tk.LEFT,
|
||||
command=self.click_shutdown,
|
||||
)
|
||||
b.image = image
|
||||
b.grid(row=0, column=2, padx=2, sticky="ew")
|
||||
|
||||
b = ttk.Button(frame, text="Cancel", command=self.click_new)
|
||||
b.grid(row=0, column=3, padx=2, sticky="ew")
|
||||
|
||||
|
|
|
@ -146,9 +146,7 @@ class CanvasGraph(tk.Canvas):
|
|||
# peer to peer node is not drawn on the GUI
|
||||
if node.type != core_pb2.NodeType.PEER_TO_PEER:
|
||||
# draw nodes on the canvas
|
||||
image, name = Images.convert_type_and_model_to_image(
|
||||
node.type, node.model
|
||||
)
|
||||
image, name = Images.node_icon(node.type, node.model)
|
||||
n = CanvasNode(
|
||||
node.position.x, node.position.y, image, name, self.master, node.id
|
||||
)
|
||||
|
|
|
@ -77,6 +77,7 @@ class WlanAntennaManager:
|
|||
self.quantity = 0
|
||||
self._max = 5
|
||||
self.antennas = []
|
||||
self.image = Images.get(ImageEnum.ANTENNA, 32)
|
||||
|
||||
# distance between each antenna
|
||||
self.offset = 0
|
||||
|
@ -94,7 +95,7 @@ class WlanAntennaManager:
|
|||
x - 16 + self.offset,
|
||||
y - 16,
|
||||
anchor=tk.CENTER,
|
||||
image=Images.get(ImageEnum.ANTENNA),
|
||||
image=self.image,
|
||||
tags="antenna",
|
||||
)
|
||||
)
|
||||
|
|
|
@ -6,35 +6,37 @@ from PIL import Image, ImageTk
|
|||
from core.api.grpc import core_pb2
|
||||
from coretk.appconfig import LOCAL_ICONS_PATH
|
||||
|
||||
NODE_WIDTH = 32
|
||||
|
||||
|
||||
class Images:
|
||||
images = {}
|
||||
|
||||
@classmethod
|
||||
def create(cls, file_path):
|
||||
def create(cls, file_path, width, height=None):
|
||||
if height is None:
|
||||
height = width
|
||||
image = Image.open(file_path)
|
||||
image = image.resize((width, height), Image.ANTIALIAS)
|
||||
return ImageTk.PhotoImage(image)
|
||||
|
||||
@classmethod
|
||||
def load_all(cls):
|
||||
for image in LOCAL_ICONS_PATH.glob("*"):
|
||||
cls.load(image.stem, str(image))
|
||||
cls.images[image.stem] = str(image)
|
||||
|
||||
@classmethod
|
||||
def load(cls, name, file_path):
|
||||
tk_image = cls.create(file_path)
|
||||
cls.images[name] = tk_image
|
||||
def get(cls, image_enum, width, height=None):
|
||||
file_path = cls.images[image_enum.value]
|
||||
return cls.create(file_path, width, height)
|
||||
|
||||
@classmethod
|
||||
def get(cls, image):
|
||||
return cls.images[image.value]
|
||||
def get_custom(cls, name, width, height):
|
||||
file_path = cls.images[name]
|
||||
return cls.create(file_path, width, height)
|
||||
|
||||
@classmethod
|
||||
def get_custom(cls, name):
|
||||
return cls.images[name]
|
||||
|
||||
@classmethod
|
||||
def convert_type_and_model_to_image(cls, node_type, node_model):
|
||||
def node_icon(cls, node_type, node_model):
|
||||
"""
|
||||
Retrieve image based on type and model
|
||||
:param core_pb2.NodeType node_type: core node type
|
||||
|
@ -43,34 +45,48 @@ class Images:
|
|||
:rtype: tuple(PhotoImage, str)
|
||||
:return: the matching image and its name
|
||||
"""
|
||||
image_enum = ImageEnum.ROUTER
|
||||
name = "unknown"
|
||||
if node_type == core_pb2.NodeType.SWITCH:
|
||||
return Images.get(ImageEnum.SWITCH), "switch"
|
||||
if node_type == core_pb2.NodeType.HUB:
|
||||
return Images.get(ImageEnum.HUB), "hub"
|
||||
if node_type == core_pb2.NodeType.WIRELESS_LAN:
|
||||
return Images.get(ImageEnum.WLAN), "wlan"
|
||||
if node_type == core_pb2.NodeType.EMANE:
|
||||
return Images.get(ImageEnum.EMANE), "emane"
|
||||
|
||||
if node_type == core_pb2.NodeType.RJ45:
|
||||
return Images.get(ImageEnum.RJ45), "rj45"
|
||||
if node_type == core_pb2.NodeType.TUNNEL:
|
||||
return Images.get(ImageEnum.TUNNEL), "tunnel"
|
||||
if node_type == core_pb2.NodeType.DEFAULT:
|
||||
image_enum = ImageEnum.SWITCH
|
||||
name = "switch"
|
||||
elif node_type == core_pb2.NodeType.HUB:
|
||||
image_enum = ImageEnum.HUB
|
||||
name = "hub"
|
||||
elif node_type == core_pb2.NodeType.WIRELESS_LAN:
|
||||
image_enum = ImageEnum.WLAN
|
||||
name = "wlan"
|
||||
elif node_type == core_pb2.NodeType.EMANE:
|
||||
image_enum = ImageEnum.EMANE
|
||||
name = "emane"
|
||||
elif node_type == core_pb2.NodeType.RJ45:
|
||||
image_enum = ImageEnum.RJ45
|
||||
name = "rj45"
|
||||
elif node_type == core_pb2.NodeType.TUNNEL:
|
||||
image_enum = ImageEnum.TUNNEL
|
||||
name = "tunnel"
|
||||
elif node_type == core_pb2.NodeType.DEFAULT:
|
||||
if node_model == "router":
|
||||
return Images.get(ImageEnum.ROUTER), "router"
|
||||
if node_model == "host":
|
||||
return Images.get(ImageEnum.HOST), "host"
|
||||
if node_model == "PC":
|
||||
return Images.get(ImageEnum.PC), "PC"
|
||||
if node_model == "mdr":
|
||||
return Images.get(ImageEnum.MDR), "mdr"
|
||||
if node_model == "prouter":
|
||||
return Images.get(ImageEnum.PROUTER), "prouter"
|
||||
if node_model == "OVS":
|
||||
return Images.get(ImageEnum.OVS), "ovs"
|
||||
image_enum = ImageEnum.ROUTER
|
||||
name = "router"
|
||||
elif node_model == "host":
|
||||
image_enum = ImageEnum.HOST
|
||||
name = "host"
|
||||
elif node_model == "PC":
|
||||
image_enum = ImageEnum.PC
|
||||
name = "PC"
|
||||
elif node_model == "mdr":
|
||||
image_enum = ImageEnum.MDR
|
||||
name = "mdr"
|
||||
elif node_model == "prouter":
|
||||
image_enum = ImageEnum.PROUTER
|
||||
name = "prouter"
|
||||
else:
|
||||
logging.debug("INVALID INPUT OR NOT CONSIDERED YET")
|
||||
logging.error("invalid node model: %s", node_model)
|
||||
else:
|
||||
logging.error("invalid node type: %s", node_type)
|
||||
|
||||
return Images.get(image_enum, NODE_WIDTH), name
|
||||
|
||||
|
||||
class ImageEnum(Enum):
|
||||
|
|
|
@ -1,43 +1,44 @@
|
|||
import logging
|
||||
import tkinter as tk
|
||||
from functools import partial
|
||||
from tkinter import ttk
|
||||
|
||||
from coretk.dialogs.customnodes import CustomNodesDialog
|
||||
from coretk.graph import GraphMode
|
||||
from coretk.images import ImageEnum, Images
|
||||
from coretk.tooltip import Tooltip
|
||||
|
||||
WIDTH = 32
|
||||
|
||||
class Toolbar(tk.Frame):
|
||||
|
||||
def icon(image_enum):
|
||||
return Images.get(image_enum, WIDTH)
|
||||
|
||||
|
||||
class Toolbar(ttk.Frame):
|
||||
"""
|
||||
Core toolbar class
|
||||
"""
|
||||
|
||||
def __init__(self, master, app, cnf={}, **kwargs):
|
||||
def __init__(self, master, app, **kwargs):
|
||||
"""
|
||||
Create a CoreToolbar instance
|
||||
|
||||
:param tkinter.Frame edit_frame: edit frame
|
||||
"""
|
||||
super().__init__(master, cnf, **kwargs)
|
||||
super().__init__(master, **kwargs)
|
||||
self.app = app
|
||||
self.master = app.master
|
||||
self.radio_value = tk.IntVar()
|
||||
self.exec_radio_value = tk.IntVar()
|
||||
|
||||
# button dimension
|
||||
self.width = 32
|
||||
self.height = 32
|
||||
|
||||
# Reference to the option menus
|
||||
self.selection_tool_button = None
|
||||
self.link_layer_option_menu = None
|
||||
self.marker_option_menu = None
|
||||
self.network_layer_option_menu = None
|
||||
# design buttons
|
||||
self.select_button = None
|
||||
self.link_button = None
|
||||
self.node_button = None
|
||||
self.network_button = None
|
||||
self.annotation_button = None
|
||||
|
||||
# runtime buttons
|
||||
|
||||
# frames
|
||||
self.design_frame = None
|
||||
self.runtime_frame = None
|
||||
|
@ -56,89 +57,77 @@ class Toolbar(tk.Frame):
|
|||
self.design_frame.tkraise()
|
||||
|
||||
def draw_design_frame(self):
|
||||
self.design_frame = tk.Frame(self)
|
||||
self.design_frame = ttk.Frame(self)
|
||||
self.design_frame.grid(row=0, column=0, sticky="nsew")
|
||||
self.design_frame.columnconfigure(0, weight=1)
|
||||
|
||||
self.create_regular_button(
|
||||
self.create_button(
|
||||
self.design_frame,
|
||||
Images.get(ImageEnum.START),
|
||||
self.click_start_session_tool,
|
||||
icon(ImageEnum.START),
|
||||
self.click_start,
|
||||
"start the session",
|
||||
)
|
||||
self.create_radio_button(
|
||||
self.select_button = self.create_button(
|
||||
self.design_frame,
|
||||
Images.get(ImageEnum.SELECT),
|
||||
self.click_selection_tool,
|
||||
self.radio_value,
|
||||
1,
|
||||
icon(ImageEnum.SELECT),
|
||||
self.click_selection,
|
||||
"selection tool",
|
||||
)
|
||||
self.create_radio_button(
|
||||
self.design_frame,
|
||||
Images.get(ImageEnum.LINK),
|
||||
self.click_link_tool,
|
||||
self.radio_value,
|
||||
2,
|
||||
"link tool",
|
||||
self.link_button = self.create_button(
|
||||
self.design_frame, icon(ImageEnum.LINK), self.click_link, "link tool"
|
||||
)
|
||||
self.create_node_button()
|
||||
self.create_network_button()
|
||||
self.create_annotation_button()
|
||||
self.radio_value.set(1)
|
||||
|
||||
def design_select(self, button):
|
||||
logging.info("selecting design button: %s", button)
|
||||
self.select_button.state(["!pressed"])
|
||||
self.link_button.state(["!pressed"])
|
||||
self.node_button.state(["!pressed"])
|
||||
self.network_button.state(["!pressed"])
|
||||
self.annotation_button.state(["!pressed"])
|
||||
button.state(["pressed"])
|
||||
|
||||
def draw_runtime_frame(self):
|
||||
self.runtime_frame = tk.Frame(self)
|
||||
self.runtime_frame = ttk.Frame(self)
|
||||
self.runtime_frame.grid(row=0, column=0, sticky="nsew")
|
||||
self.runtime_frame.columnconfigure(0, weight=1)
|
||||
|
||||
self.create_regular_button(
|
||||
self.create_button(
|
||||
self.runtime_frame,
|
||||
Images.get(ImageEnum.STOP),
|
||||
self.click_stop_button,
|
||||
icon(ImageEnum.STOP),
|
||||
self.click_stop,
|
||||
"stop the session",
|
||||
)
|
||||
self.create_radio_button(
|
||||
self.create_button(
|
||||
self.runtime_frame,
|
||||
Images.get(ImageEnum.SELECT),
|
||||
self.click_selection_tool,
|
||||
self.exec_radio_value,
|
||||
1,
|
||||
icon(ImageEnum.SELECT),
|
||||
self.click_selection,
|
||||
"selection tool",
|
||||
)
|
||||
self.create_observe_button()
|
||||
self.create_radio_button(
|
||||
self.runtime_frame,
|
||||
Images.get(ImageEnum.PLOT),
|
||||
self.click_plot_button,
|
||||
self.exec_radio_value,
|
||||
2,
|
||||
"plot",
|
||||
# self.create_observe_button()
|
||||
self.create_button(
|
||||
self.runtime_frame, icon(ImageEnum.PLOT), self.click_plot_button, "plot"
|
||||
)
|
||||
self.create_radio_button(
|
||||
self.create_button(
|
||||
self.runtime_frame,
|
||||
Images.get(ImageEnum.MARKER),
|
||||
icon(ImageEnum.MARKER),
|
||||
self.click_marker_button,
|
||||
self.exec_radio_value,
|
||||
3,
|
||||
"marker",
|
||||
)
|
||||
self.create_radio_button(
|
||||
self.create_button(
|
||||
self.runtime_frame,
|
||||
Images.get(ImageEnum.TWONODE),
|
||||
icon(ImageEnum.TWONODE),
|
||||
self.click_two_node_button,
|
||||
self.exec_radio_value,
|
||||
4,
|
||||
"run command from one node to another",
|
||||
)
|
||||
self.create_regular_button(
|
||||
self.runtime_frame, Images.get(ImageEnum.RUN), self.click_run_button, "run"
|
||||
self.create_button(
|
||||
self.runtime_frame, icon(ImageEnum.RUN), self.click_run_button, "run"
|
||||
)
|
||||
self.exec_radio_value.set(1)
|
||||
|
||||
def draw_node_picker(self):
|
||||
self.hide_pickers()
|
||||
self.node_picker = tk.Frame(self.master, padx=1, pady=1)
|
||||
self.node_picker = ttk.Frame(self.master)
|
||||
nodes = [
|
||||
(ImageEnum.ROUTER, "router"),
|
||||
(ImageEnum.HOST, "host"),
|
||||
|
@ -148,26 +137,28 @@ class Toolbar(tk.Frame):
|
|||
]
|
||||
# draw default nodes
|
||||
for image_enum, tooltip in nodes:
|
||||
image = Images.get(image_enum)
|
||||
image = icon(image_enum)
|
||||
func = partial(self.update_button, self.node_button, image, tooltip)
|
||||
self.create_button(image, func, self.node_picker, tooltip)
|
||||
self.create_picker_button(image, func, self.node_picker, tooltip)
|
||||
# draw custom nodes
|
||||
for name in sorted(self.app.core.custom_nodes):
|
||||
custom_node = self.app.core.custom_nodes[name]
|
||||
image = custom_node.image
|
||||
func = partial(self.update_button, self.node_button, image, name)
|
||||
self.create_button(image, func, self.node_picker, name)
|
||||
self.create_picker_button(image, func, self.node_picker, name)
|
||||
# draw edit node
|
||||
image = Images.get(ImageEnum.EDITNODE)
|
||||
self.create_button(
|
||||
image = icon(ImageEnum.EDITNODE)
|
||||
self.create_picker_button(
|
||||
image, self.click_edit_node, self.node_picker, "custom nodes"
|
||||
)
|
||||
self.show_picker(self.node_button, self.node_picker)
|
||||
self.design_select(self.node_button)
|
||||
self.node_button.after(
|
||||
0, lambda: self.show_picker(self.node_button, self.node_picker)
|
||||
)
|
||||
|
||||
def show_picker(self, button, picker):
|
||||
first_button = self.winfo_children()[0]
|
||||
x = button.winfo_rootx() - first_button.winfo_rootx() + 40
|
||||
y = button.winfo_rooty() - first_button.winfo_rooty() - 1
|
||||
x = self.winfo_width() + 1
|
||||
y = button.winfo_rooty() - picker.master.winfo_rooty() - 1
|
||||
picker.place(x=x, y=y)
|
||||
self.app.bind_all("<ButtonRelease-1>", lambda e: self.hide_pickers())
|
||||
picker.wait_visibility()
|
||||
|
@ -175,7 +166,7 @@ class Toolbar(tk.Frame):
|
|||
self.wait_window(picker)
|
||||
self.app.unbind_all("<ButtonRelease-1>")
|
||||
|
||||
def create_button(self, image, func, frame, tooltip):
|
||||
def create_picker_button(self, image, func, frame, tooltip):
|
||||
"""
|
||||
Create button and put it on the frame
|
||||
|
||||
|
@ -185,37 +176,25 @@ class Toolbar(tk.Frame):
|
|||
:param str tooltip: tooltip text
|
||||
:return: nothing
|
||||
"""
|
||||
button = tk.Button(frame, width=self.width, height=self.height, image=image)
|
||||
button = ttk.Button(frame, image=image)
|
||||
button.image = image
|
||||
button.bind("<ButtonRelease-1>", lambda e: func())
|
||||
button.grid(pady=1)
|
||||
Tooltip(button, tooltip)
|
||||
|
||||
def create_radio_button(self, frame, image, func, variable, value, tooltip_msg):
|
||||
button = tk.Radiobutton(
|
||||
frame,
|
||||
indicatoron=False,
|
||||
width=self.width,
|
||||
height=self.height,
|
||||
image=image,
|
||||
value=value,
|
||||
variable=variable,
|
||||
command=func,
|
||||
)
|
||||
button.grid()
|
||||
Tooltip(button, tooltip_msg)
|
||||
|
||||
def create_regular_button(self, frame, image, func, tooltip):
|
||||
button = tk.Button(
|
||||
frame, width=self.width, height=self.height, image=image, command=func
|
||||
)
|
||||
button.grid()
|
||||
def create_button(self, frame, image, func, tooltip):
|
||||
button = ttk.Button(frame, image=image, command=func)
|
||||
button.image = image
|
||||
button.grid(sticky="ew")
|
||||
Tooltip(button, tooltip)
|
||||
return button
|
||||
|
||||
def click_selection_tool(self):
|
||||
def click_selection(self):
|
||||
logging.debug("clicked selection tool")
|
||||
self.design_select(self.select_button)
|
||||
self.app.canvas.mode = GraphMode.SELECT
|
||||
|
||||
def click_start_session_tool(self):
|
||||
def click_start(self):
|
||||
"""
|
||||
Start session handler redraw buttons, send node and link messages to grpc
|
||||
server.
|
||||
|
@ -227,8 +206,9 @@ class Toolbar(tk.Frame):
|
|||
self.app.core.start_session()
|
||||
self.runtime_frame.tkraise()
|
||||
|
||||
def click_link_tool(self):
|
||||
def click_link(self):
|
||||
logging.debug("Click LINK button")
|
||||
self.design_select(self.link_button)
|
||||
self.app.canvas.mode = GraphMode.EDGE
|
||||
|
||||
def click_edit_node(self):
|
||||
|
@ -240,6 +220,7 @@ class Toolbar(tk.Frame):
|
|||
logging.info("update button(%s): %s", button, name)
|
||||
self.hide_pickers()
|
||||
button.configure(image=image)
|
||||
button.image = image
|
||||
self.app.canvas.mode = GraphMode.NODE
|
||||
self.app.canvas.draw_node_image = image
|
||||
self.app.canvas.draw_node_name = name
|
||||
|
@ -262,29 +243,22 @@ class Toolbar(tk.Frame):
|
|||
|
||||
:return: nothing
|
||||
"""
|
||||
router_image = Images.get(ImageEnum.ROUTER)
|
||||
self.node_button = tk.Radiobutton(
|
||||
self.design_frame,
|
||||
indicatoron=False,
|
||||
variable=self.radio_value,
|
||||
value=3,
|
||||
width=self.width,
|
||||
height=self.height,
|
||||
image=router_image,
|
||||
image = icon(ImageEnum.ROUTER)
|
||||
self.node_button = ttk.Button(
|
||||
self.design_frame, image=image, command=self.draw_node_picker
|
||||
)
|
||||
self.node_button.bind("<ButtonRelease-1>", lambda e: self.draw_node_picker())
|
||||
self.node_button.grid()
|
||||
self.node_button.image = image
|
||||
self.node_button.grid(sticky="ew")
|
||||
Tooltip(self.node_button, "Network-layer virtual nodes")
|
||||
|
||||
def draw_network_picker(self):
|
||||
"""
|
||||
Draw the options for link-layer button
|
||||
Draw the options for link-layer button.
|
||||
|
||||
:param tkinter.RadioButton link_layer_button: link-layer button
|
||||
:return: nothing
|
||||
"""
|
||||
self.hide_pickers()
|
||||
self.network_picker = tk.Frame(self.master, padx=1, pady=1)
|
||||
self.network_picker = ttk.Frame(self.master)
|
||||
nodes = [
|
||||
(ImageEnum.HUB, "hub", "ethernet hub"),
|
||||
(ImageEnum.SWITCH, "switch", "ethernet switch"),
|
||||
|
@ -294,14 +268,17 @@ class Toolbar(tk.Frame):
|
|||
(ImageEnum.TUNNEL, "tunnel", "tunnel tool"),
|
||||
]
|
||||
for image_enum, name, tooltip in nodes:
|
||||
image = Images.get(image_enum)
|
||||
self.create_button(
|
||||
image = icon(image_enum)
|
||||
self.create_picker_button(
|
||||
image,
|
||||
partial(self.update_button, self.network_button, image, name),
|
||||
self.network_picker,
|
||||
tooltip,
|
||||
)
|
||||
self.show_picker(self.network_button, self.network_picker)
|
||||
self.design_select(self.network_button)
|
||||
self.network_button.after(
|
||||
0, lambda: self.show_picker(self.network_button, self.network_picker)
|
||||
)
|
||||
|
||||
def create_network_button(self):
|
||||
"""
|
||||
|
@ -309,31 +286,22 @@ class Toolbar(tk.Frame):
|
|||
|
||||
:return: nothing
|
||||
"""
|
||||
hub_image = Images.get(ImageEnum.HUB)
|
||||
self.network_button = tk.Radiobutton(
|
||||
self.design_frame,
|
||||
indicatoron=False,
|
||||
variable=self.radio_value,
|
||||
value=4,
|
||||
width=self.width,
|
||||
height=self.height,
|
||||
image=hub_image,
|
||||
image = icon(ImageEnum.HUB)
|
||||
self.network_button = ttk.Button(
|
||||
self.design_frame, image=image, command=self.draw_network_picker
|
||||
)
|
||||
self.network_button.bind(
|
||||
"<ButtonRelease-1>", lambda e: self.draw_network_picker()
|
||||
)
|
||||
self.network_button.grid()
|
||||
self.network_button.image = image
|
||||
self.network_button.grid(sticky="ew")
|
||||
Tooltip(self.network_button, "link-layer nodes")
|
||||
|
||||
def draw_annotation_picker(self):
|
||||
"""
|
||||
Draw the options for marker button
|
||||
Draw the options for marker button.
|
||||
|
||||
:param tkinter.Radiobutton main_button: the main button
|
||||
:return: nothing
|
||||
"""
|
||||
self.hide_pickers()
|
||||
self.annotation_picker = tk.Frame(self.master, padx=1, pady=1)
|
||||
self.annotation_picker = ttk.Frame(self.master)
|
||||
nodes = [
|
||||
(ImageEnum.MARKER, "marker"),
|
||||
(ImageEnum.OVAL, "oval"),
|
||||
|
@ -341,13 +309,17 @@ class Toolbar(tk.Frame):
|
|||
(ImageEnum.TEXT, "text"),
|
||||
]
|
||||
for image_enum, tooltip in nodes:
|
||||
self.create_button(
|
||||
Images.get(image_enum),
|
||||
partial(self.update_annotation, image_enum),
|
||||
image = icon(image_enum)
|
||||
self.create_picker_button(
|
||||
image,
|
||||
partial(self.update_annotation, image),
|
||||
self.annotation_picker,
|
||||
tooltip,
|
||||
)
|
||||
self.show_picker(self.annotation_button, self.annotation_picker)
|
||||
self.design_select(self.annotation_button)
|
||||
self.annotation_button.after(
|
||||
0, lambda: self.show_picker(self.annotation_button, self.annotation_picker)
|
||||
)
|
||||
|
||||
def create_annotation_button(self):
|
||||
"""
|
||||
|
@ -355,53 +327,39 @@ class Toolbar(tk.Frame):
|
|||
|
||||
:return: nothing
|
||||
"""
|
||||
marker_image = Images.get(ImageEnum.MARKER)
|
||||
self.annotation_button = tk.Radiobutton(
|
||||
self.design_frame,
|
||||
indicatoron=False,
|
||||
variable=self.radio_value,
|
||||
value=5,
|
||||
width=self.width,
|
||||
height=self.height,
|
||||
image=marker_image,
|
||||
image = icon(ImageEnum.MARKER)
|
||||
self.annotation_button = ttk.Button(
|
||||
self.design_frame, image=image, command=self.draw_annotation_picker
|
||||
)
|
||||
self.annotation_button.bind(
|
||||
"<ButtonRelease-1>", lambda e: self.draw_annotation_picker()
|
||||
)
|
||||
self.annotation_button.grid()
|
||||
self.annotation_button.image = image
|
||||
self.annotation_button.grid(sticky="ew")
|
||||
Tooltip(self.annotation_button, "background annotation tools")
|
||||
|
||||
def create_observe_button(self):
|
||||
menu_button = tk.Menubutton(
|
||||
self.runtime_frame,
|
||||
image=Images.get(ImageEnum.OBSERVE),
|
||||
width=self.width,
|
||||
height=self.height,
|
||||
direction=tk.RIGHT,
|
||||
relief=tk.RAISED,
|
||||
menu_button = ttk.Menubutton(
|
||||
self.runtime_frame, image=icon(ImageEnum.OBSERVE), direction=tk.RIGHT
|
||||
)
|
||||
menu_button.menu = tk.Menu(menu_button, tearoff=0)
|
||||
menu_button["menu"] = menu_button.menu
|
||||
menu_button.grid()
|
||||
menu_button.grid(sticky="ew")
|
||||
menu = tk.Menu(menu_button, tearoff=0)
|
||||
menu_button["menu"] = menu
|
||||
menu.add_command(label="None")
|
||||
menu.add_command(label="processes")
|
||||
menu.add_command(label="ifconfig")
|
||||
menu.add_command(label="IPv4 routes")
|
||||
menu.add_command(label="IPv6 routes")
|
||||
menu.add_command(label="OSPFv2 neighbors")
|
||||
menu.add_command(label="OSPFv3 neighbors")
|
||||
menu.add_command(label="Listening sockets")
|
||||
menu.add_command(label="IPv4 MFC entries")
|
||||
menu.add_command(label="IPv6 MFC entries")
|
||||
menu.add_command(label="firewall rules")
|
||||
menu.add_command(label="IPSec policies")
|
||||
menu.add_command(label="docker logs")
|
||||
menu.add_command(label="OSPFv3 MDR level")
|
||||
menu.add_command(label="PIM neighbors")
|
||||
menu.add_command(label="Edit...")
|
||||
|
||||
menu_button.menu.add_command(label="None")
|
||||
menu_button.menu.add_command(label="processes")
|
||||
menu_button.menu.add_command(label="ifconfig")
|
||||
menu_button.menu.add_command(label="IPv4 routes")
|
||||
menu_button.menu.add_command(label="IPv6 routes")
|
||||
menu_button.menu.add_command(label="OSPFv2 neighbors")
|
||||
menu_button.menu.add_command(label="OSPFv3 neighbors")
|
||||
menu_button.menu.add_command(label="Listening sockets")
|
||||
menu_button.menu.add_command(label="IPv4 MFC entries")
|
||||
menu_button.menu.add_command(label="IPv6 MFC entries")
|
||||
menu_button.menu.add_command(label="firewall rules")
|
||||
menu_button.menu.add_command(label="IPSec policies")
|
||||
menu_button.menu.add_command(label="docker logs")
|
||||
menu_button.menu.add_command(label="OSPFv3 MDR level")
|
||||
menu_button.menu.add_command(label="PIM neighbors")
|
||||
menu_button.menu.add_command(label="Edit...")
|
||||
|
||||
def click_stop_button(self):
|
||||
def click_stop(self):
|
||||
"""
|
||||
redraw buttons on the toolbar, send node and link messages to grpc server
|
||||
|
||||
|
@ -411,10 +369,11 @@ class Toolbar(tk.Frame):
|
|||
self.app.core.stop_session()
|
||||
self.design_frame.tkraise()
|
||||
|
||||
def update_annotation(self, image_enum):
|
||||
def update_annotation(self, image):
|
||||
logging.info("clicked annotation: ")
|
||||
self.hide_pickers()
|
||||
self.annotation_button.configure(image=Images.get(image_enum))
|
||||
self.annotation_button.configure(image=image)
|
||||
self.annotation_button.image = image
|
||||
|
||||
def click_run_button(self):
|
||||
logging.debug("Click on RUN button")
|
||||
|
|
Loading…
Add table
Reference in a new issue