create grids

This commit is contained in:
Huy Pham 2019-09-30 10:11:29 -07:00
parent 130c2a9b8d
commit 269d7f8f92
3 changed files with 162 additions and 13 deletions

View file

@ -21,7 +21,7 @@ class Application(tk.Frame):
def setup_app(self):
self.master.title("CORE")
self.master.geometry("800x600")
self.master.geometry("1000x800")
image = Images.get("core")
self.master.tk.call("wm", "iconphoto", self.master._w, image)
self.pack(fill=tk.BOTH, expand=True)
@ -40,11 +40,11 @@ class Application(tk.Frame):
core_editbar.create_toolbar()
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.create_line(0, 0, 10, 10)
# self.canvas.create_rectangle(0, 0, 1000, 750, outline="#000000", fill="#ffffff", width=1)
scroll_x = tk.Scrollbar(
self.canvas, orient=tk.HORIZONTAL, command=self.canvas.xview

View file

@ -1,6 +1,7 @@
import logging
import tkinter as tk
from coretk.graph import GraphMode
from coretk.images import Images
from coretk.tooltip import CreateToolTip
@ -34,6 +35,9 @@ class CoreToolbar(object):
self.marker_option_menu = None
self.network_layer_option_menu = None
# variables used by canvas graph
self.mode = GraphMode.SELECT
def load_toolbar_images(self):
"""
Load the images that appear in core toolbar
@ -66,6 +70,24 @@ class CoreToolbar(object):
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
def destroy_previous_frame(self):
"""
Destroy any extra frame from previous before drawing a new one
@ -94,7 +116,7 @@ class CoreToolbar(object):
if i.winfo_name() != "!frame":
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
@ -106,6 +128,7 @@ class CoreToolbar(object):
"""
button = tk.Button(frame, width=self.width, height=self.height, image=img)
button.pack(side=tk.LEFT, pady=1)
CreateToolTip(button, btt_message)
button.bind("<Button-1>", lambda mb: func(main_button))
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)
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(
frame, width=self.width, height=self.height, image=image, command=func
)
button.pack(side=tk.TOP, pady=1)
CreateToolTip(button, btt_message)
def draw_button_menu_frame(self, edit_frame, option_frame, main_button):
"""
@ -165,6 +189,7 @@ class CoreToolbar(object):
def click_selection_tool(self):
logging.debug("Click SELECTION TOOL")
self.set_graph_mode(GraphMode.SELECT)
def click_start_stop_session_tool(self):
logging.debug("Click START STOP SESSION button")
@ -173,6 +198,7 @@ class CoreToolbar(object):
def click_link_tool(self):
logging.debug("Click LINK button")
self.set_graph_mode(GraphMode.EDGE)
def pick_router(self, main_button):
self.network_layer_option_menu.destroy()
@ -237,9 +263,22 @@ class CoreToolbar(object):
self.pick_ovs,
self.pick_editnode,
]
tooltip_list = [
"router",
"host",
"PC",
"mdr",
"prouter",
"OVS",
"edit node types",
]
for i in range(len(img_list)):
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
@ -320,9 +359,20 @@ class CoreToolbar(object):
self.pick_rj45,
self.pick_tunnel,
]
tooltip_list = [
"ethernet hub",
"ethernet switch",
"wireless LAN",
"rj45 physical interface tool",
"tunnel tool",
]
for i in range(len(img_list)):
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
@ -358,7 +408,6 @@ class CoreToolbar(object):
self.marker_option_menu.destroy()
main_button.configure(image=Images.get("marker"))
logging.debug("Pick MARKER")
return "break"
def pick_oval(self, main_button):
self.marker_option_menu.destroy()
@ -397,8 +446,11 @@ class CoreToolbar(object):
self.pick_rectangle,
self.pick_text,
]
tooltip_list = ["marker", "oval", "rectangle", "text"]
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
self.draw_button_menu_frame(self.edit_frame, option_frame, main_button)
@ -432,7 +484,10 @@ class CoreToolbar(object):
def create_toolbar(self):
self.load_toolbar_images()
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.edit_frame,
@ -503,7 +558,10 @@ class CoreToolbar(object):
def create_runtime_toolbar(self):
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.edit_frame,
@ -539,5 +597,5 @@ class CoreToolbar(object):
"run command from one node to another",
)
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"
)

View file

@ -17,14 +17,42 @@ class CanvasGraph(tk.Canvas):
cnf = {}
kwargs["highlightthickness"] = 0
super().__init__(master, cnf, **kwargs)
self.mode = GraphMode.SELECT
self.selected = None
self.node_context = None
self.nodes = {}
self.edges = {}
self.drawing_edge = None
self.setup_menus()
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):
self.node_context = tk.Menu(self.master)
@ -33,6 +61,11 @@ class CanvasGraph(tk.Canvas):
self.node_context.add_command(label="Three")
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("<ButtonRelease-1>", self.click_release)
self.bind("<B1-Motion>", self.click_motion)
@ -42,11 +75,25 @@ class CanvasGraph(tk.Canvas):
self.bind("n", self.set_mode)
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)
y = self.canvasy(event.y)
return x, y
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)
nodes = set(self.find_withtag("node"))
selected = None
@ -64,6 +111,12 @@ class CanvasGraph(tk.Canvas):
return selected
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.selected = self.get_selected(event)
logging.debug(f"click release selected: {self.selected}")
@ -109,6 +162,12 @@ class CanvasGraph(tk.Canvas):
logging.debug(f"edges: {self.find_withtag('edge')}")
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}")
selected = self.get_selected(event)
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)
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:
x2, y2 = self.canvas_xy(event)
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)
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
@ -147,21 +218,41 @@ class CanvasGraph(tk.Canvas):
class CanvasEdge:
"""
Canvas edge class
"""
width = 3
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.dst = None
self.canvas = canvas
self.id = self.canvas.create_line(x1, y1, x2, y2, tags="edge", width=self.width)
self.token = None
self.canvas.tag_lower(self.id)
# TODO resolve this
# self.canvas.tag_lower(self.id)
def complete(self, dst, x, y):
self.dst = dst
self.token = tuple(sorted((self.src, self.dst)))
x1, y1, _, _ = self.canvas.coords(self.id)
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)