tweaks to retrieving images/icons, updates to toolbar to use ttk widgets

This commit is contained in:
Blake Harnden 2019-11-12 17:32:34 -08:00
parent b96f8ff999
commit 14187ba79c
10 changed files with 221 additions and 234 deletions

View file

@ -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):

View file

@ -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"])
)

View file

@ -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):

View file

@ -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(

View file

@ -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)

View file

@ -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")

View file

@ -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
)

View file

@ -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",
)
)

View file

@ -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.error("invalid node model: %s", node_model)
else:
logging.debug("INVALID INPUT OR NOT CONSIDERED YET")
logging.error("invalid node type: %s", node_type)
return Images.get(image_enum, NODE_WIDTH), name
class ImageEnum(Enum):

View file

@ -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")