pygui initial implementation for supporting the view menu for showing and hiding canvas elements
This commit is contained in:
parent
f45a11076f
commit
d26c4fc4ab
9 changed files with 119 additions and 61 deletions
|
@ -78,11 +78,11 @@ class Application(tk.Frame):
|
|||
|
||||
def draw(self):
|
||||
self.master.option_add("*tearOff", tk.FALSE)
|
||||
self.menubar = Menubar(self.master, self)
|
||||
self.toolbar = Toolbar(self, self)
|
||||
self.toolbar.pack(side=tk.LEFT, fill=tk.Y, ipadx=2, ipady=2)
|
||||
self.draw_canvas()
|
||||
self.draw_status()
|
||||
self.menubar = Menubar(self.master, self)
|
||||
|
||||
def draw_canvas(self):
|
||||
width = self.guiconfig["preferences"]["width"]
|
||||
|
|
|
@ -369,21 +369,16 @@ class CoreClient:
|
|||
logging.debug("canvas metadata: %s", canvas_config)
|
||||
if canvas_config:
|
||||
canvas_config = json.loads(canvas_config)
|
||||
|
||||
gridlines = canvas_config.get("gridlines", True)
|
||||
self.app.canvas.show_grid.set(gridlines)
|
||||
|
||||
fit_image = canvas_config.get("fit_image", False)
|
||||
self.app.canvas.adjust_to_dim.set(fit_image)
|
||||
|
||||
wallpaper_style = canvas_config.get("wallpaper-style", 1)
|
||||
self.app.canvas.scale_option.set(wallpaper_style)
|
||||
|
||||
width = self.app.guiconfig["preferences"]["width"]
|
||||
height = self.app.guiconfig["preferences"]["height"]
|
||||
dimensions = canvas_config.get("dimensions", [width, height])
|
||||
self.app.canvas.redraw_canvas(dimensions)
|
||||
|
||||
wallpaper = canvas_config.get("wallpaper")
|
||||
if wallpaper:
|
||||
wallpaper = str(appconfig.BACKGROUNDS_PATH.joinpath(wallpaper))
|
||||
|
|
|
@ -24,7 +24,6 @@ class CanvasWallpaperDialog(Dialog):
|
|||
super().__init__(master, app, "Canvas Background", modal=True)
|
||||
self.canvas = self.app.canvas
|
||||
self.scale_option = tk.IntVar(value=self.canvas.scale_option.get())
|
||||
self.show_grid = tk.BooleanVar(value=self.canvas.show_grid.get())
|
||||
self.adjust_to_dim = tk.BooleanVar(value=self.canvas.adjust_to_dim.get())
|
||||
self.filename = tk.StringVar(value=self.canvas.wallpaper_file)
|
||||
self.image_label = None
|
||||
|
@ -103,11 +102,6 @@ class CanvasWallpaperDialog(Dialog):
|
|||
self.options.append(button)
|
||||
|
||||
def draw_additional_options(self):
|
||||
checkbutton = ttk.Checkbutton(
|
||||
self.top, text="Show grid", variable=self.show_grid
|
||||
)
|
||||
checkbutton.grid(sticky="ew", padx=PADX)
|
||||
|
||||
checkbutton = ttk.Checkbutton(
|
||||
self.top,
|
||||
text="Adjust canvas size to image dimensions",
|
||||
|
@ -163,17 +157,13 @@ class CanvasWallpaperDialog(Dialog):
|
|||
|
||||
def click_apply(self):
|
||||
self.canvas.scale_option.set(self.scale_option.get())
|
||||
self.canvas.show_grid.set(self.show_grid.get())
|
||||
self.canvas.adjust_to_dim.set(self.adjust_to_dim.get())
|
||||
self.canvas.update_grid()
|
||||
|
||||
self.canvas.show_grid.click_handler()
|
||||
filename = self.filename.get()
|
||||
if not filename:
|
||||
filename = None
|
||||
|
||||
try:
|
||||
self.canvas.set_wallpaper(filename)
|
||||
except FileNotFoundError:
|
||||
logging.error("invalid background: %s", filename)
|
||||
|
||||
self.destroy()
|
||||
|
|
|
@ -20,15 +20,6 @@ WIRELESS_COLOR = "#009933"
|
|||
ARC_DISTANCE = 50
|
||||
|
||||
|
||||
def interface_label(interface: core_pb2.Interface) -> str:
|
||||
label = ""
|
||||
if interface.ip4:
|
||||
label = f"{interface.ip4}/{interface.ip4mask}"
|
||||
if interface.ip6:
|
||||
label = f"{label}\n{interface.ip6}/{interface.ip6mask}"
|
||||
return label
|
||||
|
||||
|
||||
def create_edge_token(src: int, dst: int, network: int = None) -> Tuple[int, ...]:
|
||||
values = [src, dst]
|
||||
if network is not None:
|
||||
|
@ -143,7 +134,12 @@ class Edge:
|
|||
if self.middle_label is None:
|
||||
x, y = self.middle_label_pos()
|
||||
self.middle_label = self.canvas.create_text(
|
||||
x, y, font=self.canvas.app.edge_font, text=text
|
||||
x,
|
||||
y,
|
||||
font=self.canvas.app.edge_font,
|
||||
text=text,
|
||||
tags=tags.LINK_LABEL,
|
||||
state=self.canvas.show_link_labels.state(),
|
||||
)
|
||||
else:
|
||||
self.canvas.itemconfig(self.middle_label, text=text)
|
||||
|
@ -168,7 +164,8 @@ class Edge:
|
|||
text=text,
|
||||
justify=tk.CENTER,
|
||||
font=self.canvas.app.edge_font,
|
||||
tags=tags.LINK_INFO,
|
||||
tags=tags.LINK_LABEL,
|
||||
state=self.canvas.show_link_labels.state(),
|
||||
)
|
||||
else:
|
||||
self.canvas.itemconfig(self.src_label, text=text)
|
||||
|
@ -181,7 +178,8 @@ class Edge:
|
|||
text=text,
|
||||
justify=tk.CENTER,
|
||||
font=self.canvas.app.edge_font,
|
||||
tags=tags.LINK_INFO,
|
||||
tags=tags.LINK_LABEL,
|
||||
state=self.canvas.show_link_labels.state(),
|
||||
)
|
||||
else:
|
||||
self.canvas.itemconfig(self.dst_label, text=text)
|
||||
|
@ -278,13 +276,25 @@ class CanvasEdge(Edge):
|
|||
self.link = link
|
||||
self.draw_labels()
|
||||
|
||||
def interface_label(self, interface: core_pb2.Interface) -> str:
|
||||
label = ""
|
||||
if interface.name and self.canvas.show_interface_names.get():
|
||||
label = f"{interface.name}"
|
||||
if interface.ip4 and self.canvas.show_ip4s.get():
|
||||
label = f"{label}\n" if label else ""
|
||||
label += f"{interface.ip4}/{interface.ip4mask}"
|
||||
if interface.ip6 and self.canvas.show_ip6s.get():
|
||||
label = f"{label}\n" if label else ""
|
||||
label += f"{interface.ip6}/{interface.ip6mask}"
|
||||
return label
|
||||
|
||||
def create_node_labels(self) -> Tuple[str, str]:
|
||||
label_one = None
|
||||
if self.link.HasField("interface_one"):
|
||||
label_one = interface_label(self.link.interface_one)
|
||||
label_one = self.interface_label(self.link.interface_one)
|
||||
label_two = None
|
||||
if self.link.HasField("interface_two"):
|
||||
label_two = interface_label(self.link.interface_two)
|
||||
label_two = self.interface_label(self.link.interface_two)
|
||||
return label_one, label_two
|
||||
|
||||
def draw_labels(self) -> None:
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
import logging
|
||||
import tkinter as tk
|
||||
from tkinter import BooleanVar
|
||||
from typing import TYPE_CHECKING, Tuple
|
||||
|
||||
from PIL import Image, ImageTk
|
||||
|
@ -30,6 +31,19 @@ ZOOM_OUT = 0.9
|
|||
ICON_SIZE = 48
|
||||
|
||||
|
||||
class ShowVar(BooleanVar):
|
||||
def __init__(self, canvas: "CanvasGraph", tag: str, value: bool) -> None:
|
||||
super().__init__(value=value)
|
||||
self.canvas = canvas
|
||||
self.tag = tag
|
||||
|
||||
def state(self) -> str:
|
||||
return tk.NORMAL if self.get() else tk.HIDDEN
|
||||
|
||||
def click_handler(self):
|
||||
self.canvas.itemconfigure(self.tag, state=self.state())
|
||||
|
||||
|
||||
class CanvasGraph(tk.Canvas):
|
||||
def __init__(
|
||||
self, master: "Application", core: "CoreClient", width: int, height: int
|
||||
|
@ -69,7 +83,6 @@ class CanvasGraph(tk.Canvas):
|
|||
self.wallpaper_drawn = None
|
||||
self.wallpaper_file = ""
|
||||
self.scale_option = tk.IntVar(value=1)
|
||||
self.show_grid = tk.BooleanVar(value=True)
|
||||
self.adjust_to_dim = tk.BooleanVar(value=False)
|
||||
|
||||
# throughput related
|
||||
|
@ -77,6 +90,17 @@ class CanvasGraph(tk.Canvas):
|
|||
self.throughput_width = 10
|
||||
self.throughput_color = "#FF0000"
|
||||
|
||||
# drawing related
|
||||
self.show_node_labels = ShowVar(self, tags.NODE_LABEL, value=True)
|
||||
self.show_link_labels = ShowVar(self, tags.LINK_LABEL, value=True)
|
||||
self.show_grid = ShowVar(self, tags.GRIDLINE, value=True)
|
||||
self.show_shapes = ShowVar(self, tags.SHAPE, value=True)
|
||||
self.show_shape_labels = ShowVar(self, tags.SHAPE_TEXT, value=True)
|
||||
self.show_marker = ShowVar(self, tags.MARKER, value=True)
|
||||
self.show_interface_names = BooleanVar(value=False)
|
||||
self.show_ip4s = BooleanVar(value=True)
|
||||
self.show_ip6s = BooleanVar(value=True)
|
||||
|
||||
# bindings
|
||||
self.setup_bindings()
|
||||
|
||||
|
@ -562,6 +586,7 @@ class CanvasGraph(tk.Canvas):
|
|||
fill=self.app.toolbar.marker_tool.color,
|
||||
outline="",
|
||||
tags=tags.MARKER,
|
||||
state=self.show_marker.state(),
|
||||
)
|
||||
return
|
||||
if selected is None:
|
||||
|
@ -818,7 +843,7 @@ class CanvasGraph(tk.Canvas):
|
|||
# redraw gridlines to new canvas size
|
||||
self.delete(tags.GRIDLINE)
|
||||
self.draw_grid()
|
||||
self.update_grid()
|
||||
self.app.canvas.show_grid.click_handler()
|
||||
|
||||
def redraw_wallpaper(self):
|
||||
if self.adjust_to_dim.get():
|
||||
|
@ -840,13 +865,6 @@ class CanvasGraph(tk.Canvas):
|
|||
for component in tags.ABOVE_WALLPAPER_TAGS:
|
||||
self.tag_raise(component)
|
||||
|
||||
def update_grid(self):
|
||||
logging.debug("updating grid show grid: %s", self.show_grid.get())
|
||||
if self.show_grid.get():
|
||||
self.itemconfig(tags.GRIDLINE, state=tk.NORMAL)
|
||||
else:
|
||||
self.itemconfig(tags.GRIDLINE, state=tk.HIDDEN)
|
||||
|
||||
def set_wallpaper(self, filename: str):
|
||||
logging.debug("setting wallpaper: %s", filename)
|
||||
if filename:
|
||||
|
@ -906,7 +924,8 @@ class CanvasGraph(tk.Canvas):
|
|||
self.master, scaled_x, scaled_y, copy, self.nodes[canvas_nid].image
|
||||
)
|
||||
|
||||
# add new node to modified_service_nodes set if that set contains the to_copy node
|
||||
# add new node to modified_service_nodes set if that set contains the
|
||||
# to_copy node
|
||||
if self.app.core.service_been_modified(core_node.id):
|
||||
self.app.core.modified_service_nodes.add(copy.id)
|
||||
|
||||
|
|
|
@ -47,9 +47,10 @@ class CanvasNode:
|
|||
x,
|
||||
label_y,
|
||||
text=self.core_node.name,
|
||||
tags=tags.NODE_NAME,
|
||||
tags=tags.NODE_LABEL,
|
||||
font=self.app.icon_text_font,
|
||||
fill="#0000CD",
|
||||
state=self.canvas.show_node_labels.state(),
|
||||
)
|
||||
self.tooltip = CanvasTooltip(self.canvas)
|
||||
self.edges = set()
|
||||
|
@ -195,7 +196,6 @@ class CanvasNode:
|
|||
label="Mobility Player", command=self.show_mobility_player
|
||||
)
|
||||
context.add_command(label="Select Adjacent", state=tk.DISABLED)
|
||||
context.add_command(label="Hide", state=tk.DISABLED)
|
||||
if NodeUtils.is_container_node(self.core_node.type):
|
||||
context.add_command(label="Shell Window", state=tk.DISABLED)
|
||||
context.add_command(label="Tcpdump", state=tk.DISABLED)
|
||||
|
@ -228,7 +228,6 @@ class CanvasNode:
|
|||
edit_menu.add_command(label="Cut", state=tk.DISABLED)
|
||||
edit_menu.add_command(label="Copy", command=self.canvas_copy)
|
||||
edit_menu.add_command(label="Delete", command=self.canvas_delete)
|
||||
edit_menu.add_command(label="Hide", state=tk.DISABLED)
|
||||
context.add_cascade(label="Edit", menu=edit_menu)
|
||||
return context
|
||||
|
||||
|
|
|
@ -85,6 +85,7 @@ class Shape:
|
|||
fill=self.shape_data.fill_color,
|
||||
outline=self.shape_data.border_color,
|
||||
width=self.shape_data.border_width,
|
||||
state=self.canvas.show_shapes.state(),
|
||||
)
|
||||
self.draw_shape_text()
|
||||
elif self.shape_type == ShapeType.RECTANGLE:
|
||||
|
@ -98,6 +99,7 @@ class Shape:
|
|||
fill=self.shape_data.fill_color,
|
||||
outline=self.shape_data.border_color,
|
||||
width=self.shape_data.border_width,
|
||||
state=self.canvas.show_shapes.state(),
|
||||
)
|
||||
self.draw_shape_text()
|
||||
elif self.shape_type == ShapeType.TEXT:
|
||||
|
@ -109,6 +111,7 @@ class Shape:
|
|||
text=self.shape_data.text,
|
||||
fill=self.shape_data.text_color,
|
||||
font=font,
|
||||
state=self.canvas.show_shapes.state(),
|
||||
)
|
||||
else:
|
||||
logging.error("unknown shape type: %s", self.shape_type)
|
||||
|
@ -136,6 +139,7 @@ class Shape:
|
|||
text=self.shape_data.text,
|
||||
fill=self.shape_data.text_color,
|
||||
font=font,
|
||||
state=self.canvas.show_shape_labels.state(),
|
||||
)
|
||||
|
||||
def shape_motion(self, x1: float, y1: float):
|
||||
|
|
|
@ -2,10 +2,10 @@ GRIDLINE = "gridline"
|
|||
SHAPE = "shape"
|
||||
SHAPE_TEXT = "shapetext"
|
||||
EDGE = "edge"
|
||||
LINK_INFO = "linkinfo"
|
||||
LINK_LABEL = "linklabel"
|
||||
WIRELESS_EDGE = "wireless"
|
||||
ANTENNA = "antenna"
|
||||
NODE_NAME = "nodename"
|
||||
NODE_LABEL = "nodename"
|
||||
NODE = "node"
|
||||
WALLPAPER = "wallpaper"
|
||||
SELECTION = "selectednodes"
|
||||
|
@ -15,19 +15,19 @@ ABOVE_WALLPAPER_TAGS = [
|
|||
SHAPE,
|
||||
SHAPE_TEXT,
|
||||
EDGE,
|
||||
LINK_INFO,
|
||||
LINK_LABEL,
|
||||
WIRELESS_EDGE,
|
||||
ANTENNA,
|
||||
NODE,
|
||||
NODE_NAME,
|
||||
NODE_LABEL,
|
||||
]
|
||||
ABOVE_SHAPE = [GRIDLINE, EDGE, LINK_INFO, WIRELESS_EDGE, ANTENNA, NODE, NODE_NAME]
|
||||
ABOVE_SHAPE = [GRIDLINE, EDGE, LINK_LABEL, WIRELESS_EDGE, ANTENNA, NODE, NODE_LABEL]
|
||||
COMPONENT_TAGS = [
|
||||
EDGE,
|
||||
NODE,
|
||||
NODE_NAME,
|
||||
NODE_LABEL,
|
||||
WALLPAPER,
|
||||
LINK_INFO,
|
||||
LINK_LABEL,
|
||||
ANTENNA,
|
||||
WIRELESS_EDGE,
|
||||
SELECTION,
|
||||
|
|
|
@ -3,7 +3,7 @@ import os
|
|||
import tkinter as tk
|
||||
import webbrowser
|
||||
from functools import partial
|
||||
from tkinter import filedialog, messagebox
|
||||
from tkinter import BooleanVar, filedialog, messagebox
|
||||
from typing import TYPE_CHECKING
|
||||
|
||||
from core.gui.appconfig import XMLS_PATH
|
||||
|
@ -41,8 +41,10 @@ class Menubar(tk.Menu):
|
|||
self.master.config(menu=self)
|
||||
self.app = app
|
||||
self.core = app.core
|
||||
self.canvas = app.canvas
|
||||
self.recent_menu = None
|
||||
self.edit_menu = None
|
||||
self.show_annotations = BooleanVar(value=True)
|
||||
self.draw()
|
||||
|
||||
def draw(self) -> None:
|
||||
|
@ -129,15 +131,41 @@ class Menubar(tk.Menu):
|
|||
Create view menu
|
||||
"""
|
||||
menu = tk.Menu(self)
|
||||
menu.add_command(label="All", state=tk.DISABLED)
|
||||
menu.add_command(label="None", state=tk.DISABLED)
|
||||
menu.add_separator()
|
||||
menu.add_command(label="Interface Names", state=tk.DISABLED)
|
||||
menu.add_command(label="IPv4 Addresses", state=tk.DISABLED)
|
||||
menu.add_command(label="IPv6 Addresses", state=tk.DISABLED)
|
||||
menu.add_command(label="Node Labels", state=tk.DISABLED)
|
||||
menu.add_command(label="Annotations", state=tk.DISABLED)
|
||||
menu.add_command(label="Grid", state=tk.DISABLED)
|
||||
menu.add_checkbutton(
|
||||
label="Interface Names",
|
||||
command=self.click_edge_label_change,
|
||||
variable=self.canvas.show_interface_names,
|
||||
)
|
||||
menu.add_checkbutton(
|
||||
label="IPv4 Addresses",
|
||||
command=self.click_edge_label_change,
|
||||
variable=self.canvas.show_ip4s,
|
||||
)
|
||||
menu.add_checkbutton(
|
||||
label="IPv6 Addresses",
|
||||
command=self.click_edge_label_change,
|
||||
variable=self.canvas.show_ip6s,
|
||||
)
|
||||
menu.add_checkbutton(
|
||||
label="Node Labels",
|
||||
command=self.canvas.show_node_labels.click_handler,
|
||||
variable=self.canvas.show_node_labels,
|
||||
)
|
||||
menu.add_checkbutton(
|
||||
label="Link Labels",
|
||||
command=self.canvas.show_link_labels.click_handler,
|
||||
variable=self.canvas.show_link_labels,
|
||||
)
|
||||
menu.add_checkbutton(
|
||||
label="Annotations",
|
||||
command=self.click_show_annotations,
|
||||
variable=self.show_annotations,
|
||||
)
|
||||
menu.add_checkbutton(
|
||||
label="Canvas Grid",
|
||||
command=self.canvas.show_grid.click_handler,
|
||||
variable=self.canvas.show_grid,
|
||||
)
|
||||
self.add_cascade(label="View", menu=menu)
|
||||
|
||||
def draw_tools_menu(self) -> None:
|
||||
|
@ -430,3 +458,16 @@ class Menubar(tk.Menu):
|
|||
x = (col * layout_size) + padding
|
||||
y = (row * layout_size) + padding
|
||||
node.move(x, y)
|
||||
|
||||
def click_edge_label_change(self) -> None:
|
||||
for edge in self.canvas.edges.values():
|
||||
edge.draw_labels()
|
||||
|
||||
def click_show_annotations(self) -> None:
|
||||
value = self.show_annotations.get()
|
||||
self.canvas.show_shapes.set(value)
|
||||
self.canvas.show_shape_labels.set(value)
|
||||
self.canvas.show_marker.set(value)
|
||||
self.canvas.show_shapes.click_handler()
|
||||
self.canvas.show_shape_labels.click_handler()
|
||||
self.canvas.show_marker.click_handler()
|
||||
|
|
Loading…
Reference in a new issue