Merge branch 'coretk' into coretk-validation
This commit is contained in:
commit
8bdc5c8e2e
7 changed files with 180 additions and 198 deletions
|
@ -72,14 +72,7 @@ class Application(tk.Frame):
|
||||||
def draw_canvas(self):
|
def draw_canvas(self):
|
||||||
width = self.guiconfig["preferences"]["width"]
|
width = self.guiconfig["preferences"]["width"]
|
||||||
height = self.guiconfig["preferences"]["height"]
|
height = self.guiconfig["preferences"]["height"]
|
||||||
self.canvas = CanvasGraph(
|
self.canvas = CanvasGraph(self, self.core, width, height)
|
||||||
self,
|
|
||||||
self.core,
|
|
||||||
width,
|
|
||||||
height,
|
|
||||||
background="#cccccc",
|
|
||||||
scrollregion=(0, 0, 1200, 1000),
|
|
||||||
)
|
|
||||||
self.canvas.pack(fill=tk.BOTH, expand=True)
|
self.canvas.pack(fill=tk.BOTH, expand=True)
|
||||||
scroll_x = ttk.Scrollbar(
|
scroll_x = ttk.Scrollbar(
|
||||||
self.canvas, orient=tk.HORIZONTAL, command=self.canvas.xview
|
self.canvas, orient=tk.HORIZONTAL, command=self.canvas.xview
|
||||||
|
|
|
@ -174,7 +174,7 @@ class CoreClient:
|
||||||
x = event.node.position.x
|
x = event.node.position.x
|
||||||
y = event.node.position.y
|
y = event.node.position.y
|
||||||
canvas_node = self.canvas_nodes[node_id]
|
canvas_node = self.canvas_nodes[node_id]
|
||||||
canvas_node.move(x, y, update=False)
|
canvas_node.move(x, y)
|
||||||
|
|
||||||
def handle_throughputs(self, event):
|
def handle_throughputs(self, event):
|
||||||
if self.throughput:
|
if self.throughput:
|
||||||
|
@ -412,10 +412,11 @@ class CoreClient:
|
||||||
show_grpc_error(e)
|
show_grpc_error(e)
|
||||||
self.app.close()
|
self.app.close()
|
||||||
|
|
||||||
def edit_node(self, node_id, x, y):
|
def edit_node(self, core_node):
|
||||||
position = core_pb2.Position(x=x, y=y)
|
|
||||||
try:
|
try:
|
||||||
self.client.edit_node(self.session_id, node_id, position, source="gui")
|
self.client.edit_node(
|
||||||
|
self.session_id, core_node.id, core_node.position, source="gui"
|
||||||
|
)
|
||||||
except grpc.RpcError as e:
|
except grpc.RpcError as e:
|
||||||
show_grpc_error(e)
|
show_grpc_error(e)
|
||||||
|
|
||||||
|
|
|
@ -231,7 +231,7 @@ class SizeAndScaleDialog(Dialog):
|
||||||
width, height = self.pixel_width.get(), self.pixel_height.get()
|
width, height = self.pixel_width.get(), self.pixel_height.get()
|
||||||
self.canvas.redraw_canvas(width, height)
|
self.canvas.redraw_canvas(width, height)
|
||||||
if self.canvas.wallpaper:
|
if self.canvas.wallpaper:
|
||||||
self.canvas.redraw()
|
self.canvas.redraw_wallpaper()
|
||||||
location = self.app.core.location
|
location = self.app.core.location
|
||||||
location.x = self.x.get()
|
location.x = self.x.get()
|
||||||
location.y = self.y.get()
|
location.y = self.y.get()
|
||||||
|
|
|
@ -27,6 +27,7 @@ class MobilityPlayer:
|
||||||
self.dialog = MobilityPlayerDialog(
|
self.dialog = MobilityPlayerDialog(
|
||||||
self.master, self.app, self.canvas_node, self.config
|
self.master, self.app, self.canvas_node, self.config
|
||||||
)
|
)
|
||||||
|
self.dialog.protocol("WM_DELETE_WINDOW", self.handle_close)
|
||||||
if self.state == MobilityAction.START:
|
if self.state == MobilityAction.START:
|
||||||
self.set_play()
|
self.set_play()
|
||||||
elif self.state == MobilityAction.PAUSE:
|
elif self.state == MobilityAction.PAUSE:
|
||||||
|
@ -35,17 +36,24 @@ class MobilityPlayer:
|
||||||
self.set_stop()
|
self.set_stop()
|
||||||
self.dialog.show()
|
self.dialog.show()
|
||||||
|
|
||||||
|
def handle_close(self):
|
||||||
|
self.dialog.destroy()
|
||||||
|
self.dialog = None
|
||||||
|
|
||||||
def set_play(self):
|
def set_play(self):
|
||||||
self.dialog.set_play()
|
|
||||||
self.state = MobilityAction.START
|
self.state = MobilityAction.START
|
||||||
|
if self.dialog:
|
||||||
|
self.dialog.set_play()
|
||||||
|
|
||||||
def set_pause(self):
|
def set_pause(self):
|
||||||
self.dialog.set_pause()
|
|
||||||
self.state = MobilityAction.PAUSE
|
self.state = MobilityAction.PAUSE
|
||||||
|
if self.dialog:
|
||||||
|
self.dialog.set_pause()
|
||||||
|
|
||||||
def set_stop(self):
|
def set_stop(self):
|
||||||
self.dialog.set_stop()
|
|
||||||
self.state = MobilityAction.STOP
|
self.state = MobilityAction.STOP
|
||||||
|
if self.dialog:
|
||||||
|
self.dialog.set_stop()
|
||||||
|
|
||||||
|
|
||||||
class MobilityPlayerDialog(Dialog):
|
class MobilityPlayerDialog(Dialog):
|
||||||
|
@ -92,7 +100,6 @@ class MobilityPlayerDialog(Dialog):
|
||||||
self.stop_button = ttk.Button(frame, image=image, command=self.click_stop)
|
self.stop_button = ttk.Button(frame, image=image, command=self.click_stop)
|
||||||
self.stop_button.image = image
|
self.stop_button.image = image
|
||||||
self.stop_button.grid(row=0, column=2, sticky="ew", padx=PAD)
|
self.stop_button.grid(row=0, column=2, sticky="ew", padx=PAD)
|
||||||
self.stop_button.state(["pressed"])
|
|
||||||
|
|
||||||
loop = tk.IntVar(value=int(self.config["loop"].value == "1"))
|
loop = tk.IntVar(value=int(self.config["loop"].value == "1"))
|
||||||
checkbutton = ttk.Checkbutton(
|
checkbutton = ttk.Checkbutton(
|
||||||
|
|
|
@ -15,14 +15,21 @@ from coretk.graph.shapeutils import is_draw_shape
|
||||||
from coretk.images import Images
|
from coretk.images import Images
|
||||||
from coretk.nodeutils import NodeUtils
|
from coretk.nodeutils import NodeUtils
|
||||||
|
|
||||||
|
SCROLL_BUFFER = 25
|
||||||
|
ZOOM_IN = 1.1
|
||||||
|
ZOOM_OUT = 0.9
|
||||||
|
|
||||||
|
|
||||||
class CanvasGraph(tk.Canvas):
|
class CanvasGraph(tk.Canvas):
|
||||||
def __init__(self, master, core, width, height, cnf=None, **kwargs):
|
def __init__(self, master, core, width, height):
|
||||||
if cnf is None:
|
super().__init__(
|
||||||
cnf = {}
|
master,
|
||||||
kwargs["highlightthickness"] = 0
|
highlightthickness=0,
|
||||||
super().__init__(master, cnf, **kwargs)
|
background="#cccccc",
|
||||||
|
scrollregion=(0, 0, width + SCROLL_BUFFER, height + SCROLL_BUFFER),
|
||||||
|
)
|
||||||
self.app = master
|
self.app = master
|
||||||
|
self.core = core
|
||||||
self.mode = GraphMode.SELECT
|
self.mode = GraphMode.SELECT
|
||||||
self.annotation_type = None
|
self.annotation_type = None
|
||||||
self.selection = {}
|
self.selection = {}
|
||||||
|
@ -35,12 +42,13 @@ class CanvasGraph(tk.Canvas):
|
||||||
self.wireless_edges = {}
|
self.wireless_edges = {}
|
||||||
self.drawing_edge = None
|
self.drawing_edge = None
|
||||||
self.grid = None
|
self.grid = None
|
||||||
self.setup_bindings()
|
|
||||||
self.core = core
|
|
||||||
self.throughput_draw = Throughput(self, core)
|
self.throughput_draw = Throughput(self, core)
|
||||||
self.shape_drawing = False
|
self.shape_drawing = False
|
||||||
self.default_width = width
|
self.default_width = width
|
||||||
self.default_height = height
|
self.default_height = height
|
||||||
|
self.ratio = 1.0
|
||||||
|
self.offset = (0, 0)
|
||||||
|
self.cursor = (0, 0)
|
||||||
|
|
||||||
# background related
|
# background related
|
||||||
self.wallpaper_id = None
|
self.wallpaper_id = None
|
||||||
|
@ -51,6 +59,9 @@ class CanvasGraph(tk.Canvas):
|
||||||
self.show_grid = tk.BooleanVar(value=True)
|
self.show_grid = tk.BooleanVar(value=True)
|
||||||
self.adjust_to_dim = tk.BooleanVar(value=False)
|
self.adjust_to_dim = tk.BooleanVar(value=False)
|
||||||
|
|
||||||
|
# bindings
|
||||||
|
self.setup_bindings()
|
||||||
|
|
||||||
# draw base canvas
|
# draw base canvas
|
||||||
self.draw_canvas()
|
self.draw_canvas()
|
||||||
self.draw_grid()
|
self.draw_grid()
|
||||||
|
@ -100,17 +111,19 @@ class CanvasGraph(tk.Canvas):
|
||||||
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)
|
||||||
self.bind("<Button-3>", self.click_context)
|
self.bind("<ButtonRelease-3>", self.click_context)
|
||||||
self.bind("<Delete>", self.press_delete)
|
self.bind("<Delete>", self.press_delete)
|
||||||
self.bind("<Control-1>", self.ctrl_click)
|
self.bind("<Control-1>", self.ctrl_click)
|
||||||
self.bind("<Double-Button-1>", self.double_click)
|
self.bind("<Double-Button-1>", self.double_click)
|
||||||
|
self.bind("<MouseWheel>", self.zoom)
|
||||||
|
self.bind("<Button-4>", lambda e: self.zoom(e, ZOOM_IN))
|
||||||
|
self.bind("<Button-5>", lambda e: self.zoom(e, ZOOM_OUT))
|
||||||
|
self.bind("<ButtonPress-3>", lambda e: self.scan_mark(e.x, e.y))
|
||||||
|
self.bind("<B3-Motion>", lambda e: self.scan_dragto(e.x, e.y, gain=1))
|
||||||
|
|
||||||
def draw_grid(self):
|
def draw_grid(self):
|
||||||
"""
|
"""
|
||||||
Create grid
|
Create grid.
|
||||||
|
|
||||||
:param int width: the width
|
|
||||||
:param int height: the height
|
|
||||||
|
|
||||||
:return: nothing
|
:return: nothing
|
||||||
"""
|
"""
|
||||||
|
@ -214,7 +227,8 @@ class CanvasGraph(tk.Canvas):
|
||||||
:rtype: int
|
:rtype: int
|
||||||
:return: the item that the mouse point to
|
:return: the item that the mouse point to
|
||||||
"""
|
"""
|
||||||
overlapping = self.find_overlapping(event.x, event.y, event.x, event.y)
|
x, y = self.canvas_xy(event)
|
||||||
|
overlapping = self.find_overlapping(x, y, x, y)
|
||||||
selected = None
|
selected = None
|
||||||
for _id in overlapping:
|
for _id in overlapping:
|
||||||
if self.drawing_edge and self.drawing_edge.id == _id:
|
if self.drawing_edge and self.drawing_edge.id == _id:
|
||||||
|
@ -331,10 +345,10 @@ class CanvasGraph(tk.Canvas):
|
||||||
self.delete(_id)
|
self.delete(_id)
|
||||||
self.selection.clear()
|
self.selection.clear()
|
||||||
|
|
||||||
def object_drag(self, object_id, offset_x, offset_y):
|
def move_selection(self, object_id, x_offset, y_offset):
|
||||||
select_id = self.selection.get(object_id)
|
select_id = self.selection.get(object_id)
|
||||||
if select_id is not None:
|
if select_id is not None:
|
||||||
self.move(select_id, offset_x, offset_y)
|
self.move(select_id, x_offset, y_offset)
|
||||||
|
|
||||||
def delete_selection_objects(self):
|
def delete_selection_objects(self):
|
||||||
edges = set()
|
edges = set()
|
||||||
|
@ -383,6 +397,21 @@ class CanvasGraph(tk.Canvas):
|
||||||
self.selection.clear()
|
self.selection.clear()
|
||||||
return nodes
|
return nodes
|
||||||
|
|
||||||
|
def zoom(self, event, factor=None):
|
||||||
|
if not factor:
|
||||||
|
factor = ZOOM_IN if event.delta > 0 else ZOOM_OUT
|
||||||
|
event.x, event.y = self.canvasx(event.x), self.canvasy(event.y)
|
||||||
|
self.scale("all", event.x, event.y, factor, factor)
|
||||||
|
self.configure(scrollregion=self.bbox("all"))
|
||||||
|
self.ratio *= float(factor)
|
||||||
|
self.offset = (
|
||||||
|
self.offset[0] * factor + event.x * (1 - factor),
|
||||||
|
self.offset[1] * factor + event.y * (1 - factor),
|
||||||
|
)
|
||||||
|
logging.info("ratio: %s", self.ratio)
|
||||||
|
logging.info("offset: %s", self.offset)
|
||||||
|
self.redraw_wallpaper()
|
||||||
|
|
||||||
def click_press(self, event):
|
def click_press(self, event):
|
||||||
"""
|
"""
|
||||||
Start drawing an edge if mouse click is on a node
|
Start drawing an edge if mouse click is on a node
|
||||||
|
@ -390,40 +419,46 @@ class CanvasGraph(tk.Canvas):
|
||||||
:param event: mouse event
|
:param event: mouse event
|
||||||
:return: nothing
|
:return: nothing
|
||||||
"""
|
"""
|
||||||
logging.debug(f"click press: {event}")
|
x, y = self.canvas_xy(event)
|
||||||
|
self.cursor = x, y
|
||||||
selected = self.get_selected(event)
|
selected = self.get_selected(event)
|
||||||
|
logging.debug(f"click press: %s", selected)
|
||||||
is_node = selected in self.nodes
|
is_node = selected in self.nodes
|
||||||
if self.mode == GraphMode.EDGE and is_node:
|
if self.mode == GraphMode.EDGE and is_node:
|
||||||
x, y = self.coords(selected)
|
x, y = self.coords(selected)
|
||||||
self.drawing_edge = CanvasEdge(x, y, x, y, selected, self)
|
self.drawing_edge = CanvasEdge(x, y, x, y, selected, self)
|
||||||
|
|
||||||
if self.mode == GraphMode.ANNOTATION and selected is None:
|
if self.mode == GraphMode.ANNOTATION and selected is None:
|
||||||
x, y = self.canvas_xy(event)
|
|
||||||
shape = Shape(self.app, self, self.annotation_type, x, y)
|
shape = Shape(self.app, self, self.annotation_type, x, y)
|
||||||
self.selected = shape.id
|
self.selected = shape.id
|
||||||
self.shape_drawing = True
|
self.shape_drawing = True
|
||||||
self.shapes[shape.id] = shape
|
self.shapes[shape.id] = shape
|
||||||
|
|
||||||
if self.mode == GraphMode.SELECT:
|
|
||||||
if selected is not None:
|
if selected is not None:
|
||||||
if selected in self.shapes:
|
|
||||||
x, y = self.canvas_xy(event)
|
|
||||||
shape = self.shapes[selected]
|
|
||||||
shape.cursor_x = x
|
|
||||||
shape.cursor_y = y
|
|
||||||
if selected not in self.selection:
|
if selected not in self.selection:
|
||||||
|
if selected in self.shapes:
|
||||||
|
shape = self.shapes[selected]
|
||||||
self.select_object(shape.id)
|
self.select_object(shape.id)
|
||||||
self.selected = selected
|
self.selected = selected
|
||||||
|
elif selected in self.nodes:
|
||||||
|
node = self.nodes[selected]
|
||||||
|
self.select_object(node.id)
|
||||||
|
self.selected = selected
|
||||||
else:
|
else:
|
||||||
self.clear_selection()
|
self.clear_selection()
|
||||||
|
|
||||||
def ctrl_click(self, event):
|
def ctrl_click(self, event):
|
||||||
|
# update cursor location
|
||||||
|
x, y = self.canvas_xy(event)
|
||||||
|
self.cursor = x, y
|
||||||
|
|
||||||
|
# handle multiple selections
|
||||||
logging.debug("control left click: %s", event)
|
logging.debug("control left click: %s", event)
|
||||||
selected = self.get_selected(event)
|
selected = self.get_selected(event)
|
||||||
if (
|
if (
|
||||||
self.mode == GraphMode.SELECT
|
selected not in self.selection
|
||||||
and selected is not None
|
|
||||||
and selected in self.shapes
|
and selected in self.shapes
|
||||||
|
or selected in self.nodes
|
||||||
):
|
):
|
||||||
self.select_object(selected, choose_multiple=True)
|
self.select_object(selected, choose_multiple=True)
|
||||||
|
|
||||||
|
@ -434,36 +469,31 @@ class CanvasGraph(tk.Canvas):
|
||||||
:param event: mouse event
|
:param event: mouse event
|
||||||
:return: nothing
|
:return: nothing
|
||||||
"""
|
"""
|
||||||
|
x, y = self.canvas_xy(event)
|
||||||
|
x_offset = x - self.cursor[0]
|
||||||
|
y_offset = y - self.cursor[1]
|
||||||
|
self.cursor = x, y
|
||||||
|
|
||||||
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)
|
|
||||||
x1, y1, _, _ = self.coords(self.drawing_edge.id)
|
x1, y1, _, _ = self.coords(self.drawing_edge.id)
|
||||||
self.coords(self.drawing_edge.id, x1, y1, x2, y2)
|
self.coords(self.drawing_edge.id, x1, y1, x, y)
|
||||||
if self.mode == GraphMode.ANNOTATION:
|
if self.mode == GraphMode.ANNOTATION:
|
||||||
if is_draw_shape(self.annotation_type) and self.shape_drawing:
|
if is_draw_shape(self.annotation_type) and self.shape_drawing:
|
||||||
x, y = self.canvas_xy(event)
|
|
||||||
shape = self.shapes[self.selected]
|
shape = self.shapes[self.selected]
|
||||||
shape.shape_motion(x, y)
|
shape.shape_motion(x, y)
|
||||||
if (
|
|
||||||
self.mode == GraphMode.SELECT
|
|
||||||
and self.selected is not None
|
|
||||||
and self.selected in self.shapes
|
|
||||||
):
|
|
||||||
x, y = self.canvas_xy(event)
|
|
||||||
shape = self.shapes[self.selected]
|
|
||||||
delta_x = x - shape.cursor_x
|
|
||||||
delta_y = y - shape.cursor_y
|
|
||||||
shape.motion(event)
|
|
||||||
|
|
||||||
# move other selected components
|
if self.mode == GraphMode.EDGE:
|
||||||
for _id in self.selection:
|
return
|
||||||
if _id != self.selected and _id in self.shapes:
|
|
||||||
shape = self.shapes[_id]
|
# move selected objects
|
||||||
shape.motion(None, delta_x, delta_y)
|
for selected_id in self.selection:
|
||||||
if _id != self.selected and _id in self.nodes:
|
if selected_id in self.shapes:
|
||||||
node = self.nodes[_id]
|
shape = self.shapes[selected_id]
|
||||||
node_x = node.core_node.position.x
|
shape.motion(x_offset, y_offset)
|
||||||
node_y = node.core_node.position.y
|
|
||||||
node.move(node_x + delta_x, node_y + delta_y)
|
if selected_id in self.nodes:
|
||||||
|
node = self.nodes[selected_id]
|
||||||
|
node.motion(x_offset, y_offset, update=self.core.is_runtime())
|
||||||
|
|
||||||
def click_context(self, event):
|
def click_context(self, event):
|
||||||
logging.info("context event: %s", self.context)
|
logging.info("context event: %s", self.context)
|
||||||
|
@ -516,24 +546,30 @@ class CanvasGraph(tk.Canvas):
|
||||||
canvas_h = abs(y0 - y1)
|
canvas_h = abs(y0 - y1)
|
||||||
return canvas_w, canvas_h
|
return canvas_w, canvas_h
|
||||||
|
|
||||||
def wallpaper_upper_left(self):
|
def draw_wallpaper(self, image):
|
||||||
tk_img = ImageTk.PhotoImage(self.wallpaper)
|
x1, y1, x2, y2 = self.bbox(self.grid)
|
||||||
# crop image if it is bigger than canvas
|
x = (x1 + x2) / 2
|
||||||
canvas_w, canvas_h = self.width_and_height()
|
y = (y1 + y2) / 2
|
||||||
cropx = img_w = tk_img.width()
|
|
||||||
cropy = img_h = tk_img.height()
|
|
||||||
if img_w > canvas_w:
|
|
||||||
cropx -= img_w - canvas_w
|
|
||||||
if img_h > canvas_h:
|
|
||||||
cropy -= img_h - canvas_h
|
|
||||||
cropped = self.wallpaper.crop((0, 0, cropx, cropy))
|
|
||||||
cropped_tk = ImageTk.PhotoImage(cropped)
|
|
||||||
self.delete(self.wallpaper_id)
|
|
||||||
# place left corner of image to the left corner of the canvas
|
|
||||||
self.wallpaper_id = self.create_image(
|
self.wallpaper_id = self.create_image(
|
||||||
(cropx / 2, cropy / 2), image=cropped_tk, tags=tags.WALLPAPER
|
(x + 1, y + 1), image=image, tags=tags.WALLPAPER
|
||||||
)
|
)
|
||||||
self.wallpaper_drawn = cropped_tk
|
self.wallpaper_drawn = image
|
||||||
|
|
||||||
|
def wallpaper_upper_left(self):
|
||||||
|
self.delete(self.wallpaper_id)
|
||||||
|
|
||||||
|
# place left corner of image to the left corner of the canvas
|
||||||
|
tk_img = ImageTk.PhotoImage(self.wallpaper)
|
||||||
|
width, height = self.width_and_height()
|
||||||
|
cropx = image_width = tk_img.width()
|
||||||
|
cropy = image_height = tk_img.height()
|
||||||
|
if image_width > width:
|
||||||
|
cropx = width
|
||||||
|
if image_height > height:
|
||||||
|
cropy = height
|
||||||
|
cropped = self.wallpaper.crop((0, 0, cropx, cropy))
|
||||||
|
image = ImageTk.PhotoImage(cropped)
|
||||||
|
self.draw_wallpaper(image)
|
||||||
|
|
||||||
def wallpaper_center(self):
|
def wallpaper_center(self):
|
||||||
"""
|
"""
|
||||||
|
@ -541,27 +577,26 @@ class CanvasGraph(tk.Canvas):
|
||||||
|
|
||||||
:return: nothing
|
:return: nothing
|
||||||
"""
|
"""
|
||||||
tk_img = ImageTk.PhotoImage(self.wallpaper)
|
|
||||||
canvas_w, canvas_h = self.width_and_height()
|
|
||||||
cropx = img_w = tk_img.width()
|
|
||||||
cropy = img_h = tk_img.height()
|
|
||||||
# dimension of the cropped image
|
|
||||||
if img_w > canvas_w:
|
|
||||||
cropx -= img_w - canvas_w
|
|
||||||
if img_h > canvas_h:
|
|
||||||
cropy -= img_h - canvas_h
|
|
||||||
x0 = (img_w - cropx) / 2
|
|
||||||
y0 = (img_h - cropy) / 2
|
|
||||||
x1 = x0 + cropx
|
|
||||||
y1 = y0 + cropy
|
|
||||||
cropped = self.wallpaper.crop((x0, y0, x1, y1))
|
|
||||||
cropped_tk = ImageTk.PhotoImage(cropped)
|
|
||||||
# place the center of the image at the center of the canvas
|
|
||||||
self.delete(self.wallpaper_id)
|
self.delete(self.wallpaper_id)
|
||||||
self.wallpaper_id = self.create_image(
|
|
||||||
(canvas_w / 2, canvas_h / 2), image=cropped_tk, tags=tags.WALLPAPER
|
# dimension of the cropped image
|
||||||
)
|
tk_img = ImageTk.PhotoImage(self.wallpaper)
|
||||||
self.wallpaper_drawn = cropped_tk
|
width, height = self.width_and_height()
|
||||||
|
image_width = tk_img.width()
|
||||||
|
image_height = tk_img.height()
|
||||||
|
cropx = 0
|
||||||
|
if image_width > width:
|
||||||
|
cropx = (image_width - width) / 2
|
||||||
|
cropy = 0
|
||||||
|
if image_height > height:
|
||||||
|
cropy = (image_height - height) / 2
|
||||||
|
x1 = 0 + cropx
|
||||||
|
y1 = 0 + cropy
|
||||||
|
x2 = image_width - cropx
|
||||||
|
y2 = image_height - cropy
|
||||||
|
cropped = self.wallpaper.crop((x1, y1, x2, y2))
|
||||||
|
image = ImageTk.PhotoImage(cropped)
|
||||||
|
self.draw_wallpaper(image)
|
||||||
|
|
||||||
def wallpaper_scaled(self):
|
def wallpaper_scaled(self):
|
||||||
"""
|
"""
|
||||||
|
@ -569,22 +604,18 @@ class CanvasGraph(tk.Canvas):
|
||||||
|
|
||||||
:return: nothing
|
:return: nothing
|
||||||
"""
|
"""
|
||||||
|
self.delete(self.wallpaper_id)
|
||||||
canvas_w, canvas_h = self.width_and_height()
|
canvas_w, canvas_h = self.width_and_height()
|
||||||
image = Images.create(self.wallpaper_file, int(canvas_w), int(canvas_h))
|
image = Images.create(self.wallpaper_file, int(canvas_w), int(canvas_h))
|
||||||
self.delete(self.wallpaper_id)
|
self.draw_wallpaper(image)
|
||||||
self.wallpaper_id = self.create_image(
|
|
||||||
(canvas_w / 2, canvas_h / 2), image=image, tags=tags.WALLPAPER
|
|
||||||
)
|
|
||||||
self.wallpaper_drawn = image
|
|
||||||
|
|
||||||
def resize_to_wallpaper(self):
|
def resize_to_wallpaper(self):
|
||||||
image_tk = ImageTk.PhotoImage(self.wallpaper)
|
|
||||||
img_w = image_tk.width()
|
|
||||||
img_h = image_tk.height()
|
|
||||||
self.delete(self.wallpaper_id)
|
self.delete(self.wallpaper_id)
|
||||||
self.redraw_canvas(img_w, img_h)
|
image = ImageTk.PhotoImage(self.wallpaper)
|
||||||
self.wallpaper_id = self.create_image((img_w / 2, img_h / 2), image=image_tk)
|
image_width = image.width()
|
||||||
self.wallpaper_drawn = image_tk
|
image_height = image.height()
|
||||||
|
self.redraw_canvas(image_width, image_height)
|
||||||
|
self.draw_wallpaper(image)
|
||||||
|
|
||||||
def redraw_canvas(self, width, height):
|
def redraw_canvas(self, width, height):
|
||||||
"""
|
"""
|
||||||
|
@ -593,7 +624,7 @@ class CanvasGraph(tk.Canvas):
|
||||||
:return: nothing
|
:return: nothing
|
||||||
"""
|
"""
|
||||||
# resize canvas and scrollregion
|
# resize canvas and scrollregion
|
||||||
self.config(scrollregion=(0, 0, width + 200, height + 200))
|
self.config(scrollregion=(0, 0, width + SCROLL_BUFFER, height + SCROLL_BUFFER))
|
||||||
self.coords(self.grid, 0, 0, width, height)
|
self.coords(self.grid, 0, 0, width, height)
|
||||||
|
|
||||||
# redraw gridlines to new canvas size
|
# redraw gridlines to new canvas size
|
||||||
|
@ -601,7 +632,7 @@ class CanvasGraph(tk.Canvas):
|
||||||
self.draw_grid()
|
self.draw_grid()
|
||||||
self.update_grid()
|
self.update_grid()
|
||||||
|
|
||||||
def redraw(self):
|
def redraw_wallpaper(self):
|
||||||
if self.adjust_to_dim.get():
|
if self.adjust_to_dim.get():
|
||||||
self.resize_to_wallpaper()
|
self.resize_to_wallpaper()
|
||||||
else:
|
else:
|
||||||
|
@ -633,7 +664,7 @@ class CanvasGraph(tk.Canvas):
|
||||||
img = Image.open(filename)
|
img = Image.open(filename)
|
||||||
self.wallpaper = img
|
self.wallpaper = img
|
||||||
self.wallpaper_file = filename
|
self.wallpaper_file = filename
|
||||||
self.redraw()
|
self.redraw_wallpaper()
|
||||||
else:
|
else:
|
||||||
if self.wallpaper_id is not None:
|
if self.wallpaper_id is not None:
|
||||||
self.delete(self.wallpaper_id)
|
self.delete(self.wallpaper_id)
|
||||||
|
|
|
@ -1,4 +1,3 @@
|
||||||
import logging
|
|
||||||
import tkinter as tk
|
import tkinter as tk
|
||||||
from tkinter import font
|
from tkinter import font
|
||||||
|
|
||||||
|
@ -12,7 +11,6 @@ from coretk.dialogs.nodeservice import NodeService
|
||||||
from coretk.dialogs.wlanconfig import WlanConfigDialog
|
from coretk.dialogs.wlanconfig import WlanConfigDialog
|
||||||
from coretk.errors import show_grpc_error
|
from coretk.errors import show_grpc_error
|
||||||
from coretk.graph import tags
|
from coretk.graph import tags
|
||||||
from coretk.graph.enums import GraphMode
|
|
||||||
from coretk.graph.tooltip import CanvasTooltip
|
from coretk.graph.tooltip import CanvasTooltip
|
||||||
from coretk.nodeutils import NodeUtils
|
from coretk.nodeutils import NodeUtils
|
||||||
|
|
||||||
|
@ -30,12 +28,11 @@ class CanvasNode:
|
||||||
self.id = self.canvas.create_image(
|
self.id = self.canvas.create_image(
|
||||||
x, y, anchor=tk.CENTER, image=self.image, tags=tags.NODE
|
x, y, anchor=tk.CENTER, image=self.image, tags=tags.NODE
|
||||||
)
|
)
|
||||||
image_box = self.canvas.bbox(self.id)
|
|
||||||
y = image_box[3] + NODE_TEXT_OFFSET
|
|
||||||
text_font = font.Font(family="TkIconFont", size=12)
|
text_font = font.Font(family="TkIconFont", size=12)
|
||||||
|
label_y = self._get_label_y()
|
||||||
self.text_id = self.canvas.create_text(
|
self.text_id = self.canvas.create_text(
|
||||||
x,
|
x,
|
||||||
y,
|
label_y,
|
||||||
text=self.core_node.name,
|
text=self.core_node.name,
|
||||||
tags=tags.NODE_NAME,
|
tags=tags.NODE_NAME,
|
||||||
font=text_font,
|
font=text_font,
|
||||||
|
@ -45,17 +42,11 @@ class CanvasNode:
|
||||||
self.edges = set()
|
self.edges = set()
|
||||||
self.interfaces = []
|
self.interfaces = []
|
||||||
self.wireless_edges = set()
|
self.wireless_edges = set()
|
||||||
self.moving = None
|
|
||||||
self.antennae = []
|
self.antennae = []
|
||||||
self.setup_bindings()
|
self.setup_bindings()
|
||||||
|
|
||||||
def setup_bindings(self):
|
def setup_bindings(self):
|
||||||
# self.canvas.bind("<Button-3>", self.click_context)
|
|
||||||
self.canvas.tag_bind(self.id, "<ButtonPress-1>", self.click_press)
|
|
||||||
self.canvas.tag_bind(self.id, "<ButtonRelease-1>", self.click_release)
|
|
||||||
self.canvas.tag_bind(self.id, "<B1-Motion>", self.motion)
|
|
||||||
self.canvas.tag_bind(self.id, "<Double-Button-1>", self.double_click)
|
self.canvas.tag_bind(self.id, "<Double-Button-1>", self.double_click)
|
||||||
self.canvas.tag_bind(self.id, "<Control-1>", self.select_multiple)
|
|
||||||
self.canvas.tag_bind(self.id, "<Enter>", self.on_enter)
|
self.canvas.tag_bind(self.id, "<Enter>", self.on_enter)
|
||||||
self.canvas.tag_bind(self.id, "<Leave>", self.on_leave)
|
self.canvas.tag_bind(self.id, "<Leave>", self.on_leave)
|
||||||
|
|
||||||
|
@ -96,30 +87,32 @@ class CanvasNode:
|
||||||
self.canvas.delete(antenna_id)
|
self.canvas.delete(antenna_id)
|
||||||
self.antennae.clear()
|
self.antennae.clear()
|
||||||
|
|
||||||
def move_antennae(self, x_offset, y_offset):
|
|
||||||
"""
|
|
||||||
redraw antennas of a node according to the new node position
|
|
||||||
|
|
||||||
:return: nothing
|
|
||||||
"""
|
|
||||||
for antenna_id in self.antennae:
|
|
||||||
self.canvas.move(antenna_id, x_offset, y_offset)
|
|
||||||
|
|
||||||
def redraw(self):
|
def redraw(self):
|
||||||
self.canvas.itemconfig(self.id, image=self.image)
|
self.canvas.itemconfig(self.id, image=self.image)
|
||||||
self.canvas.itemconfig(self.text_id, text=self.core_node.name)
|
self.canvas.itemconfig(self.text_id, text=self.core_node.name)
|
||||||
|
|
||||||
def move(self, x, y, update=True):
|
def _get_label_y(self):
|
||||||
old_x = self.core_node.position.x
|
image_box = self.canvas.bbox(self.id)
|
||||||
old_y = self.core_node.position.y
|
return image_box[3] + NODE_TEXT_OFFSET
|
||||||
x_offset = x - old_x
|
|
||||||
y_offset = y - old_y
|
def move(self, x, y):
|
||||||
self.core_node.position.x = int(x)
|
x_offset = x - self.core_node.position.x
|
||||||
self.core_node.position.y = int(y)
|
y_offset = y - self.core_node.position.y
|
||||||
|
self.motion(x_offset, y_offset, update=False)
|
||||||
|
|
||||||
|
def motion(self, x_offset, y_offset, update=True):
|
||||||
self.canvas.move(self.id, x_offset, y_offset)
|
self.canvas.move(self.id, x_offset, y_offset)
|
||||||
self.canvas.move(self.text_id, x_offset, y_offset)
|
self.canvas.move(self.text_id, x_offset, y_offset)
|
||||||
self.move_antennae(x_offset, y_offset)
|
self.canvas.move_selection(self.id, x_offset, y_offset)
|
||||||
self.canvas.object_drag(self.id, x_offset, y_offset)
|
x, y = self.canvas.coords(self.id)
|
||||||
|
self.core_node.position.x = int(x)
|
||||||
|
self.core_node.position.y = int(y)
|
||||||
|
|
||||||
|
# move antennae
|
||||||
|
for antenna_id in self.antennae:
|
||||||
|
self.canvas.move(antenna_id, x_offset, y_offset)
|
||||||
|
|
||||||
|
# move edges
|
||||||
for edge in self.edges:
|
for edge in self.edges:
|
||||||
x1, y1, x2, y2 = self.canvas.coords(edge.id)
|
x1, y1, x2, y2 = self.canvas.coords(edge.id)
|
||||||
if edge.src == self.id:
|
if edge.src == self.id:
|
||||||
|
@ -127,16 +120,18 @@ class CanvasNode:
|
||||||
else:
|
else:
|
||||||
self.canvas.coords(edge.id, x1, y1, x, y)
|
self.canvas.coords(edge.id, x1, y1, x, y)
|
||||||
self.canvas.throughput_draw.move(edge)
|
self.canvas.throughput_draw.move(edge)
|
||||||
|
|
||||||
edge.link_info.recalculate_info()
|
edge.link_info.recalculate_info()
|
||||||
|
|
||||||
for edge in self.wireless_edges:
|
for edge in self.wireless_edges:
|
||||||
x1, y1, x2, y2 = self.canvas.coords(edge.id)
|
x1, y1, x2, y2 = self.canvas.coords(edge.id)
|
||||||
if edge.src == self.id:
|
if edge.src == self.id:
|
||||||
self.canvas.coords(edge.id, x, y, x2, y2)
|
self.canvas.coords(edge.id, x, y, x2, y2)
|
||||||
else:
|
else:
|
||||||
self.canvas.coords(edge.id, x1, y1, x, y)
|
self.canvas.coords(edge.id, x1, y1, x, y)
|
||||||
|
|
||||||
|
# update core with new location
|
||||||
if self.app.core.is_runtime() and update:
|
if self.app.core.is_runtime() and update:
|
||||||
self.app.core.edit_node(self.core_node.id, int(x), int(y))
|
self.app.core.edit_node(self.core_node)
|
||||||
|
|
||||||
def on_enter(self, event):
|
def on_enter(self, event):
|
||||||
if self.app.core.is_runtime() and self.app.core.observer:
|
if self.app.core.is_runtime() and self.app.core.observer:
|
||||||
|
@ -162,39 +157,6 @@ class CanvasNode:
|
||||||
self.core_node.position.x = int(x)
|
self.core_node.position.x = int(x)
|
||||||
self.core_node.position.y = int(y)
|
self.core_node.position.y = int(y)
|
||||||
|
|
||||||
def click_press(self, event):
|
|
||||||
logging.debug(f"node click press {self.core_node.name}: {event}")
|
|
||||||
self.moving = self.canvas.canvas_xy(event)
|
|
||||||
if self.id not in self.canvas.selection:
|
|
||||||
self.canvas.select_object(self.id)
|
|
||||||
self.canvas.selected = self.id
|
|
||||||
|
|
||||||
def click_release(self, event):
|
|
||||||
logging.debug(f"node click release {self.core_node.name}: {event}")
|
|
||||||
self.update_coords()
|
|
||||||
self.moving = None
|
|
||||||
|
|
||||||
def motion(self, event):
|
|
||||||
if self.canvas.mode == GraphMode.EDGE:
|
|
||||||
return
|
|
||||||
x, y = self.canvas.canvas_xy(event)
|
|
||||||
my_x = self.core_node.position.x
|
|
||||||
my_y = self.core_node.position.y
|
|
||||||
self.move(x, y)
|
|
||||||
|
|
||||||
# move other selected components
|
|
||||||
for object_id, selection_id in self.canvas.selection.items():
|
|
||||||
if object_id != self.id and object_id in self.canvas.nodes:
|
|
||||||
canvas_node = self.canvas.nodes[object_id]
|
|
||||||
other_old_x = canvas_node.core_node.position.x
|
|
||||||
other_old_y = canvas_node.core_node.position.y
|
|
||||||
other_new_x = x + other_old_x - my_x
|
|
||||||
other_new_y = y + other_old_y - my_y
|
|
||||||
self.canvas.nodes[object_id].move(other_new_x, other_new_y)
|
|
||||||
elif object_id in self.canvas.shapes:
|
|
||||||
shape = self.canvas.shapes[object_id]
|
|
||||||
shape.motion(None, x - my_x, y - my_y)
|
|
||||||
|
|
||||||
def create_context(self):
|
def create_context(self):
|
||||||
is_wlan = self.core_node.type == NodeType.WIRELESS_LAN
|
is_wlan = self.core_node.type == NodeType.WIRELESS_LAN
|
||||||
is_emane = self.core_node.type == NodeType.EMANE
|
is_emane = self.core_node.type == NodeType.EMANE
|
||||||
|
@ -242,9 +204,6 @@ class CanvasNode:
|
||||||
context.add_command(label="Hide", state=tk.DISABLED)
|
context.add_command(label="Hide", state=tk.DISABLED)
|
||||||
return context
|
return context
|
||||||
|
|
||||||
def select_multiple(self, event):
|
|
||||||
self.canvas.select_object(self.id, choose_multiple=True)
|
|
||||||
|
|
||||||
def show_config(self):
|
def show_config(self):
|
||||||
self.canvas.context = None
|
self.canvas.context = None
|
||||||
dialog = NodeConfigDialog(self.app, self.app, self)
|
dialog = NodeConfigDialog(self.app, self.app, self)
|
||||||
|
|
|
@ -49,13 +49,9 @@ class Shape:
|
||||||
if data is None:
|
if data is None:
|
||||||
self.created = False
|
self.created = False
|
||||||
self.shape_data = AnnotationData()
|
self.shape_data = AnnotationData()
|
||||||
self.cursor_x = x1
|
|
||||||
self.cursor_y = y1
|
|
||||||
else:
|
else:
|
||||||
self.created = True
|
self.created = True
|
||||||
self.shape_data = data
|
self.shape_data = data
|
||||||
self.cursor_x = None
|
|
||||||
self.cursor_y = None
|
|
||||||
self.draw()
|
self.draw()
|
||||||
|
|
||||||
def draw(self):
|
def draw(self):
|
||||||
|
@ -136,16 +132,11 @@ class Shape:
|
||||||
s = ShapeDialog(self.app, self.app, self)
|
s = ShapeDialog(self.app, self.app, self)
|
||||||
s.show()
|
s.show()
|
||||||
|
|
||||||
def motion(self, event, delta_x=None, delta_y=None):
|
def motion(self, x_offset, y_offset):
|
||||||
if event is not None:
|
self.canvas.move(self.id, x_offset, y_offset)
|
||||||
delta_x = event.x - self.cursor_x
|
self.canvas.move_selection(self.id, x_offset, y_offset)
|
||||||
delta_y = event.y - self.cursor_y
|
|
||||||
self.cursor_x = event.x
|
|
||||||
self.cursor_y = event.y
|
|
||||||
self.canvas.move(self.id, delta_x, delta_y)
|
|
||||||
self.canvas.object_drag(self.id, delta_x, delta_y)
|
|
||||||
if self.text_id is not None:
|
if self.text_id is not None:
|
||||||
self.canvas.move(self.text_id, delta_x, delta_y)
|
self.canvas.move(self.text_id, x_offset, y_offset)
|
||||||
|
|
||||||
def delete(self):
|
def delete(self):
|
||||||
self.canvas.delete(self.id)
|
self.canvas.delete(self.id)
|
||||||
|
|
Loading…
Add table
Reference in a new issue