finish the basics of toolbar and start working on simple grpc
This commit is contained in:
parent
269d7f8f92
commit
cbd593eed6
5 changed files with 254 additions and 95 deletions
|
@ -1,6 +1,8 @@
|
|||
import logging
|
||||
import tkinter as tk
|
||||
|
||||
import coretk.images as images
|
||||
from coretk.coregrpc import CoreGrpc
|
||||
from coretk.coremenubar import CoreMenubar
|
||||
from coretk.coretoolbar import CoreToolbar
|
||||
from coretk.graph import CanvasGraph
|
||||
|
@ -13,11 +15,16 @@ class Application(tk.Frame):
|
|||
self.load_images()
|
||||
self.setup_app()
|
||||
self.menubar = None
|
||||
self.canvas = None
|
||||
self.core_grpc = CoreGrpc()
|
||||
self.create_menu()
|
||||
self.create_widgets()
|
||||
|
||||
def load_images(self):
|
||||
Images.load("core", "core-icon.png")
|
||||
images.load_core_images(Images)
|
||||
|
||||
def close_grpc(self):
|
||||
self.core_grpc.close()
|
||||
|
||||
def setup_app(self):
|
||||
self.master.title("CORE")
|
||||
|
@ -40,11 +47,14 @@ class Application(tk.Frame):
|
|||
core_editbar.create_toolbar()
|
||||
|
||||
self.canvas = CanvasGraph(
|
||||
master=self, background="#cccccc", scrollregion=(0, 0, 1000, 1000)
|
||||
grpc=self.core_grpc,
|
||||
master=self,
|
||||
background="#cccccc",
|
||||
scrollregion=(0, 0, 1000, 1000),
|
||||
)
|
||||
self.canvas.pack(fill=tk.BOTH, expand=True)
|
||||
|
||||
# self.canvas.create_rectangle(0, 0, 1000, 750, outline="#000000", fill="#ffffff", width=1)
|
||||
core_editbar.update_canvas(self.canvas)
|
||||
|
||||
scroll_x = tk.Scrollbar(
|
||||
self.canvas, orient=tk.HORIZONTAL, command=self.canvas.xview
|
||||
|
@ -69,3 +79,4 @@ if __name__ == "__main__":
|
|||
logging.basicConfig(level=logging.DEBUG)
|
||||
app = Application()
|
||||
app.mainloop()
|
||||
app.close_grpc()
|
||||
|
|
83
coretk/coretk/coregrpc.py
Normal file
83
coretk/coretk/coregrpc.py
Normal file
|
@ -0,0 +1,83 @@
|
|||
"""
|
||||
Incorporate grpc into python tkinter GUI
|
||||
"""
|
||||
import logging
|
||||
|
||||
from core.api.grpc import client, core_pb2
|
||||
|
||||
|
||||
class CoreGrpc:
|
||||
def __init__(self):
|
||||
"""
|
||||
Create a CoreGrpc instance
|
||||
"""
|
||||
self.core = client.CoreGrpcClient()
|
||||
self.session_id = None
|
||||
self.set_up()
|
||||
|
||||
def log_event(self, event):
|
||||
logging.info("event: %s", event)
|
||||
|
||||
def set_up(self):
|
||||
"""
|
||||
Create session, handle events session may broadcast, change session state
|
||||
|
||||
:return: nothing
|
||||
"""
|
||||
self.core.connect()
|
||||
# create session
|
||||
response = self.core.create_session()
|
||||
logging.info("created session: %s", response)
|
||||
|
||||
# handle events session may broadcast
|
||||
self.session_id = response.session_id
|
||||
self.core.events(self.session_id, self.log_event)
|
||||
|
||||
# change session state
|
||||
response = self.core.set_session_state(
|
||||
self.session_id, core_pb2.SessionState.CONFIGURATION
|
||||
)
|
||||
logging.info("set session state: %s", response)
|
||||
|
||||
def get_session_id(self):
|
||||
return self.session_id
|
||||
|
||||
# TODO add checkings to the function
|
||||
def add_node(self, x, y, node_name):
|
||||
link_layer_nodes = ["switch", "hub", "wlan", "rj45", "tunnel"]
|
||||
network_layer_nodes = ["default"]
|
||||
node = None
|
||||
if node_name in link_layer_nodes:
|
||||
if node_name == "switch":
|
||||
node = core_pb2.Node(type=core_pb2.NodeType.SWITCH)
|
||||
elif node_name == "hub":
|
||||
node = core_pb2.Node(type=core_pb2.NodeType.HUB)
|
||||
elif node_name == "wlan":
|
||||
node = core_pb2.Node(type=core_pb2.NodeType.WIRELESS_LAN)
|
||||
elif node_name == "rj45":
|
||||
node = core_pb2.Node(type=core_pb2.NodeType.RJ45)
|
||||
elif node_name == "tunnel":
|
||||
node = core_pb2.Node(type=core_pb2.NodeType.TUNNEL)
|
||||
|
||||
elif node_name in network_layer_nodes:
|
||||
position = core_pb2.Position(x=x, y=y)
|
||||
node = core_pb2.Node(position=position)
|
||||
else:
|
||||
return
|
||||
response = self.core.add_node(self.session_id, node)
|
||||
logging.info("created %s: %s", node_name, response)
|
||||
return response.node_id
|
||||
|
||||
def edit_node(self, session_id, node_id, x, y):
|
||||
position = core_pb2.Position(x=x, y=y)
|
||||
response = self.core.edit_node(session_id, node_id, position)
|
||||
logging.info("updated node id %s: %s", node_id, response)
|
||||
|
||||
def close(self):
|
||||
"""
|
||||
Clean ups when done using grpc
|
||||
|
||||
:return: nothing
|
||||
"""
|
||||
logging.debug("Close grpc")
|
||||
self.core.close()
|
|
@ -36,57 +36,17 @@ class CoreToolbar(object):
|
|||
self.network_layer_option_menu = None
|
||||
|
||||
# variables used by canvas graph
|
||||
self.mode = GraphMode.SELECT
|
||||
self.image_to_draw = None
|
||||
self.canvas = None
|
||||
|
||||
def load_toolbar_images(self):
|
||||
def update_canvas(self, canvas):
|
||||
"""
|
||||
Load the images that appear in core toolbar
|
||||
Update canvas variable in CoreToolbar class
|
||||
|
||||
:param tkinter.Canvas canvas: core canvas
|
||||
:return: nothing
|
||||
"""
|
||||
Images.load("core", "core-icon.png")
|
||||
Images.load("start", "start.gif")
|
||||
Images.load("switch", "lanswitch.gif")
|
||||
Images.load("marker", "marker.gif")
|
||||
Images.load("router", "router.gif")
|
||||
Images.load("select", "select.gif")
|
||||
Images.load("link", "link.gif")
|
||||
Images.load("hub", "hub.gif")
|
||||
Images.load("wlan", "wlan.gif")
|
||||
Images.load("rj45", "rj45.gif")
|
||||
Images.load("tunnel", "tunnel.gif")
|
||||
Images.load("oval", "oval.gif")
|
||||
Images.load("rectangle", "rectangle.gif")
|
||||
Images.load("text", "text.gif")
|
||||
Images.load("host", "host.gif")
|
||||
Images.load("pc", "pc.gif")
|
||||
Images.load("mdr", "mdr.gif")
|
||||
Images.load("prouter", "router_green.gif")
|
||||
Images.load("ovs", "OVS.gif")
|
||||
Images.load("editnode", "document-properties.gif")
|
||||
Images.load("run", "run.gif")
|
||||
Images.load("plot", "plot.gif")
|
||||
Images.load("twonode", "twonode.gif")
|
||||
Images.load("stop", "stop.gif")
|
||||
Images.load("observe", "observe.gif")
|
||||
|
||||
def get_graph_mode(self):
|
||||
"""
|
||||
Retrieve current graph mode
|
||||
|
||||
:rtype: int
|
||||
:return: current graph mode
|
||||
"""
|
||||
return self.mode
|
||||
|
||||
def set_graph_mode(self, mode):
|
||||
"""
|
||||
Set graph mode
|
||||
|
||||
:param int mode: graph mode
|
||||
:return: nothing
|
||||
"""
|
||||
self.mode = mode
|
||||
self.canvas = canvas
|
||||
|
||||
def destroy_previous_frame(self):
|
||||
"""
|
||||
|
@ -189,47 +149,67 @@ class CoreToolbar(object):
|
|||
|
||||
def click_selection_tool(self):
|
||||
logging.debug("Click SELECTION TOOL")
|
||||
self.set_graph_mode(GraphMode.SELECT)
|
||||
self.canvas.mode = GraphMode.SELECT
|
||||
|
||||
def click_start_stop_session_tool(self):
|
||||
logging.debug("Click START STOP SESSION button")
|
||||
self.destroy_children_widgets(self.edit_frame)
|
||||
self.canvas.set_canvas_mode(GraphMode.SELECT)
|
||||
self.create_runtime_toolbar()
|
||||
|
||||
def click_link_tool(self):
|
||||
logging.debug("Click LINK button")
|
||||
self.set_graph_mode(GraphMode.EDGE)
|
||||
self.canvas.set_canvas_mode(GraphMode.EDGE)
|
||||
|
||||
def pick_router(self, main_button):
|
||||
logging.debug("Pick router option")
|
||||
self.network_layer_option_menu.destroy()
|
||||
main_button.configure(image=Images.get("router"))
|
||||
logging.debug("Pick router option")
|
||||
self.canvas.set_canvas_mode(GraphMode.PICKNODE)
|
||||
self.canvas.set_drawing_image(Images.get("router"))
|
||||
self.canvas.set_drawing_name("default")
|
||||
|
||||
def pick_host(self, main_button):
|
||||
logging.debug("Pick host option")
|
||||
self.network_layer_option_menu.destroy()
|
||||
main_button.configure(image=Images.get("host"))
|
||||
logging.debug("Pick host option")
|
||||
self.canvas.set_canvas_mode(GraphMode.PICKNODE)
|
||||
self.canvas.set_drawing_image(Images.get("host"))
|
||||
self.canvas.set_drawing_name("default")
|
||||
|
||||
def pick_pc(self, main_button):
|
||||
logging.debug("Pick PC option")
|
||||
self.network_layer_option_menu.destroy()
|
||||
main_button.configure(image=Images.get("pc"))
|
||||
logging.debug("Pick PC option")
|
||||
self.canvas.set_canvas_mode(GraphMode.PICKNODE)
|
||||
self.canvas.set_drawing_image(Images.get("pc"))
|
||||
self.canvas.set_drawing_name("default")
|
||||
|
||||
def pick_mdr(self, main_button):
|
||||
logging.debug("Pick MDR option")
|
||||
self.network_layer_option_menu.destroy()
|
||||
main_button.configure(image=Images.get("mdr"))
|
||||
logging.debug("Pick MDR option")
|
||||
self.canvas.set_canvas_mode(GraphMode.PICKNODE)
|
||||
self.canvas.set_drawing_image(Images.get("mdr"))
|
||||
self.canvas.set_drawing_name("default")
|
||||
|
||||
def pick_prouter(self, main_button):
|
||||
logging.debug("Pick prouter option")
|
||||
self.network_layer_option_menu.destroy()
|
||||
main_button.configure(image=Images.get("prouter"))
|
||||
logging.debug("Pick prouter option")
|
||||
self.canvas.set_canvas_mode(GraphMode.PICKNODE)
|
||||
self.canvas.set_drawing_image(Images.get("prouter"))
|
||||
self.canvas.set_drawing_name("default")
|
||||
|
||||
def pick_ovs(self, main_button):
|
||||
logging.debug("Pick OVS option")
|
||||
self.network_layer_option_menu.destroy()
|
||||
main_button.configure(image=Images.get("ovs"))
|
||||
logging.debug("Pick OVS option")
|
||||
self.canvas.set_canvas_mode(GraphMode.PICKNODE)
|
||||
self.canvas.set_drawing_image(Images.get("ovs"))
|
||||
self.canvas.set_drawing_name("default")
|
||||
|
||||
# TODO what graph node is this
|
||||
def pick_editnode(self, main_button):
|
||||
self.network_layer_option_menu.destroy()
|
||||
main_button.configure(image=Images.get("editnode"))
|
||||
|
@ -311,29 +291,43 @@ class CoreToolbar(object):
|
|||
CreateToolTip(network_layer_button, "Network-layer virtual nodes")
|
||||
|
||||
def pick_hub(self, main_button):
|
||||
logging.debug("Pick link-layer node HUB")
|
||||
self.link_layer_option_menu.destroy()
|
||||
main_button.configure(image=Images.get("hub"))
|
||||
logging.debug("Pick link-layer node HUB")
|
||||
self.canvas.set_canvas_mode(GraphMode.PICKNODE)
|
||||
self.canvas.set_drawing_image(Images.get("hub"))
|
||||
self.canvas.set_drawing_name("hub")
|
||||
|
||||
def pick_switch(self, main_button):
|
||||
logging.debug("Pick link-layer node SWITCH")
|
||||
self.link_layer_option_menu.destroy()
|
||||
main_button.configure(image=Images.get("switch"))
|
||||
logging.debug("Pick link-layer node SWITCH")
|
||||
self.canvas.set_canvas_mode(GraphMode.PICKNODE)
|
||||
self.canvas.set_drawing_image(Images.get("switch"))
|
||||
self.canvas.set_drawing_name("switch")
|
||||
|
||||
def pick_wlan(self, main_button):
|
||||
logging.debug("Pick link-layer node WLAN")
|
||||
self.link_layer_option_menu.destroy()
|
||||
main_button.configure(image=Images.get("wlan"))
|
||||
logging.debug("Pick link-layer node WLAN")
|
||||
self.canvas.set_canvas_mode(GraphMode.PICKNODE)
|
||||
self.canvas.set_drawing_image(Images.get("wlan"))
|
||||
self.canvas.set_drawing_name("wlan")
|
||||
|
||||
def pick_rj45(self, main_button):
|
||||
logging.debug("Pick link-layer node RJ45")
|
||||
self.link_layer_option_menu.destroy()
|
||||
main_button.configure(image=Images.get("rj45"))
|
||||
logging.debug("Pick link-layer node RJ45")
|
||||
self.canvas.set_canvas_mode(GraphMode.PICKNODE)
|
||||
self.canvas.set_drawing_image(Images.get("rj45"))
|
||||
|
||||
def pick_tunnel(self, main_button):
|
||||
logging.debug("Pick link-layer node TUNNEL")
|
||||
self.link_layer_option_menu.destroy()
|
||||
main_button.configure(image=Images.get("tunnel"))
|
||||
logging.debug("Pick link-layer node TUNNEL")
|
||||
self.canvas.set_canvas_mode(GraphMode.PICKNODE)
|
||||
self.canvas.set_drawing_image(Images.get("tunnel"))
|
||||
self.canvas.set_drawing_image(Images.get("tunnel"))
|
||||
|
||||
def draw_link_layer_options(self, link_layer_button):
|
||||
"""
|
||||
|
@ -482,7 +476,7 @@ class CoreToolbar(object):
|
|||
CreateToolTip(marker_main_button, "background annotation tools")
|
||||
|
||||
def create_toolbar(self):
|
||||
self.load_toolbar_images()
|
||||
# self.load_toolbar_images()
|
||||
self.create_regular_button(
|
||||
self.edit_frame,
|
||||
Images.get("start"),
|
||||
|
@ -508,6 +502,7 @@ class CoreToolbar(object):
|
|||
self.create_network_layer_button()
|
||||
self.create_link_layer_button()
|
||||
self.create_marker_button()
|
||||
self.radio_value.set(1)
|
||||
|
||||
def create_observe_button(self):
|
||||
menu_button = tk.Menubutton(
|
||||
|
@ -599,3 +594,4 @@ class CoreToolbar(object):
|
|||
self.create_regular_button(
|
||||
self.edit_frame, Images.get("run"), self.click_run_button, "run"
|
||||
)
|
||||
self.exec_radio_value.set(1)
|
||||
|
|
|
@ -2,23 +2,25 @@ import enum
|
|||
import logging
|
||||
import tkinter as tk
|
||||
|
||||
from coretk.images import Images
|
||||
|
||||
|
||||
class GraphMode(enum.Enum):
|
||||
SELECT = 0
|
||||
EDGE = 1
|
||||
NODE = 2
|
||||
PICKNODE = 2
|
||||
NODE = 3
|
||||
OTHER = 4
|
||||
|
||||
|
||||
class CanvasGraph(tk.Canvas):
|
||||
def __init__(self, master=None, cnf=None, **kwargs):
|
||||
def __init__(self, grpc=None, master=None, cnf=None, **kwargs):
|
||||
if cnf is None:
|
||||
cnf = {}
|
||||
kwargs["highlightthickness"] = 0
|
||||
super().__init__(master, cnf, **kwargs)
|
||||
|
||||
self.core_grpc = grpc
|
||||
self.mode = GraphMode.SELECT
|
||||
self.draw_node_image = None
|
||||
self.draw_node_name = None
|
||||
self.selected = None
|
||||
self.node_context = None
|
||||
self.nodes = {}
|
||||
|
@ -29,6 +31,15 @@ class CanvasGraph(tk.Canvas):
|
|||
self.setup_bindings()
|
||||
self.draw_grid()
|
||||
|
||||
def set_canvas_mode(self, mode):
|
||||
self.mode = mode
|
||||
|
||||
def set_drawing_image(self, img):
|
||||
self.draw_node_image = img
|
||||
|
||||
def set_drawing_name(self, name):
|
||||
self.draw_node_name = name
|
||||
|
||||
def draw_grid(self, width=1000, height=750):
|
||||
"""
|
||||
Create grid
|
||||
|
@ -70,9 +81,9 @@ class CanvasGraph(tk.Canvas):
|
|||
self.bind("<ButtonRelease-1>", self.click_release)
|
||||
self.bind("<B1-Motion>", self.click_motion)
|
||||
self.bind("<Button-3>", self.context)
|
||||
self.bind("e", self.set_mode)
|
||||
self.bind("s", self.set_mode)
|
||||
self.bind("n", self.set_mode)
|
||||
# self.bind("e", self.set_mode)
|
||||
# self.bind("s", self.set_mode)
|
||||
# self.bind("n", self.set_mode)
|
||||
|
||||
def canvas_xy(self, event):
|
||||
"""
|
||||
|
@ -124,7 +135,9 @@ class CanvasGraph(tk.Canvas):
|
|||
self.handle_edge_release(event)
|
||||
elif self.mode == GraphMode.NODE:
|
||||
x, y = self.canvas_xy(event)
|
||||
self.add_node(x, y, "switch")
|
||||
self.add_node(x, y, self.draw_node_image, self.draw_node_name)
|
||||
elif self.mode == GraphMode.PICKNODE:
|
||||
self.mode = GraphMode.NODE
|
||||
|
||||
def handle_edge_release(self, event):
|
||||
edge = self.drawing_edge
|
||||
|
@ -194,25 +207,39 @@ class CanvasGraph(tk.Canvas):
|
|||
logging.debug(f"node context: {selected}")
|
||||
self.node_context.post(event.x_root, event.y_root)
|
||||
|
||||
def set_mode(self, event):
|
||||
"""
|
||||
Set canvas mode according to the hot key that has been pressed
|
||||
# def set_mode(self, event):
|
||||
# """
|
||||
# Set canvas mode according to the hot key that has been pressed
|
||||
#
|
||||
# :param event: key event
|
||||
# :return: nothing
|
||||
# """
|
||||
# logging.debug(f"mode event: {event}")
|
||||
# if event.char == "e":
|
||||
# self.mode = GraphMode.EDGE
|
||||
# elif event.char == "s":
|
||||
# self.mode = GraphMode.SELECT
|
||||
# elif event.char == "n":
|
||||
# self.mode = GraphMode.NODE
|
||||
# logging.debug(f"graph mode: {self.mode}")
|
||||
|
||||
:param event: key event
|
||||
:return: nothing
|
||||
"""
|
||||
logging.debug(f"mode event: {event}")
|
||||
if event.char == "e":
|
||||
self.mode = GraphMode.EDGE
|
||||
elif event.char == "s":
|
||||
self.mode = GraphMode.SELECT
|
||||
elif event.char == "n":
|
||||
self.mode = GraphMode.NODE
|
||||
logging.debug(f"graph mode: {self.mode}")
|
||||
# def add_node(self, x, y, image_name):
|
||||
# image = Images.get(image_name)
|
||||
# node = CanvasNode(x, y, image, self)
|
||||
# self.nodes[node.id] = node
|
||||
# return node
|
||||
|
||||
def add_node(self, x, y, image_name):
|
||||
image = Images.get(image_name)
|
||||
node = CanvasNode(x, y, image, self)
|
||||
def add_node(self, x, y, image, node_name):
|
||||
core_session_id = self.core_grpc.get_session_id()
|
||||
core_node_id = self.core_grpc.add_node(int(x), int(y), node_name)
|
||||
node = CanvasNode(
|
||||
core_session_id=core_session_id,
|
||||
core_node_id=core_node_id,
|
||||
x=x,
|
||||
y=y,
|
||||
image=image,
|
||||
canvas=self,
|
||||
)
|
||||
self.nodes[node.id] = node
|
||||
return node
|
||||
|
||||
|
@ -250,22 +277,23 @@ class CanvasEdge:
|
|||
self.canvas.coords(self.id, x1, y1, x, y)
|
||||
self.canvas.lift(self.src)
|
||||
self.canvas.lift(self.dst)
|
||||
# self.canvas.create_line(0,0,10,10)
|
||||
# print(x1,y1,x,y)
|
||||
# self.canvas.create_line(x1+1, y1+1, x+1, y+1)
|
||||
|
||||
def delete(self):
|
||||
self.canvas.delete(self.id)
|
||||
|
||||
|
||||
class CanvasNode:
|
||||
def __init__(self, x, y, image, canvas):
|
||||
def __init__(self, core_session_id, core_node_id, x, y, image, canvas):
|
||||
self.image = image
|
||||
self.canvas = canvas
|
||||
self.id = self.canvas.create_image(
|
||||
x, y, anchor=tk.CENTER, image=self.image, tags="node"
|
||||
)
|
||||
self.name = f"Node {self.id}"
|
||||
self.x_coord = x
|
||||
self.y_coord = y
|
||||
self.core_session_id = core_session_id
|
||||
self.core_node_id = core_node_id
|
||||
self.name = f"Node {self.core_node_id}"
|
||||
self.text_id = self.canvas.create_text(x, y + 20, text=self.name)
|
||||
self.canvas.tag_bind(self.id, "<ButtonPress-1>", self.click_press)
|
||||
self.canvas.tag_bind(self.id, "<ButtonRelease-1>", self.click_release)
|
||||
|
@ -274,16 +302,29 @@ class CanvasNode:
|
|||
self.edges = set()
|
||||
self.moving = None
|
||||
|
||||
def get_coords(self):
|
||||
return self.x_coord, self.y_coord
|
||||
|
||||
def update_coords(self):
|
||||
self.x_coord, self.y_coord = self.canvas.coords(self.id)
|
||||
|
||||
def click_press(self, event):
|
||||
logging.debug(f"click press {self.name}: {event}")
|
||||
self.moving = self.canvas.canvas_xy(event)
|
||||
|
||||
def click_release(self, event):
|
||||
logging.debug(f"click release {self.name}: {event}")
|
||||
self.update_coords()
|
||||
self.canvas.core_grpc.edit_node(
|
||||
self.core_session_id,
|
||||
self.core_node_id,
|
||||
int(self.x_coord),
|
||||
int(self.y_coord),
|
||||
)
|
||||
self.moving = None
|
||||
|
||||
def motion(self, event):
|
||||
if self.canvas.mode == GraphMode.EDGE:
|
||||
if self.canvas.mode == GraphMode.EDGE or self.canvas.mode == GraphMode.NODE:
|
||||
return
|
||||
x, y = self.canvas.canvas_xy(event)
|
||||
moving_x, moving_y = self.moving
|
||||
|
|
|
@ -18,3 +18,31 @@ class Images:
|
|||
@classmethod
|
||||
def get(cls, name):
|
||||
return cls.images[name]
|
||||
|
||||
|
||||
def load_core_images(images):
|
||||
images.load("core", "core-icon.png")
|
||||
images.load("start", "start.gif")
|
||||
images.load("switch", "lanswitch.gif")
|
||||
images.load("marker", "marker.gif")
|
||||
images.load("router", "router.gif")
|
||||
images.load("select", "select.gif")
|
||||
images.load("link", "link.gif")
|
||||
images.load("hub", "hub.gif")
|
||||
images.load("wlan", "wlan.gif")
|
||||
images.load("rj45", "rj45.gif")
|
||||
images.load("tunnel", "tunnel.gif")
|
||||
images.load("oval", "oval.gif")
|
||||
images.load("rectangle", "rectangle.gif")
|
||||
images.load("text", "text.gif")
|
||||
images.load("host", "host.gif")
|
||||
images.load("pc", "pc.gif")
|
||||
images.load("mdr", "mdr.gif")
|
||||
images.load("prouter", "router_green.gif")
|
||||
images.load("ovs", "OVS.gif")
|
||||
images.load("editnode", "document-properties.gif")
|
||||
images.load("run", "run.gif")
|
||||
images.load("plot", "plot.gif")
|
||||
images.load("twonode", "twonode.gif")
|
||||
images.load("stop", "stop.gif")
|
||||
images.load("observe", "observe.gif")
|
||||
|
|
Loading…
Add table
Reference in a new issue