create grids
This commit is contained in:
parent
130c2a9b8d
commit
269d7f8f92
3 changed files with 162 additions and 13 deletions
|
@ -21,7 +21,7 @@ class Application(tk.Frame):
|
||||||
|
|
||||||
def setup_app(self):
|
def setup_app(self):
|
||||||
self.master.title("CORE")
|
self.master.title("CORE")
|
||||||
self.master.geometry("800x600")
|
self.master.geometry("1000x800")
|
||||||
image = Images.get("core")
|
image = Images.get("core")
|
||||||
self.master.tk.call("wm", "iconphoto", self.master._w, image)
|
self.master.tk.call("wm", "iconphoto", self.master._w, image)
|
||||||
self.pack(fill=tk.BOTH, expand=True)
|
self.pack(fill=tk.BOTH, expand=True)
|
||||||
|
@ -40,11 +40,11 @@ class Application(tk.Frame):
|
||||||
core_editbar.create_toolbar()
|
core_editbar.create_toolbar()
|
||||||
|
|
||||||
self.canvas = CanvasGraph(
|
self.canvas = CanvasGraph(
|
||||||
self, background="#cccccc", scrollregion=(0, 0, 1000, 1000)
|
master=self, background="#cccccc", scrollregion=(0, 0, 1000, 1000)
|
||||||
)
|
)
|
||||||
self.canvas.pack(fill=tk.BOTH, expand=True)
|
self.canvas.pack(fill=tk.BOTH, expand=True)
|
||||||
|
|
||||||
# self.canvas.create_line(0, 0, 10, 10)
|
# self.canvas.create_rectangle(0, 0, 1000, 750, outline="#000000", fill="#ffffff", width=1)
|
||||||
|
|
||||||
scroll_x = tk.Scrollbar(
|
scroll_x = tk.Scrollbar(
|
||||||
self.canvas, orient=tk.HORIZONTAL, command=self.canvas.xview
|
self.canvas, orient=tk.HORIZONTAL, command=self.canvas.xview
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
import logging
|
import logging
|
||||||
import tkinter as tk
|
import tkinter as tk
|
||||||
|
|
||||||
|
from coretk.graph import GraphMode
|
||||||
from coretk.images import Images
|
from coretk.images import Images
|
||||||
from coretk.tooltip import CreateToolTip
|
from coretk.tooltip import CreateToolTip
|
||||||
|
|
||||||
|
@ -34,6 +35,9 @@ class CoreToolbar(object):
|
||||||
self.marker_option_menu = None
|
self.marker_option_menu = None
|
||||||
self.network_layer_option_menu = None
|
self.network_layer_option_menu = None
|
||||||
|
|
||||||
|
# variables used by canvas graph
|
||||||
|
self.mode = GraphMode.SELECT
|
||||||
|
|
||||||
def load_toolbar_images(self):
|
def load_toolbar_images(self):
|
||||||
"""
|
"""
|
||||||
Load the images that appear in core toolbar
|
Load the images that appear in core toolbar
|
||||||
|
@ -66,6 +70,24 @@ class CoreToolbar(object):
|
||||||
Images.load("stop", "stop.gif")
|
Images.load("stop", "stop.gif")
|
||||||
Images.load("observe", "observe.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
|
||||||
|
|
||||||
def destroy_previous_frame(self):
|
def destroy_previous_frame(self):
|
||||||
"""
|
"""
|
||||||
Destroy any extra frame from previous before drawing a new one
|
Destroy any extra frame from previous before drawing a new one
|
||||||
|
@ -94,7 +116,7 @@ class CoreToolbar(object):
|
||||||
if i.winfo_name() != "!frame":
|
if i.winfo_name() != "!frame":
|
||||||
i.destroy()
|
i.destroy()
|
||||||
|
|
||||||
def create_button(self, img, func, frame, main_button):
|
def create_button(self, img, func, frame, main_button, btt_message):
|
||||||
"""
|
"""
|
||||||
Create button and put it on the frame
|
Create button and put it on the frame
|
||||||
|
|
||||||
|
@ -106,6 +128,7 @@ class CoreToolbar(object):
|
||||||
"""
|
"""
|
||||||
button = tk.Button(frame, width=self.width, height=self.height, image=img)
|
button = tk.Button(frame, width=self.width, height=self.height, image=img)
|
||||||
button.pack(side=tk.LEFT, pady=1)
|
button.pack(side=tk.LEFT, pady=1)
|
||||||
|
CreateToolTip(button, btt_message)
|
||||||
button.bind("<Button-1>", lambda mb: func(main_button))
|
button.bind("<Button-1>", lambda mb: func(main_button))
|
||||||
|
|
||||||
def create_radio_button(self, frame, image, func, variable, value, tooltip_msg):
|
def create_radio_button(self, frame, image, func, variable, value, tooltip_msg):
|
||||||
|
@ -122,11 +145,12 @@ class CoreToolbar(object):
|
||||||
button.pack(side=tk.TOP, pady=1)
|
button.pack(side=tk.TOP, pady=1)
|
||||||
CreateToolTip(button, tooltip_msg)
|
CreateToolTip(button, tooltip_msg)
|
||||||
|
|
||||||
def create_regular_button(self, frame, image, func):
|
def create_regular_button(self, frame, image, func, btt_message):
|
||||||
button = tk.Button(
|
button = tk.Button(
|
||||||
frame, width=self.width, height=self.height, image=image, command=func
|
frame, width=self.width, height=self.height, image=image, command=func
|
||||||
)
|
)
|
||||||
button.pack(side=tk.TOP, pady=1)
|
button.pack(side=tk.TOP, pady=1)
|
||||||
|
CreateToolTip(button, btt_message)
|
||||||
|
|
||||||
def draw_button_menu_frame(self, edit_frame, option_frame, main_button):
|
def draw_button_menu_frame(self, edit_frame, option_frame, main_button):
|
||||||
"""
|
"""
|
||||||
|
@ -165,6 +189,7 @@ class CoreToolbar(object):
|
||||||
|
|
||||||
def click_selection_tool(self):
|
def click_selection_tool(self):
|
||||||
logging.debug("Click SELECTION TOOL")
|
logging.debug("Click SELECTION TOOL")
|
||||||
|
self.set_graph_mode(GraphMode.SELECT)
|
||||||
|
|
||||||
def click_start_stop_session_tool(self):
|
def click_start_stop_session_tool(self):
|
||||||
logging.debug("Click START STOP SESSION button")
|
logging.debug("Click START STOP SESSION button")
|
||||||
|
@ -173,6 +198,7 @@ class CoreToolbar(object):
|
||||||
|
|
||||||
def click_link_tool(self):
|
def click_link_tool(self):
|
||||||
logging.debug("Click LINK button")
|
logging.debug("Click LINK button")
|
||||||
|
self.set_graph_mode(GraphMode.EDGE)
|
||||||
|
|
||||||
def pick_router(self, main_button):
|
def pick_router(self, main_button):
|
||||||
self.network_layer_option_menu.destroy()
|
self.network_layer_option_menu.destroy()
|
||||||
|
@ -237,9 +263,22 @@ class CoreToolbar(object):
|
||||||
self.pick_ovs,
|
self.pick_ovs,
|
||||||
self.pick_editnode,
|
self.pick_editnode,
|
||||||
]
|
]
|
||||||
|
tooltip_list = [
|
||||||
|
"router",
|
||||||
|
"host",
|
||||||
|
"PC",
|
||||||
|
"mdr",
|
||||||
|
"prouter",
|
||||||
|
"OVS",
|
||||||
|
"edit node types",
|
||||||
|
]
|
||||||
for i in range(len(img_list)):
|
for i in range(len(img_list)):
|
||||||
self.create_button(
|
self.create_button(
|
||||||
img_list[i], func_list[i], option_frame, network_layer_button
|
img_list[i],
|
||||||
|
func_list[i],
|
||||||
|
option_frame,
|
||||||
|
network_layer_button,
|
||||||
|
tooltip_list[i],
|
||||||
)
|
)
|
||||||
|
|
||||||
# place frame at a calculated position as well as keep a reference of that frame
|
# place frame at a calculated position as well as keep a reference of that frame
|
||||||
|
@ -320,9 +359,20 @@ class CoreToolbar(object):
|
||||||
self.pick_rj45,
|
self.pick_rj45,
|
||||||
self.pick_tunnel,
|
self.pick_tunnel,
|
||||||
]
|
]
|
||||||
|
tooltip_list = [
|
||||||
|
"ethernet hub",
|
||||||
|
"ethernet switch",
|
||||||
|
"wireless LAN",
|
||||||
|
"rj45 physical interface tool",
|
||||||
|
"tunnel tool",
|
||||||
|
]
|
||||||
for i in range(len(img_list)):
|
for i in range(len(img_list)):
|
||||||
self.create_button(
|
self.create_button(
|
||||||
img_list[i], func_list[i], option_frame, link_layer_button
|
img_list[i],
|
||||||
|
func_list[i],
|
||||||
|
option_frame,
|
||||||
|
link_layer_button,
|
||||||
|
tooltip_list[i],
|
||||||
)
|
)
|
||||||
|
|
||||||
# place frame at a calculated position as well as keep a reference of the frame
|
# place frame at a calculated position as well as keep a reference of the frame
|
||||||
|
@ -358,7 +408,6 @@ class CoreToolbar(object):
|
||||||
self.marker_option_menu.destroy()
|
self.marker_option_menu.destroy()
|
||||||
main_button.configure(image=Images.get("marker"))
|
main_button.configure(image=Images.get("marker"))
|
||||||
logging.debug("Pick MARKER")
|
logging.debug("Pick MARKER")
|
||||||
return "break"
|
|
||||||
|
|
||||||
def pick_oval(self, main_button):
|
def pick_oval(self, main_button):
|
||||||
self.marker_option_menu.destroy()
|
self.marker_option_menu.destroy()
|
||||||
|
@ -397,8 +446,11 @@ class CoreToolbar(object):
|
||||||
self.pick_rectangle,
|
self.pick_rectangle,
|
||||||
self.pick_text,
|
self.pick_text,
|
||||||
]
|
]
|
||||||
|
tooltip_list = ["marker", "oval", "rectangle", "text"]
|
||||||
for i in range(len(img_list)):
|
for i in range(len(img_list)):
|
||||||
self.create_button(img_list[i], func_list[i], option_frame, main_button)
|
self.create_button(
|
||||||
|
img_list[i], func_list[i], option_frame, main_button, tooltip_list[i]
|
||||||
|
)
|
||||||
|
|
||||||
# place the frame at a calculated position as well as keep a reference of that frame
|
# place the frame at a calculated position as well as keep a reference of that frame
|
||||||
self.draw_button_menu_frame(self.edit_frame, option_frame, main_button)
|
self.draw_button_menu_frame(self.edit_frame, option_frame, main_button)
|
||||||
|
@ -432,7 +484,10 @@ class CoreToolbar(object):
|
||||||
def create_toolbar(self):
|
def create_toolbar(self):
|
||||||
self.load_toolbar_images()
|
self.load_toolbar_images()
|
||||||
self.create_regular_button(
|
self.create_regular_button(
|
||||||
self.edit_frame, Images.get("start"), self.click_start_stop_session_tool
|
self.edit_frame,
|
||||||
|
Images.get("start"),
|
||||||
|
self.click_start_stop_session_tool,
|
||||||
|
"start the session",
|
||||||
)
|
)
|
||||||
self.create_radio_button(
|
self.create_radio_button(
|
||||||
self.edit_frame,
|
self.edit_frame,
|
||||||
|
@ -503,7 +558,10 @@ class CoreToolbar(object):
|
||||||
|
|
||||||
def create_runtime_toolbar(self):
|
def create_runtime_toolbar(self):
|
||||||
self.create_regular_button(
|
self.create_regular_button(
|
||||||
self.edit_frame, Images.get("stop"), self.click_stop_button
|
self.edit_frame,
|
||||||
|
Images.get("stop"),
|
||||||
|
self.click_stop_button,
|
||||||
|
"stop the session",
|
||||||
)
|
)
|
||||||
self.create_radio_button(
|
self.create_radio_button(
|
||||||
self.edit_frame,
|
self.edit_frame,
|
||||||
|
@ -539,5 +597,5 @@ class CoreToolbar(object):
|
||||||
"run command from one node to another",
|
"run command from one node to another",
|
||||||
)
|
)
|
||||||
self.create_regular_button(
|
self.create_regular_button(
|
||||||
self.edit_frame, Images.get("run"), self.click_run_button
|
self.edit_frame, Images.get("run"), self.click_run_button, "run"
|
||||||
)
|
)
|
||||||
|
|
|
@ -17,14 +17,42 @@ class CanvasGraph(tk.Canvas):
|
||||||
cnf = {}
|
cnf = {}
|
||||||
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.selected = None
|
self.selected = None
|
||||||
self.node_context = None
|
self.node_context = None
|
||||||
self.nodes = {}
|
self.nodes = {}
|
||||||
self.edges = {}
|
self.edges = {}
|
||||||
self.drawing_edge = None
|
self.drawing_edge = None
|
||||||
|
|
||||||
self.setup_menus()
|
self.setup_menus()
|
||||||
self.setup_bindings()
|
self.setup_bindings()
|
||||||
|
self.draw_grid()
|
||||||
|
|
||||||
|
def draw_grid(self, width=1000, height=750):
|
||||||
|
"""
|
||||||
|
Create grid
|
||||||
|
|
||||||
|
:param int width: the width
|
||||||
|
:param int height: the height
|
||||||
|
|
||||||
|
:return: nothing
|
||||||
|
"""
|
||||||
|
rectangle_id = self.create_rectangle(
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
width,
|
||||||
|
height,
|
||||||
|
outline="#000000",
|
||||||
|
fill="#ffffff",
|
||||||
|
width=1,
|
||||||
|
tags="rectangle",
|
||||||
|
)
|
||||||
|
self.tag_lower(rectangle_id)
|
||||||
|
for i in range(0, width, 27):
|
||||||
|
self.create_line(i, 0, i, height, dash=(2, 4), tags="grid line")
|
||||||
|
for i in range(0, height, 27):
|
||||||
|
self.create_line(0, i, width, i, dash=(2, 4), tags="grid line")
|
||||||
|
|
||||||
def setup_menus(self):
|
def setup_menus(self):
|
||||||
self.node_context = tk.Menu(self.master)
|
self.node_context = tk.Menu(self.master)
|
||||||
|
@ -33,6 +61,11 @@ class CanvasGraph(tk.Canvas):
|
||||||
self.node_context.add_command(label="Three")
|
self.node_context.add_command(label="Three")
|
||||||
|
|
||||||
def setup_bindings(self):
|
def setup_bindings(self):
|
||||||
|
"""
|
||||||
|
Bind any mouse events or hot keys to the matching action
|
||||||
|
|
||||||
|
:return: nothing
|
||||||
|
"""
|
||||||
self.bind("<ButtonPress-1>", self.click_press)
|
self.bind("<ButtonPress-1>", self.click_press)
|
||||||
self.bind("<ButtonRelease-1>", self.click_release)
|
self.bind("<ButtonRelease-1>", self.click_release)
|
||||||
self.bind("<B1-Motion>", self.click_motion)
|
self.bind("<B1-Motion>", self.click_motion)
|
||||||
|
@ -42,11 +75,25 @@ class CanvasGraph(tk.Canvas):
|
||||||
self.bind("n", self.set_mode)
|
self.bind("n", self.set_mode)
|
||||||
|
|
||||||
def canvas_xy(self, event):
|
def canvas_xy(self, event):
|
||||||
|
"""
|
||||||
|
Convert window coordinate to canvas coordinate
|
||||||
|
|
||||||
|
:param event:
|
||||||
|
:rtype: (int, int)
|
||||||
|
:return: x, y canvas coordinate
|
||||||
|
"""
|
||||||
x = self.canvasx(event.x)
|
x = self.canvasx(event.x)
|
||||||
y = self.canvasy(event.y)
|
y = self.canvasy(event.y)
|
||||||
return x, y
|
return x, y
|
||||||
|
|
||||||
def get_selected(self, event):
|
def get_selected(self, event):
|
||||||
|
"""
|
||||||
|
Retrieve the item id that is on the mouse position
|
||||||
|
|
||||||
|
:param event: mouse event
|
||||||
|
:rtype: int
|
||||||
|
:return: the item that the mouse point to
|
||||||
|
"""
|
||||||
overlapping = self.find_overlapping(event.x, event.y, event.x, event.y)
|
overlapping = self.find_overlapping(event.x, event.y, event.x, event.y)
|
||||||
nodes = set(self.find_withtag("node"))
|
nodes = set(self.find_withtag("node"))
|
||||||
selected = None
|
selected = None
|
||||||
|
@ -64,6 +111,12 @@ class CanvasGraph(tk.Canvas):
|
||||||
return selected
|
return selected
|
||||||
|
|
||||||
def click_release(self, event):
|
def click_release(self, event):
|
||||||
|
"""
|
||||||
|
Draw a node or finish drawing an edge according to the current graph mode
|
||||||
|
|
||||||
|
:param event: mouse event
|
||||||
|
:return: nothing
|
||||||
|
"""
|
||||||
self.focus_set()
|
self.focus_set()
|
||||||
self.selected = self.get_selected(event)
|
self.selected = self.get_selected(event)
|
||||||
logging.debug(f"click release selected: {self.selected}")
|
logging.debug(f"click release selected: {self.selected}")
|
||||||
|
@ -109,6 +162,12 @@ class CanvasGraph(tk.Canvas):
|
||||||
logging.debug(f"edges: {self.find_withtag('edge')}")
|
logging.debug(f"edges: {self.find_withtag('edge')}")
|
||||||
|
|
||||||
def click_press(self, event):
|
def click_press(self, event):
|
||||||
|
"""
|
||||||
|
Start drawing an edge if mouse click is on a node
|
||||||
|
|
||||||
|
:param event: mouse event
|
||||||
|
:return: nothing
|
||||||
|
"""
|
||||||
logging.debug(f"click press: {event}")
|
logging.debug(f"click press: {event}")
|
||||||
selected = self.get_selected(event)
|
selected = self.get_selected(event)
|
||||||
is_node = selected in self.find_withtag("node")
|
is_node = selected in self.find_withtag("node")
|
||||||
|
@ -117,6 +176,12 @@ class CanvasGraph(tk.Canvas):
|
||||||
self.drawing_edge = CanvasEdge(x, y, x, y, selected, self)
|
self.drawing_edge = CanvasEdge(x, y, x, y, selected, self)
|
||||||
|
|
||||||
def click_motion(self, event):
|
def click_motion(self, event):
|
||||||
|
"""
|
||||||
|
Redraw drawing edge according to the current position of the mouse
|
||||||
|
|
||||||
|
:param event: mouse event
|
||||||
|
:return: nothing
|
||||||
|
"""
|
||||||
if self.mode == GraphMode.EDGE and self.drawing_edge is not None:
|
if self.mode == GraphMode.EDGE and self.drawing_edge is not None:
|
||||||
x2, y2 = self.canvas_xy(event)
|
x2, y2 = self.canvas_xy(event)
|
||||||
x1, y1, _, _ = self.coords(self.drawing_edge.id)
|
x1, y1, _, _ = self.coords(self.drawing_edge.id)
|
||||||
|
@ -130,6 +195,12 @@ class CanvasGraph(tk.Canvas):
|
||||||
self.node_context.post(event.x_root, event.y_root)
|
self.node_context.post(event.x_root, event.y_root)
|
||||||
|
|
||||||
def set_mode(self, event):
|
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}")
|
logging.debug(f"mode event: {event}")
|
||||||
if event.char == "e":
|
if event.char == "e":
|
||||||
self.mode = GraphMode.EDGE
|
self.mode = GraphMode.EDGE
|
||||||
|
@ -147,21 +218,41 @@ class CanvasGraph(tk.Canvas):
|
||||||
|
|
||||||
|
|
||||||
class CanvasEdge:
|
class CanvasEdge:
|
||||||
|
"""
|
||||||
|
Canvas edge class
|
||||||
|
"""
|
||||||
|
|
||||||
width = 3
|
width = 3
|
||||||
|
|
||||||
def __init__(self, x1, y1, x2, y2, src, canvas):
|
def __init__(self, x1, y1, x2, y2, src, canvas):
|
||||||
|
"""
|
||||||
|
Create an instance of canvas edge object
|
||||||
|
:param int x1: source x-coord
|
||||||
|
:param int y1: source y-coord
|
||||||
|
:param int x2: destination x-coord
|
||||||
|
:param int y2: destination y-coord
|
||||||
|
:param int src: source id
|
||||||
|
:param tkinter.Canvas canvas: canvas object
|
||||||
|
"""
|
||||||
self.src = src
|
self.src = src
|
||||||
self.dst = None
|
self.dst = None
|
||||||
self.canvas = canvas
|
self.canvas = canvas
|
||||||
self.id = self.canvas.create_line(x1, y1, x2, y2, tags="edge", width=self.width)
|
self.id = self.canvas.create_line(x1, y1, x2, y2, tags="edge", width=self.width)
|
||||||
self.token = None
|
self.token = None
|
||||||
self.canvas.tag_lower(self.id)
|
|
||||||
|
# TODO resolve this
|
||||||
|
# self.canvas.tag_lower(self.id)
|
||||||
|
|
||||||
def complete(self, dst, x, y):
|
def complete(self, dst, x, y):
|
||||||
self.dst = dst
|
self.dst = dst
|
||||||
self.token = tuple(sorted((self.src, self.dst)))
|
self.token = tuple(sorted((self.src, self.dst)))
|
||||||
x1, y1, _, _ = self.canvas.coords(self.id)
|
x1, y1, _, _ = self.canvas.coords(self.id)
|
||||||
self.canvas.coords(self.id, x1, y1, x, y)
|
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):
|
def delete(self):
|
||||||
self.canvas.delete(self.id)
|
self.canvas.delete(self.id)
|
||||||
|
|
Loading…
Add table
Reference in a new issue