more on type hinting, remove unecessary function comments
This commit is contained in:
parent
7bbd6aa353
commit
eb5f2c5648
34 changed files with 169 additions and 326 deletions
|
@ -204,7 +204,7 @@ class CoreClient:
|
||||||
self.handling_throughputs.cancel()
|
self.handling_throughputs.cancel()
|
||||||
self.handling_throughputs = None
|
self.handling_throughputs = None
|
||||||
|
|
||||||
def handle_throughputs(self, event):
|
def handle_throughputs(self, event: core_pb2.ThroughputsEvent):
|
||||||
if event.session_id != self.session_id:
|
if event.session_id != self.session_id:
|
||||||
logging.warning(
|
logging.warning(
|
||||||
"ignoring throughput event session(%s) current(%s)",
|
"ignoring throughput event session(%s) current(%s)",
|
||||||
|
@ -303,7 +303,7 @@ class CoreClient:
|
||||||
def is_runtime(self) -> bool:
|
def is_runtime(self) -> bool:
|
||||||
return self.state == core_pb2.SessionState.RUNTIME
|
return self.state == core_pb2.SessionState.RUNTIME
|
||||||
|
|
||||||
def parse_metadata(self, config):
|
def parse_metadata(self, config: Dict[str, str]):
|
||||||
# canvas setting
|
# canvas setting
|
||||||
canvas_config = config.get("canvas")
|
canvas_config = config.get("canvas")
|
||||||
logging.info("canvas metadata: %s", canvas_config)
|
logging.info("canvas metadata: %s", canvas_config)
|
||||||
|
@ -367,8 +367,6 @@ class CoreClient:
|
||||||
def create_new_session(self):
|
def create_new_session(self):
|
||||||
"""
|
"""
|
||||||
Create a new session
|
Create a new session
|
||||||
|
|
||||||
:return: nothing
|
|
||||||
"""
|
"""
|
||||||
try:
|
try:
|
||||||
response = self.client.create_session()
|
response = self.client.create_session()
|
||||||
|
@ -399,8 +397,6 @@ class CoreClient:
|
||||||
def set_up(self):
|
def set_up(self):
|
||||||
"""
|
"""
|
||||||
Query sessions, if there exist any, prompt whether to join one
|
Query sessions, if there exist any, prompt whether to join one
|
||||||
|
|
||||||
:return: existing sessions
|
|
||||||
"""
|
"""
|
||||||
try:
|
try:
|
||||||
self.client.connect()
|
self.client.connect()
|
||||||
|
@ -534,9 +530,6 @@ class CoreClient:
|
||||||
def save_xml(self, file_path: str):
|
def save_xml(self, file_path: str):
|
||||||
"""
|
"""
|
||||||
Save core session as to an xml file
|
Save core session as to an xml file
|
||||||
|
|
||||||
:param str file_path: file path that user pick
|
|
||||||
:return: nothing
|
|
||||||
"""
|
"""
|
||||||
try:
|
try:
|
||||||
if self.state != core_pb2.SessionState.RUNTIME:
|
if self.state != core_pb2.SessionState.RUNTIME:
|
||||||
|
@ -552,9 +545,6 @@ class CoreClient:
|
||||||
def open_xml(self, file_path: str):
|
def open_xml(self, file_path: str):
|
||||||
"""
|
"""
|
||||||
Open core xml
|
Open core xml
|
||||||
|
|
||||||
:param str file_path: file to open
|
|
||||||
:return: session id
|
|
||||||
"""
|
"""
|
||||||
try:
|
try:
|
||||||
response = self.client.open_xml(file_path)
|
response = self.client.open_xml(file_path)
|
||||||
|
@ -596,7 +586,7 @@ class CoreClient:
|
||||||
return response.data
|
return response.data
|
||||||
|
|
||||||
def set_node_service_file(
|
def set_node_service_file(
|
||||||
self, node_id: int, service_name: str, file_name: str, data: str
|
self, node_id: int, service_name: str, file_name: str, data: bytes
|
||||||
):
|
):
|
||||||
response = self.client.set_node_service_file(
|
response = self.client.set_node_service_file(
|
||||||
self.session_id, node_id, service_name, file_name, data
|
self.session_id, node_id, service_name, file_name, data
|
||||||
|
@ -606,8 +596,6 @@ class CoreClient:
|
||||||
def create_nodes_and_links(self):
|
def create_nodes_and_links(self):
|
||||||
"""
|
"""
|
||||||
create nodes and links that have not been created yet
|
create nodes and links that have not been created yet
|
||||||
|
|
||||||
:return: nothing
|
|
||||||
"""
|
"""
|
||||||
node_protos = [x.core_node for x in self.canvas_nodes.values()]
|
node_protos = [x.core_node for x in self.canvas_nodes.values()]
|
||||||
link_protos = [x.link for x in self.links.values()]
|
link_protos = [x.link for x in self.links.values()]
|
||||||
|
@ -634,8 +622,6 @@ class CoreClient:
|
||||||
def send_data(self):
|
def send_data(self):
|
||||||
"""
|
"""
|
||||||
send to daemon all session info, but don't start the session
|
send to daemon all session info, but don't start the session
|
||||||
|
|
||||||
:return: nothing
|
|
||||||
"""
|
"""
|
||||||
self.create_nodes_and_links()
|
self.create_nodes_and_links()
|
||||||
for config_proto in self.get_wlan_configs_proto():
|
for config_proto in self.get_wlan_configs_proto():
|
||||||
|
@ -680,18 +666,13 @@ class CoreClient:
|
||||||
def close(self):
|
def close(self):
|
||||||
"""
|
"""
|
||||||
Clean ups when done using grpc
|
Clean ups when done using grpc
|
||||||
|
|
||||||
:return: nothing
|
|
||||||
"""
|
"""
|
||||||
logging.debug("close grpc")
|
logging.debug("close grpc")
|
||||||
self.client.close()
|
self.client.close()
|
||||||
|
|
||||||
def next_node_id(self):
|
def next_node_id(self) -> int:
|
||||||
"""
|
"""
|
||||||
Get the next usable node id.
|
Get the next usable node id.
|
||||||
|
|
||||||
:return: the next id to be used
|
|
||||||
:rtype: int
|
|
||||||
"""
|
"""
|
||||||
i = 1
|
i = 1
|
||||||
while True:
|
while True:
|
||||||
|
@ -743,9 +724,6 @@ class CoreClient:
|
||||||
"""
|
"""
|
||||||
remove the nodes selected by the user and anything related to that node
|
remove the nodes selected by the user and anything related to that node
|
||||||
such as link, configurations, interfaces
|
such as link, configurations, interfaces
|
||||||
|
|
||||||
:param list canvas_nodes: list of nodes to delete
|
|
||||||
:return: nothing
|
|
||||||
"""
|
"""
|
||||||
edges = set()
|
edges = set()
|
||||||
for canvas_node in canvas_nodes:
|
for canvas_node in canvas_nodes:
|
||||||
|
@ -767,9 +745,6 @@ class CoreClient:
|
||||||
if edge in edges:
|
if edge in edges:
|
||||||
continue
|
continue
|
||||||
edges.add(edge)
|
edges.add(edge)
|
||||||
#
|
|
||||||
# if edge.token not in self.links:
|
|
||||||
# logging.error("unknown edge: %s", edge.token)
|
|
||||||
self.links.pop(edge.token, None)
|
self.links.pop(edge.token, None)
|
||||||
|
|
||||||
def create_interface(self, canvas_node: CanvasNode) -> core_pb2.Interface:
|
def create_interface(self, canvas_node: CanvasNode) -> core_pb2.Interface:
|
||||||
|
@ -795,12 +770,6 @@ class CoreClient:
|
||||||
"""
|
"""
|
||||||
Create core link for a pair of canvas nodes, with token referencing
|
Create core link for a pair of canvas nodes, with token referencing
|
||||||
the canvas edge.
|
the canvas edge.
|
||||||
|
|
||||||
:param edge: edge for link
|
|
||||||
:param canvas_src_node: canvas node one
|
|
||||||
:param canvas_dst_node: canvas node two
|
|
||||||
|
|
||||||
:return: nothing
|
|
||||||
"""
|
"""
|
||||||
src_node = canvas_src_node.core_node
|
src_node = canvas_src_node.core_node
|
||||||
dst_node = canvas_dst_node.core_node
|
dst_node = canvas_dst_node.core_node
|
||||||
|
|
|
@ -110,7 +110,7 @@ class AlertsDialog(Dialog):
|
||||||
dialog = DaemonLog(self, self.app)
|
dialog = DaemonLog(self, self.app)
|
||||||
dialog.show()
|
dialog.show()
|
||||||
|
|
||||||
def click_select(self, event):
|
def click_select(self, event: tk.Event):
|
||||||
current = self.tree.selection()[0]
|
current = self.tree.selection()[0]
|
||||||
alarm = self.alarm_map[current]
|
alarm = self.alarm_map[current]
|
||||||
self.codetext.text.config(state=tk.NORMAL)
|
self.codetext.text.config(state=tk.NORMAL)
|
||||||
|
|
|
@ -14,8 +14,6 @@ class SizeAndScaleDialog(Dialog):
|
||||||
def __init__(self, master, app):
|
def __init__(self, master, app):
|
||||||
"""
|
"""
|
||||||
create an instance for size and scale object
|
create an instance for size and scale object
|
||||||
|
|
||||||
:param app: main application
|
|
||||||
"""
|
"""
|
||||||
super().__init__(master, app, "Canvas Size and Scale", modal=True)
|
super().__init__(master, app, "Canvas Size and Scale", modal=True)
|
||||||
self.canvas = self.app.canvas
|
self.canvas = self.app.canvas
|
||||||
|
|
|
@ -140,8 +140,6 @@ class CanvasWallpaperDialog(Dialog):
|
||||||
def click_clear(self):
|
def click_clear(self):
|
||||||
"""
|
"""
|
||||||
delete like shown in image link entry if there is any
|
delete like shown in image link entry if there is any
|
||||||
|
|
||||||
:return: nothing
|
|
||||||
"""
|
"""
|
||||||
# delete entry
|
# delete entry
|
||||||
self.filename.set("")
|
self.filename.set("")
|
||||||
|
|
|
@ -31,7 +31,7 @@ class ColorPickerDialog(Dialog):
|
||||||
self.draw()
|
self.draw()
|
||||||
self.set_bindings()
|
self.set_bindings()
|
||||||
|
|
||||||
def askcolor(self):
|
def askcolor(self) -> str:
|
||||||
self.show()
|
self.show()
|
||||||
return self.color
|
return self.color
|
||||||
|
|
||||||
|
@ -175,12 +175,9 @@ class ColorPickerDialog(Dialog):
|
||||||
self.color = self.hex.get()
|
self.color = self.hex.get()
|
||||||
self.destroy()
|
self.destroy()
|
||||||
|
|
||||||
def get_hex(self):
|
def get_hex(self) -> str:
|
||||||
"""
|
"""
|
||||||
convert current RGB values into hex color
|
convert current RGB values into hex color
|
||||||
|
|
||||||
:rtype: str
|
|
||||||
:return: hex color
|
|
||||||
"""
|
"""
|
||||||
red = self.red_entry.get()
|
red = self.red_entry.get()
|
||||||
blue = self.blue_entry.get()
|
blue = self.blue_entry.get()
|
||||||
|
@ -210,35 +207,31 @@ class ColorPickerDialog(Dialog):
|
||||||
self.set_entry(red, green, blue)
|
self.set_entry(red, green, blue)
|
||||||
self.set_scale(red, green, blue)
|
self.set_scale(red, green, blue)
|
||||||
self.display.config(background=hex_code)
|
self.display.config(background=hex_code)
|
||||||
self.set_label(red, green, blue)
|
self.set_label(str(red), str(green), str(blue))
|
||||||
|
|
||||||
def scale_callback(self, var, color_var):
|
def scale_callback(self, var: tk.IntVar, color_var: tk.IntVar):
|
||||||
color_var.set(var.get())
|
color_var.set(var.get())
|
||||||
self.focus = "rgb"
|
self.focus = "rgb"
|
||||||
self.update_color()
|
self.update_color()
|
||||||
|
|
||||||
def set_scale(self, red, green, blue):
|
def set_scale(self, red: int, green: int, blue: int):
|
||||||
self.red_scale.set(red)
|
self.red_scale.set(red)
|
||||||
self.green_scale.set(green)
|
self.green_scale.set(green)
|
||||||
self.blue_scale.set(blue)
|
self.blue_scale.set(blue)
|
||||||
|
|
||||||
def set_entry(self, red, green, blue):
|
def set_entry(self, red: int, green: int, blue: int):
|
||||||
self.red.set(red)
|
self.red.set(red)
|
||||||
self.green.set(green)
|
self.green.set(green)
|
||||||
self.blue.set(blue)
|
self.blue.set(blue)
|
||||||
|
|
||||||
def set_label(self, red, green, blue):
|
def set_label(self, red: str, green: str, blue: str):
|
||||||
self.red_label.configure(background="#%02x%02x%02x" % (int(red), 0, 0))
|
self.red_label.configure(background="#%02x%02x%02x" % (int(red), 0, 0))
|
||||||
self.green_label.configure(background="#%02x%02x%02x" % (0, int(green), 0))
|
self.green_label.configure(background="#%02x%02x%02x" % (0, int(green), 0))
|
||||||
self.blue_label.configure(background="#%02x%02x%02x" % (0, 0, int(blue)))
|
self.blue_label.configure(background="#%02x%02x%02x" % (0, 0, int(blue)))
|
||||||
|
|
||||||
def get_rgb(self, hex_code):
|
def get_rgb(self, hex_code: str) -> [int, int, int]:
|
||||||
"""
|
"""
|
||||||
convert a valid hex code to RGB values
|
convert a valid hex code to RGB values
|
||||||
|
|
||||||
:param string hex_code: color in hex
|
|
||||||
:rtype: tuple(int, int, int)
|
|
||||||
:return: the RGB values
|
|
||||||
"""
|
"""
|
||||||
if len(hex_code) == 4:
|
if len(hex_code) == 4:
|
||||||
red = hex_code[1]
|
red = hex_code[1]
|
||||||
|
|
|
@ -5,6 +5,7 @@ copy service config dialog
|
||||||
import logging
|
import logging
|
||||||
import tkinter as tk
|
import tkinter as tk
|
||||||
from tkinter import ttk
|
from tkinter import ttk
|
||||||
|
from typing import Tuple
|
||||||
|
|
||||||
from core.gui.dialogs.dialog import Dialog
|
from core.gui.dialogs.dialog import Dialog
|
||||||
from core.gui.themes import FRAME_PAD, PADX
|
from core.gui.themes import FRAME_PAD, PADX
|
||||||
|
@ -147,7 +148,7 @@ class CopyServiceConfigDialog(Dialog):
|
||||||
dialog = ViewConfigDialog(self, self.app, self.node_id, data)
|
dialog = ViewConfigDialog(self, self.app, self.node_id, data)
|
||||||
dialog.show()
|
dialog.show()
|
||||||
|
|
||||||
def get_node_service(self, selected):
|
def get_node_service(self, selected: Tuple[str]) -> [int, str]:
|
||||||
service_tree_id = self.tree.parent(selected[0])
|
service_tree_id = self.tree.parent(selected[0])
|
||||||
service_name = self.tree.item(service_tree_id)["text"]
|
service_name = self.tree.item(service_tree_id)["text"]
|
||||||
node_tree_id = self.tree.parent(service_tree_id)
|
node_tree_id = self.tree.parent(service_tree_id)
|
||||||
|
|
|
@ -71,7 +71,7 @@ class ServicesSelectDialog(Dialog):
|
||||||
# trigger group change
|
# trigger group change
|
||||||
self.groups.listbox.event_generate("<<ListboxSelect>>")
|
self.groups.listbox.event_generate("<<ListboxSelect>>")
|
||||||
|
|
||||||
def handle_group_change(self, event):
|
def handle_group_change(self, event: tk.Event):
|
||||||
selection = self.groups.listbox.curselection()
|
selection = self.groups.listbox.curselection()
|
||||||
if selection:
|
if selection:
|
||||||
index = selection[0]
|
index = selection[0]
|
||||||
|
@ -81,7 +81,7 @@ class ServicesSelectDialog(Dialog):
|
||||||
checked = name in self.current_services
|
checked = name in self.current_services
|
||||||
self.services.add(name, checked)
|
self.services.add(name, checked)
|
||||||
|
|
||||||
def service_clicked(self, name, var):
|
def service_clicked(self, name: str, var: tk.BooleanVar):
|
||||||
if var.get() and name not in self.current_services:
|
if var.get() and name not in self.current_services:
|
||||||
self.current_services.add(name)
|
self.current_services.add(name)
|
||||||
elif not var.get() and name in self.current_services:
|
elif not var.get() and name in self.current_services:
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
import tkinter as tk
|
import tkinter as tk
|
||||||
from tkinter import ttk
|
from tkinter import ttk
|
||||||
|
from typing import Optional
|
||||||
|
|
||||||
from core.gui.images import ImageEnum, Images
|
from core.gui.images import ImageEnum, Images
|
||||||
from core.gui.themes import DIALOG_PAD
|
from core.gui.themes import DIALOG_PAD
|
||||||
|
@ -30,7 +31,7 @@ class Dialog(tk.Toplevel):
|
||||||
self.grab_set()
|
self.grab_set()
|
||||||
self.wait_window()
|
self.wait_window()
|
||||||
|
|
||||||
def draw_spacer(self, row=None):
|
def draw_spacer(self, row: Optional[int] = None):
|
||||||
frame = ttk.Frame(self.top)
|
frame = ttk.Frame(self.top)
|
||||||
frame.grid(row=row, sticky="nsew")
|
frame.grid(row=row, sticky="nsew")
|
||||||
frame.rowconfigure(0, weight=1)
|
frame.rowconfigure(0, weight=1)
|
||||||
|
|
|
@ -116,8 +116,6 @@ class EmaneConfigDialog(Dialog):
|
||||||
def draw_emane_configuration(self):
|
def draw_emane_configuration(self):
|
||||||
"""
|
"""
|
||||||
draw the main frame for emane configuration
|
draw the main frame for emane configuration
|
||||||
|
|
||||||
:return: nothing
|
|
||||||
"""
|
"""
|
||||||
label = ttk.Label(
|
label = ttk.Label(
|
||||||
self.top,
|
self.top,
|
||||||
|
@ -143,8 +141,6 @@ class EmaneConfigDialog(Dialog):
|
||||||
def draw_emane_models(self):
|
def draw_emane_models(self):
|
||||||
"""
|
"""
|
||||||
create a combobox that has all the known emane models
|
create a combobox that has all the known emane models
|
||||||
|
|
||||||
:return: nothing
|
|
||||||
"""
|
"""
|
||||||
frame = ttk.Frame(self.top)
|
frame = ttk.Frame(self.top)
|
||||||
frame.grid(sticky="ew", pady=PADY)
|
frame.grid(sticky="ew", pady=PADY)
|
||||||
|
@ -210,8 +206,6 @@ class EmaneConfigDialog(Dialog):
|
||||||
def click_model_config(self):
|
def click_model_config(self):
|
||||||
"""
|
"""
|
||||||
draw emane model configuration
|
draw emane model configuration
|
||||||
|
|
||||||
:return: nothing
|
|
||||||
"""
|
"""
|
||||||
model_name = self.emane_model.get()
|
model_name = self.emane_model.get()
|
||||||
logging.info("configuring emane model: %s", model_name)
|
logging.info("configuring emane model: %s", model_name)
|
||||||
|
@ -220,12 +214,9 @@ class EmaneConfigDialog(Dialog):
|
||||||
)
|
)
|
||||||
dialog.show()
|
dialog.show()
|
||||||
|
|
||||||
def emane_model_change(self, event):
|
def emane_model_change(self, event: tk.Event):
|
||||||
"""
|
"""
|
||||||
update emane model options button
|
update emane model options button
|
||||||
|
|
||||||
:param event:
|
|
||||||
:return: nothing
|
|
||||||
"""
|
"""
|
||||||
model_name = self.emane_model.get()
|
model_name = self.emane_model.get()
|
||||||
self.emane_model_button.config(text=f"{model_name} options")
|
self.emane_model_button.config(text=f"{model_name} options")
|
||||||
|
|
|
@ -62,11 +62,11 @@ class HookDialog(Dialog):
|
||||||
button = ttk.Button(frame, text="Cancel", command=lambda: self.destroy())
|
button = ttk.Button(frame, text="Cancel", command=lambda: self.destroy())
|
||||||
button.grid(row=0, column=1, sticky="ew")
|
button.grid(row=0, column=1, sticky="ew")
|
||||||
|
|
||||||
def state_change(self, event):
|
def state_change(self, event: tk.Event):
|
||||||
state_name = self.state.get()
|
state_name = self.state.get()
|
||||||
self.name.set(f"{state_name.lower()}_hook.sh")
|
self.name.set(f"{state_name.lower()}_hook.sh")
|
||||||
|
|
||||||
def set(self, hook):
|
def set(self, hook: core_pb2.Hook):
|
||||||
self.hook = hook
|
self.hook = hook
|
||||||
self.name.set(hook.file)
|
self.name.set(hook.file)
|
||||||
self.codetext.text.delete(1.0, tk.END)
|
self.codetext.text.delete(1.0, tk.END)
|
||||||
|
@ -140,7 +140,7 @@ class HooksDialog(Dialog):
|
||||||
self.edit_button.config(state=tk.DISABLED)
|
self.edit_button.config(state=tk.DISABLED)
|
||||||
self.delete_button.config(state=tk.DISABLED)
|
self.delete_button.config(state=tk.DISABLED)
|
||||||
|
|
||||||
def select(self, event):
|
def select(self, event: tk.Event):
|
||||||
if self.listbox.curselection():
|
if self.listbox.curselection():
|
||||||
index = self.listbox.curselection()[0]
|
index = self.listbox.curselection()[0]
|
||||||
self.selected = self.listbox.get(index)
|
self.selected = self.listbox.get(index)
|
||||||
|
|
|
@ -4,6 +4,7 @@ link configuration
|
||||||
import logging
|
import logging
|
||||||
import tkinter as tk
|
import tkinter as tk
|
||||||
from tkinter import ttk
|
from tkinter import ttk
|
||||||
|
from typing import Union
|
||||||
|
|
||||||
from core.api.grpc import core_pb2
|
from core.api.grpc import core_pb2
|
||||||
from core.gui.dialogs.colorpicker import ColorPickerDialog
|
from core.gui.dialogs.colorpicker import ColorPickerDialog
|
||||||
|
@ -11,7 +12,7 @@ from core.gui.dialogs.dialog import Dialog
|
||||||
from core.gui.themes import PADX, PADY
|
from core.gui.themes import PADX, PADY
|
||||||
|
|
||||||
|
|
||||||
def get_int(var):
|
def get_int(var: tk.StringVar) -> Union[int, None]:
|
||||||
value = var.get()
|
value = var.get()
|
||||||
if value != "":
|
if value != "":
|
||||||
return int(value)
|
return int(value)
|
||||||
|
@ -19,7 +20,7 @@ def get_int(var):
|
||||||
return None
|
return None
|
||||||
|
|
||||||
|
|
||||||
def get_float(var):
|
def get_float(var: tk.StringVar) -> Union[int, None]:
|
||||||
value = var.get()
|
value = var.get()
|
||||||
if value != "":
|
if value != "":
|
||||||
return float(value)
|
return float(value)
|
||||||
|
@ -103,7 +104,7 @@ class LinkConfigurationDialog(Dialog):
|
||||||
button = ttk.Button(frame, text="Cancel", command=self.destroy)
|
button = ttk.Button(frame, text="Cancel", command=self.destroy)
|
||||||
button.grid(row=0, column=1, sticky="ew")
|
button.grid(row=0, column=1, sticky="ew")
|
||||||
|
|
||||||
def get_frame(self):
|
def get_frame(self) -> ttk.Frame:
|
||||||
frame = ttk.Frame(self.top)
|
frame = ttk.Frame(self.top)
|
||||||
frame.columnconfigure(1, weight=1)
|
frame.columnconfigure(1, weight=1)
|
||||||
if self.is_symmetric:
|
if self.is_symmetric:
|
||||||
|
@ -339,8 +340,6 @@ class LinkConfigurationDialog(Dialog):
|
||||||
def load_link_config(self):
|
def load_link_config(self):
|
||||||
"""
|
"""
|
||||||
populate link config to the table
|
populate link config to the table
|
||||||
|
|
||||||
:return: nothing
|
|
||||||
"""
|
"""
|
||||||
width = self.app.canvas.itemcget(self.edge.id, "width")
|
width = self.app.canvas.itemcget(self.edge.id, "width")
|
||||||
self.width.set(width)
|
self.width.set(width)
|
||||||
|
|
|
@ -53,13 +53,13 @@ class MarkerDialog(Dialog):
|
||||||
for i in canvas.find_withtag("marker"):
|
for i in canvas.find_withtag("marker"):
|
||||||
canvas.delete(i)
|
canvas.delete(i)
|
||||||
|
|
||||||
def change_color(self, event):
|
def change_color(self, event: tk.Event):
|
||||||
color_picker = ColorPickerDialog(self, self.app, self.color)
|
color_picker = ColorPickerDialog(self, self.app, self.color)
|
||||||
color = color_picker.askcolor()
|
color = color_picker.askcolor()
|
||||||
event.widget.configure(background=color)
|
event.widget.configure(background=color)
|
||||||
self.color = color
|
self.color = color
|
||||||
|
|
||||||
def change_thickness(self, event):
|
def change_thickness(self, event: tk.Event):
|
||||||
self.radius = self.marker_thickness.get()
|
self.radius = self.marker_thickness.get()
|
||||||
|
|
||||||
def show(self):
|
def show(self):
|
||||||
|
|
|
@ -13,7 +13,7 @@ from core.gui.themes import FRAME_PAD, PADX, PADY
|
||||||
from core.gui.widgets import ListboxScroll, image_chooser
|
from core.gui.widgets import ListboxScroll, image_chooser
|
||||||
|
|
||||||
|
|
||||||
def mac_auto(is_auto, entry):
|
def mac_auto(is_auto, entry: ttk.Entry):
|
||||||
logging.info("mac auto clicked")
|
logging.info("mac auto clicked")
|
||||||
if is_auto.get():
|
if is_auto.get():
|
||||||
logging.info("disabling mac")
|
logging.info("disabling mac")
|
||||||
|
@ -217,7 +217,7 @@ class NodeConfigDialog(Dialog):
|
||||||
button = ttk.Button(frame, text="Cancel", command=self.destroy)
|
button = ttk.Button(frame, text="Cancel", command=self.destroy)
|
||||||
button.grid(row=0, column=1, sticky="ew")
|
button.grid(row=0, column=1, sticky="ew")
|
||||||
|
|
||||||
def click_emane_config(self, emane_model, interface_id):
|
def click_emane_config(self, emane_model: str, interface_id: int):
|
||||||
dialog = EmaneModelDialog(self, self.app, self.node, emane_model, interface_id)
|
dialog = EmaneModelDialog(self, self.app, self.node, emane_model, interface_id)
|
||||||
dialog.show()
|
dialog.show()
|
||||||
|
|
||||||
|
@ -248,7 +248,7 @@ class NodeConfigDialog(Dialog):
|
||||||
self.canvas_node.redraw()
|
self.canvas_node.redraw()
|
||||||
self.destroy()
|
self.destroy()
|
||||||
|
|
||||||
def interface_select(self, event):
|
def interface_select(self, event: tk.Event):
|
||||||
listbox = event.widget
|
listbox = event.widget
|
||||||
cur = listbox.curselection()
|
cur = listbox.curselection()
|
||||||
if cur:
|
if cur:
|
||||||
|
|
|
@ -87,7 +87,7 @@ class NodeServiceDialog(Dialog):
|
||||||
# trigger group change
|
# trigger group change
|
||||||
self.groups.listbox.event_generate("<<ListboxSelect>>")
|
self.groups.listbox.event_generate("<<ListboxSelect>>")
|
||||||
|
|
||||||
def handle_group_change(self, event=None):
|
def handle_group_change(self, event: tk.Event = None):
|
||||||
selection = self.groups.listbox.curselection()
|
selection = self.groups.listbox.curselection()
|
||||||
if selection:
|
if selection:
|
||||||
index = selection[0]
|
index = selection[0]
|
||||||
|
@ -97,7 +97,7 @@ class NodeServiceDialog(Dialog):
|
||||||
checked = name in self.current_services
|
checked = name in self.current_services
|
||||||
self.services.add(name, checked)
|
self.services.add(name, checked)
|
||||||
|
|
||||||
def service_clicked(self, name, var):
|
def service_clicked(self, name: str, var: tk.IntVar):
|
||||||
if var.get() and name not in self.current_services:
|
if var.get() and name not in self.current_services:
|
||||||
self.current_services.add(name)
|
self.current_services.add(name)
|
||||||
elif not var.get() and name in self.current_services:
|
elif not var.get() and name in self.current_services:
|
||||||
|
@ -150,7 +150,7 @@ class NodeServiceDialog(Dialog):
|
||||||
checkbutton.invoke()
|
checkbutton.invoke()
|
||||||
return
|
return
|
||||||
|
|
||||||
def is_custom_service(self, service):
|
def is_custom_service(self, service: str) -> bool:
|
||||||
service_configs = self.app.core.service_configs
|
service_configs = self.app.core.service_configs
|
||||||
file_configs = self.app.core.file_configs
|
file_configs = self.app.core.file_configs
|
||||||
if self.node_id in service_configs and service in service_configs[self.node_id]:
|
if self.node_id in service_configs and service in service_configs[self.node_id]:
|
||||||
|
|
|
@ -126,7 +126,7 @@ class ObserverDialog(Dialog):
|
||||||
self.save_button.config(state=tk.DISABLED)
|
self.save_button.config(state=tk.DISABLED)
|
||||||
self.delete_button.config(state=tk.DISABLED)
|
self.delete_button.config(state=tk.DISABLED)
|
||||||
|
|
||||||
def handle_observer_change(self, event):
|
def handle_observer_change(self, event: tk.Event):
|
||||||
selection = self.observers.curselection()
|
selection = self.observers.curselection()
|
||||||
if selection:
|
if selection:
|
||||||
self.selected_index = selection[0]
|
self.selected_index = selection[0]
|
||||||
|
|
|
@ -72,7 +72,7 @@ class PreferencesDialog(Dialog):
|
||||||
button = ttk.Button(frame, text="Cancel", command=self.destroy)
|
button = ttk.Button(frame, text="Cancel", command=self.destroy)
|
||||||
button.grid(row=0, column=1, sticky="ew")
|
button.grid(row=0, column=1, sticky="ew")
|
||||||
|
|
||||||
def theme_change(self, event):
|
def theme_change(self, event: tk.Event):
|
||||||
theme = self.theme.get()
|
theme = self.theme.get()
|
||||||
logging.info("changing theme: %s", theme)
|
logging.info("changing theme: %s", theme)
|
||||||
self.app.style.theme_use(theme)
|
self.app.style.theme_use(theme)
|
||||||
|
|
|
@ -155,7 +155,7 @@ class ServersDialog(Dialog):
|
||||||
self.save_button.config(state=tk.DISABLED)
|
self.save_button.config(state=tk.DISABLED)
|
||||||
self.delete_button.config(state=tk.DISABLED)
|
self.delete_button.config(state=tk.DISABLED)
|
||||||
|
|
||||||
def handle_server_change(self, event):
|
def handle_server_change(self, event: tk.Event):
|
||||||
selection = self.servers.curselection()
|
selection = self.servers.curselection()
|
||||||
if selection:
|
if selection:
|
||||||
self.selected_index = selection[0]
|
self.selected_index = selection[0]
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
"Service configuration dialog"
|
"Service configuration dialog"
|
||||||
import tkinter as tk
|
import tkinter as tk
|
||||||
from tkinter import ttk
|
from tkinter import ttk
|
||||||
|
from typing import List
|
||||||
|
|
||||||
import grpc
|
import grpc
|
||||||
|
|
||||||
|
@ -345,7 +346,7 @@ class ServiceConfigDialog(Dialog):
|
||||||
button = ttk.Button(frame, text="Cancel", command=self.destroy)
|
button = ttk.Button(frame, text="Cancel", command=self.destroy)
|
||||||
button.grid(row=0, column=3, sticky="ew")
|
button.grid(row=0, column=3, sticky="ew")
|
||||||
|
|
||||||
def add_filename(self, event):
|
def add_filename(self, event: tk.Event):
|
||||||
# not worry about it for now
|
# not worry about it for now
|
||||||
return
|
return
|
||||||
frame_contains_button = event.widget.master
|
frame_contains_button = event.widget.master
|
||||||
|
@ -354,7 +355,7 @@ class ServiceConfigDialog(Dialog):
|
||||||
if filename not in combobox["values"]:
|
if filename not in combobox["values"]:
|
||||||
combobox["values"] += (filename,)
|
combobox["values"] += (filename,)
|
||||||
|
|
||||||
def delete_filename(self, event):
|
def delete_filename(self, event: tk.Event):
|
||||||
# not worry about it for now
|
# not worry about it for now
|
||||||
return
|
return
|
||||||
frame_comntains_button = event.widget.master
|
frame_comntains_button = event.widget.master
|
||||||
|
@ -364,7 +365,7 @@ class ServiceConfigDialog(Dialog):
|
||||||
combobox["values"] = tuple([x for x in combobox["values"] if x != filename])
|
combobox["values"] = tuple([x for x in combobox["values"] if x != filename])
|
||||||
combobox.set("")
|
combobox.set("")
|
||||||
|
|
||||||
def add_command(self, event):
|
def add_command(self, event: tk.Event):
|
||||||
frame_contains_button = event.widget.master
|
frame_contains_button = event.widget.master
|
||||||
listbox = frame_contains_button.master.grid_slaves(row=1, column=0)[0].listbox
|
listbox = frame_contains_button.master.grid_slaves(row=1, column=0)[0].listbox
|
||||||
command_to_add = frame_contains_button.grid_slaves(row=0, column=0)[0].get()
|
command_to_add = frame_contains_button.grid_slaves(row=0, column=0)[0].get()
|
||||||
|
@ -375,7 +376,7 @@ class ServiceConfigDialog(Dialog):
|
||||||
return
|
return
|
||||||
listbox.insert(tk.END, command_to_add)
|
listbox.insert(tk.END, command_to_add)
|
||||||
|
|
||||||
def update_entry(self, event):
|
def update_entry(self, event: tk.Event):
|
||||||
listbox = event.widget
|
listbox = event.widget
|
||||||
current_selection = listbox.curselection()
|
current_selection = listbox.curselection()
|
||||||
if len(current_selection) > 0:
|
if len(current_selection) > 0:
|
||||||
|
@ -386,7 +387,7 @@ class ServiceConfigDialog(Dialog):
|
||||||
entry.delete(0, "end")
|
entry.delete(0, "end")
|
||||||
entry.insert(0, cmd)
|
entry.insert(0, cmd)
|
||||||
|
|
||||||
def delete_command(self, event):
|
def delete_command(self, event: tk.Event):
|
||||||
button = event.widget
|
button = event.widget
|
||||||
frame_contains_button = button.master
|
frame_contains_button = button.master
|
||||||
listbox = frame_contains_button.master.grid_slaves(row=1, column=0)[0].listbox
|
listbox = frame_contains_button.master.grid_slaves(row=1, column=0)[0].listbox
|
||||||
|
@ -439,13 +440,13 @@ class ServiceConfigDialog(Dialog):
|
||||||
show_grpc_error(e)
|
show_grpc_error(e)
|
||||||
self.destroy()
|
self.destroy()
|
||||||
|
|
||||||
def display_service_file_data(self, event):
|
def display_service_file_data(self, event: tk.Event):
|
||||||
combobox = event.widget
|
combobox = event.widget
|
||||||
filename = combobox.get()
|
filename = combobox.get()
|
||||||
self.service_file_data.text.delete(1.0, "end")
|
self.service_file_data.text.delete(1.0, "end")
|
||||||
self.service_file_data.text.insert("end", self.temp_service_files[filename])
|
self.service_file_data.text.insert("end", self.temp_service_files[filename])
|
||||||
|
|
||||||
def update_temp_service_file_data(self, event):
|
def update_temp_service_file_data(self, event: tk.Event):
|
||||||
scrolledtext = event.widget
|
scrolledtext = event.widget
|
||||||
filename = self.filename_combobox.get()
|
filename = self.filename_combobox.get()
|
||||||
self.temp_service_files[filename] = scrolledtext.get(1.0, "end")
|
self.temp_service_files[filename] = scrolledtext.get(1.0, "end")
|
||||||
|
@ -490,7 +491,9 @@ class ServiceConfigDialog(Dialog):
|
||||||
dialog = CopyServiceConfigDialog(self, self.app, self.node_id)
|
dialog = CopyServiceConfigDialog(self, self.app, self.node_id)
|
||||||
dialog.show()
|
dialog.show()
|
||||||
|
|
||||||
def append_commands(self, commands, listbox, to_add):
|
def append_commands(
|
||||||
|
self, commands: List[str], listbox: tk.Listbox, to_add: List[str]
|
||||||
|
):
|
||||||
for cmd in to_add:
|
for cmd in to_add:
|
||||||
commands.append(cmd)
|
commands.append(cmd)
|
||||||
listbox.insert(tk.END, cmd)
|
listbox.insert(tk.END, cmd)
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
import logging
|
import logging
|
||||||
import tkinter as tk
|
import tkinter as tk
|
||||||
from tkinter import ttk
|
from tkinter import ttk
|
||||||
|
from typing import Iterable
|
||||||
|
|
||||||
import grpc
|
import grpc
|
||||||
|
|
||||||
|
@ -21,7 +22,7 @@ class SessionsDialog(Dialog):
|
||||||
self.sessions = self.get_sessions()
|
self.sessions = self.get_sessions()
|
||||||
self.draw()
|
self.draw()
|
||||||
|
|
||||||
def get_sessions(self):
|
def get_sessions(self) -> Iterable[core_pb2.SessionSummary]:
|
||||||
try:
|
try:
|
||||||
response = self.app.core.client.get_sessions()
|
response = self.app.core.client.get_sessions()
|
||||||
logging.info("sessions: %s", response)
|
logging.info("sessions: %s", response)
|
||||||
|
@ -40,7 +41,6 @@ class SessionsDialog(Dialog):
|
||||||
def draw_description(self):
|
def draw_description(self):
|
||||||
"""
|
"""
|
||||||
write a short description
|
write a short description
|
||||||
:return: nothing
|
|
||||||
"""
|
"""
|
||||||
label = ttk.Label(
|
label = ttk.Label(
|
||||||
self.top,
|
self.top,
|
||||||
|
@ -129,7 +129,7 @@ class SessionsDialog(Dialog):
|
||||||
self.app.core.create_new_session()
|
self.app.core.create_new_session()
|
||||||
self.destroy()
|
self.destroy()
|
||||||
|
|
||||||
def click_select(self, event):
|
def click_select(self, event: tk.Event):
|
||||||
item = self.tree.selection()
|
item = self.tree.selection()
|
||||||
session_id = int(self.tree.item(item, "text"))
|
session_id = int(self.tree.item(item, "text"))
|
||||||
self.selected = True
|
self.selected = True
|
||||||
|
@ -138,8 +138,6 @@ class SessionsDialog(Dialog):
|
||||||
def click_connect(self):
|
def click_connect(self):
|
||||||
"""
|
"""
|
||||||
if no session is selected yet, create a new one else join that session
|
if no session is selected yet, create a new one else join that session
|
||||||
|
|
||||||
:return: nothing
|
|
||||||
"""
|
"""
|
||||||
if self.selected and self.selected_id is not None:
|
if self.selected and self.selected_id is not None:
|
||||||
self.join_session(self.selected_id)
|
self.join_session(self.selected_id)
|
||||||
|
@ -152,8 +150,6 @@ class SessionsDialog(Dialog):
|
||||||
"""
|
"""
|
||||||
if no session is currently selected create a new session else shut the selected
|
if no session is currently selected create a new session else shut the selected
|
||||||
session down.
|
session down.
|
||||||
|
|
||||||
:return: nothing
|
|
||||||
"""
|
"""
|
||||||
if self.selected and self.selected_id is not None:
|
if self.selected and self.selected_id is not None:
|
||||||
self.shutdown_session(self.selected_id)
|
self.shutdown_session(self.selected_id)
|
||||||
|
@ -162,18 +158,18 @@ class SessionsDialog(Dialog):
|
||||||
else:
|
else:
|
||||||
logging.error("querysessiondrawing.py invalid state")
|
logging.error("querysessiondrawing.py invalid state")
|
||||||
|
|
||||||
def join_session(self, session_id):
|
def join_session(self, session_id: int):
|
||||||
self.app.statusbar.progress_bar.start(5)
|
self.app.statusbar.progress_bar.start(5)
|
||||||
task = BackgroundTask(self.app, self.app.core.join_session, args=(session_id,))
|
task = BackgroundTask(self.app, self.app.core.join_session, args=(session_id,))
|
||||||
task.start()
|
task.start()
|
||||||
self.destroy()
|
self.destroy()
|
||||||
|
|
||||||
def on_selected(self, event):
|
def on_selected(self, event: tk.Event):
|
||||||
item = self.tree.selection()
|
item = self.tree.selection()
|
||||||
sid = int(self.tree.item(item, "text"))
|
sid = int(self.tree.item(item, "text"))
|
||||||
self.join_session(sid)
|
self.join_session(sid)
|
||||||
|
|
||||||
def shutdown_session(self, sid):
|
def shutdown_session(self, sid: int):
|
||||||
self.app.core.stop_session(sid)
|
self.app.core.stop_session(sid)
|
||||||
self.click_new()
|
self.click_new()
|
||||||
self.destroy()
|
self.destroy()
|
||||||
|
|
|
@ -38,8 +38,6 @@ class WlanConfigDialog(Dialog):
|
||||||
def draw_apply_buttons(self):
|
def draw_apply_buttons(self):
|
||||||
"""
|
"""
|
||||||
create node configuration options
|
create node configuration options
|
||||||
|
|
||||||
:return: nothing
|
|
||||||
"""
|
"""
|
||||||
frame = ttk.Frame(self.top)
|
frame = ttk.Frame(self.top)
|
||||||
frame.grid(sticky="ew")
|
frame.grid(sticky="ew")
|
||||||
|
@ -55,8 +53,6 @@ class WlanConfigDialog(Dialog):
|
||||||
def click_apply(self):
|
def click_apply(self):
|
||||||
"""
|
"""
|
||||||
retrieve user's wlan configuration and store the new configuration values
|
retrieve user's wlan configuration and store the new configuration values
|
||||||
|
|
||||||
:return: nothing
|
|
||||||
"""
|
"""
|
||||||
config = self.config_frame.parse_config()
|
config = self.config_frame.parse_config()
|
||||||
self.app.core.wlan_configs[self.node.id] = self.config
|
self.app.core.wlan_configs[self.node.id] = self.config
|
||||||
|
|
|
@ -14,7 +14,14 @@ EDGE_COLOR = "#ff0000"
|
||||||
|
|
||||||
|
|
||||||
class CanvasWirelessEdge:
|
class CanvasWirelessEdge:
|
||||||
def __init__(self, token: Tuple[int, int], position, src: int, dst: int, canvas):
|
def __init__(
|
||||||
|
self,
|
||||||
|
token: Tuple[int, int],
|
||||||
|
position: Tuple[int, int, int, int],
|
||||||
|
src: int,
|
||||||
|
dst: int,
|
||||||
|
canvas,
|
||||||
|
):
|
||||||
self.token = token
|
self.token = token
|
||||||
self.src = src
|
self.src = src
|
||||||
self.dst = dst
|
self.dst = dst
|
||||||
|
@ -35,11 +42,6 @@ class CanvasEdge:
|
||||||
def __init__(self, x1: int, y1: int, x2: int, y2: int, src: int, canvas):
|
def __init__(self, x1: int, y1: int, x2: int, y2: int, src: int, canvas):
|
||||||
"""
|
"""
|
||||||
Create an instance of canvas edge object
|
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 coretk.graph.graph.GraphCanvas canvas: canvas object
|
:param coretk.graph.graph.GraphCanvas canvas: canvas object
|
||||||
"""
|
"""
|
||||||
self.src = src
|
self.src = src
|
||||||
|
@ -67,7 +69,7 @@ class CanvasEdge:
|
||||||
self.link = link
|
self.link = link
|
||||||
self.draw_labels()
|
self.draw_labels()
|
||||||
|
|
||||||
def get_coordinates(self):
|
def get_coordinates(self) -> [int, int, int, int]:
|
||||||
x1, y1, x2, y2 = self.canvas.coords(self.id)
|
x1, y1, x2, y2 = self.canvas.coords(self.id)
|
||||||
v1 = x2 - x1
|
v1 = x2 - x1
|
||||||
v2 = y2 - y1
|
v2 = y2 - y1
|
||||||
|
@ -79,7 +81,7 @@ class CanvasEdge:
|
||||||
y2 = y2 - uy
|
y2 = y2 - uy
|
||||||
return x1, y1, x2, y2
|
return x1, y1, x2, y2
|
||||||
|
|
||||||
def get_midpoint(self):
|
def get_midpoint(self) -> [float, float]:
|
||||||
x1, y1, x2, y2 = self.canvas.coords(self.id)
|
x1, y1, x2, y2 = self.canvas.coords(self.id)
|
||||||
x = (x1 + x2) / 2
|
x = (x1 + x2) / 2
|
||||||
y = (y1 + y2) / 2
|
y = (y1 + y2) / 2
|
||||||
|
@ -119,8 +121,6 @@ class CanvasEdge:
|
||||||
def update_labels(self):
|
def update_labels(self):
|
||||||
"""
|
"""
|
||||||
Move edge labels based on current position.
|
Move edge labels based on current position.
|
||||||
|
|
||||||
:return: nothing
|
|
||||||
"""
|
"""
|
||||||
x1, y1, x2, y2 = self.get_coordinates()
|
x1, y1, x2, y2 = self.get_coordinates()
|
||||||
self.canvas.coords(self.text_src, x1, y1)
|
self.canvas.coords(self.text_src, x1, y1)
|
||||||
|
@ -158,7 +158,7 @@ class CanvasEdge:
|
||||||
self.canvas.tag_raise(self.src)
|
self.canvas.tag_raise(self.src)
|
||||||
self.canvas.tag_raise(self.dst)
|
self.canvas.tag_raise(self.dst)
|
||||||
|
|
||||||
def is_wireless(self):
|
def is_wireless(self) -> [bool, bool]:
|
||||||
src_node = self.canvas.nodes[self.src]
|
src_node = self.canvas.nodes[self.src]
|
||||||
dst_node = self.canvas.nodes[self.dst]
|
dst_node = self.canvas.nodes[self.dst]
|
||||||
src_node_type = src_node.core_node.type
|
src_node_type = src_node.core_node.type
|
||||||
|
@ -184,7 +184,6 @@ class CanvasEdge:
|
||||||
dst_node.add_antenna()
|
dst_node.add_antenna()
|
||||||
elif not is_src_wireless and is_dst_wireless:
|
elif not is_src_wireless and is_dst_wireless:
|
||||||
src_node.add_antenna()
|
src_node.add_antenna()
|
||||||
# TODO: remove this? dont allow linking wireless nodes?
|
|
||||||
else:
|
else:
|
||||||
src_node.add_antenna()
|
src_node.add_antenna()
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
import logging
|
import logging
|
||||||
import tkinter as tk
|
import tkinter as tk
|
||||||
|
from typing import List, Optional
|
||||||
|
|
||||||
from PIL import Image, ImageTk
|
from PIL import Image, ImageTk
|
||||||
|
|
||||||
|
@ -84,13 +85,11 @@ class CanvasGraph(tk.Canvas):
|
||||||
)
|
)
|
||||||
self.configure(scrollregion=self.bbox(tk.ALL))
|
self.configure(scrollregion=self.bbox(tk.ALL))
|
||||||
|
|
||||||
def reset_and_redraw(self, session):
|
def reset_and_redraw(self, session: core_pb2.Session):
|
||||||
"""
|
"""
|
||||||
Reset the private variables CanvasGraph object, redraw nodes given the new grpc
|
Reset the private variables CanvasGraph object, redraw nodes given the new grpc
|
||||||
client.
|
client.
|
||||||
|
|
||||||
:param core.api.grpc.core_pb2.Session session: session to draw
|
:param core.api.grpc.core_pb2.Session session: session to draw
|
||||||
:return: nothing
|
|
||||||
"""
|
"""
|
||||||
# hide context
|
# hide context
|
||||||
self.hide_context()
|
self.hide_context()
|
||||||
|
@ -114,8 +113,6 @@ class CanvasGraph(tk.Canvas):
|
||||||
def setup_bindings(self):
|
def setup_bindings(self):
|
||||||
"""
|
"""
|
||||||
Bind any mouse events or hot keys to the matching action
|
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)
|
||||||
|
@ -135,28 +132,28 @@ class CanvasGraph(tk.Canvas):
|
||||||
self.context.unpost()
|
self.context.unpost()
|
||||||
self.context = None
|
self.context = None
|
||||||
|
|
||||||
def get_actual_coords(self, x, y):
|
def get_actual_coords(self, x: float, y: float) -> [float, float]:
|
||||||
actual_x = (x - self.offset[0]) / self.ratio
|
actual_x = (x - self.offset[0]) / self.ratio
|
||||||
actual_y = (y - self.offset[1]) / self.ratio
|
actual_y = (y - self.offset[1]) / self.ratio
|
||||||
return actual_x, actual_y
|
return actual_x, actual_y
|
||||||
|
|
||||||
def get_scaled_coords(self, x, y):
|
def get_scaled_coords(self, x: float, y: float) -> [float, float]:
|
||||||
scaled_x = (x * self.ratio) + self.offset[0]
|
scaled_x = (x * self.ratio) + self.offset[0]
|
||||||
scaled_y = (y * self.ratio) + self.offset[1]
|
scaled_y = (y * self.ratio) + self.offset[1]
|
||||||
return scaled_x, scaled_y
|
return scaled_x, scaled_y
|
||||||
|
|
||||||
def inside_canvas(self, x, y):
|
def inside_canvas(self, x: float, y: float) -> [bool, bool]:
|
||||||
x1, y1, x2, y2 = self.bbox(self.grid)
|
x1, y1, x2, y2 = self.bbox(self.grid)
|
||||||
valid_x = x1 <= x <= x2
|
valid_x = x1 <= x <= x2
|
||||||
valid_y = y1 <= y <= y2
|
valid_y = y1 <= y <= y2
|
||||||
return valid_x and valid_y
|
return valid_x and valid_y
|
||||||
|
|
||||||
def valid_position(self, x1, y1, x2, y2):
|
def valid_position(self, x1: int, y1: int, x2: int, y2: int) -> [bool, bool]:
|
||||||
valid_topleft = self.inside_canvas(x1, y1)
|
valid_topleft = self.inside_canvas(x1, y1)
|
||||||
valid_bottomright = self.inside_canvas(x2, y2)
|
valid_bottomright = self.inside_canvas(x2, y2)
|
||||||
return valid_topleft and valid_bottomright
|
return valid_topleft and valid_bottomright
|
||||||
|
|
||||||
def set_throughputs(self, throughputs_event):
|
def set_throughputs(self, throughputs_event: core_pb2.ThroughputsEvent):
|
||||||
for interface_throughput in throughputs_event.interface_throughputs:
|
for interface_throughput in throughputs_event.interface_throughputs:
|
||||||
node_id = interface_throughput.node_id
|
node_id = interface_throughput.node_id
|
||||||
interface_id = interface_throughput.interface_id
|
interface_id = interface_throughput.interface_id
|
||||||
|
@ -174,8 +171,6 @@ class CanvasGraph(tk.Canvas):
|
||||||
def draw_grid(self):
|
def draw_grid(self):
|
||||||
"""
|
"""
|
||||||
Create grid.
|
Create grid.
|
||||||
|
|
||||||
:return: nothing
|
|
||||||
"""
|
"""
|
||||||
width, height = self.width_and_height()
|
width, height = self.width_and_height()
|
||||||
width = int(width)
|
width = int(width)
|
||||||
|
@ -187,13 +182,12 @@ class CanvasGraph(tk.Canvas):
|
||||||
self.tag_lower(tags.GRIDLINE)
|
self.tag_lower(tags.GRIDLINE)
|
||||||
self.tag_lower(self.grid)
|
self.tag_lower(self.grid)
|
||||||
|
|
||||||
def add_wireless_edge(self, src, dst):
|
def add_wireless_edge(self, src: CanvasNode, dst: CanvasNode):
|
||||||
"""
|
"""
|
||||||
add a wireless edge between 2 canvas nodes
|
add a wireless edge between 2 canvas nodes
|
||||||
|
|
||||||
:param CanvasNode src: source node
|
:param CanvasNode src: source node
|
||||||
:param CanvasNode dst: destination node
|
:param CanvasNode dst: destination node
|
||||||
:return: nothing
|
|
||||||
"""
|
"""
|
||||||
token = tuple(sorted((src.id, dst.id)))
|
token = tuple(sorted((src.id, dst.id)))
|
||||||
x1, y1 = self.coords(src.id)
|
x1, y1 = self.coords(src.id)
|
||||||
|
@ -206,18 +200,16 @@ class CanvasGraph(tk.Canvas):
|
||||||
self.tag_raise(src.id)
|
self.tag_raise(src.id)
|
||||||
self.tag_raise(dst.id)
|
self.tag_raise(dst.id)
|
||||||
|
|
||||||
def delete_wireless_edge(self, src, dst):
|
def delete_wireless_edge(self, src: CanvasNode, dst: CanvasNode):
|
||||||
token = tuple(sorted((src.id, dst.id)))
|
token = tuple(sorted((src.id, dst.id)))
|
||||||
edge = self.wireless_edges.pop(token)
|
edge = self.wireless_edges.pop(token)
|
||||||
edge.delete()
|
edge.delete()
|
||||||
src.wireless_edges.remove(edge)
|
src.wireless_edges.remove(edge)
|
||||||
dst.wireless_edges.remove(edge)
|
dst.wireless_edges.remove(edge)
|
||||||
|
|
||||||
def draw_session(self, session):
|
def draw_session(self, session: core_pb2.Session):
|
||||||
"""
|
"""
|
||||||
Draw existing session.
|
Draw existing session.
|
||||||
|
|
||||||
:return: nothing
|
|
||||||
"""
|
"""
|
||||||
# draw existing nodes
|
# draw existing nodes
|
||||||
for core_node in session.nodes:
|
for core_node in session.nodes:
|
||||||
|
@ -296,25 +288,17 @@ class CanvasGraph(tk.Canvas):
|
||||||
for edge in self.edges.values():
|
for edge in self.edges.values():
|
||||||
edge.reset()
|
edge.reset()
|
||||||
|
|
||||||
def canvas_xy(self, event):
|
def canvas_xy(self, event: tk.Event) -> [float, float]:
|
||||||
"""
|
"""
|
||||||
Convert window coordinate to canvas coordinate
|
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: tk.Event) -> int:
|
||||||
"""
|
"""
|
||||||
Retrieve the item id that is on the mouse position
|
Retrieve the item id that is on the mouse position
|
||||||
|
|
||||||
:param event: mouse event
|
|
||||||
:rtype: int
|
|
||||||
:return: the item that the mouse point to
|
|
||||||
"""
|
"""
|
||||||
x, y = self.canvas_xy(event)
|
x, y = self.canvas_xy(event)
|
||||||
overlapping = self.find_overlapping(x, y, x, y)
|
overlapping = self.find_overlapping(x, y, x, y)
|
||||||
|
@ -332,7 +316,7 @@ class CanvasGraph(tk.Canvas):
|
||||||
|
|
||||||
return selected
|
return selected
|
||||||
|
|
||||||
def click_release(self, event):
|
def click_release(self, event: tk.Event):
|
||||||
"""
|
"""
|
||||||
Draw a node or finish drawing an edge according to the current graph mode
|
Draw a node or finish drawing an edge according to the current graph mode
|
||||||
|
|
||||||
|
@ -380,7 +364,7 @@ class CanvasGraph(tk.Canvas):
|
||||||
self.mode = GraphMode.NODE
|
self.mode = GraphMode.NODE
|
||||||
self.selected = None
|
self.selected = None
|
||||||
|
|
||||||
def handle_edge_release(self, event):
|
def handle_edge_release(self, event: tk.Event):
|
||||||
edge = self.drawing_edge
|
edge = self.drawing_edge
|
||||||
self.drawing_edge = None
|
self.drawing_edge = None
|
||||||
|
|
||||||
|
@ -417,7 +401,7 @@ class CanvasGraph(tk.Canvas):
|
||||||
node_dst.edges.add(edge)
|
node_dst.edges.add(edge)
|
||||||
self.core.create_link(edge, node_src, node_dst)
|
self.core.create_link(edge, node_src, node_dst)
|
||||||
|
|
||||||
def select_object(self, object_id, choose_multiple=False):
|
def select_object(self, object_id: int, choose_multiple: Optional[bool] = False):
|
||||||
"""
|
"""
|
||||||
create a bounding box when a node is selected
|
create a bounding box when a node is selected
|
||||||
"""
|
"""
|
||||||
|
@ -441,19 +425,17 @@ class CanvasGraph(tk.Canvas):
|
||||||
def clear_selection(self):
|
def clear_selection(self):
|
||||||
"""
|
"""
|
||||||
Clear current selection boxes.
|
Clear current selection boxes.
|
||||||
|
|
||||||
:return: nothing
|
|
||||||
"""
|
"""
|
||||||
for _id in self.selection.values():
|
for _id in self.selection.values():
|
||||||
self.delete(_id)
|
self.delete(_id)
|
||||||
self.selection.clear()
|
self.selection.clear()
|
||||||
|
|
||||||
def move_selection(self, object_id, x_offset, y_offset):
|
def move_selection(self, object_id: int, x_offset: float, y_offset: float):
|
||||||
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, x_offset, y_offset)
|
self.move(select_id, x_offset, y_offset)
|
||||||
|
|
||||||
def delete_selection_objects(self):
|
def delete_selection_objects(self) -> List[CanvasNode]:
|
||||||
edges = set()
|
edges = set()
|
||||||
nodes = []
|
nodes = []
|
||||||
for object_id in self.selection:
|
for object_id in self.selection:
|
||||||
|
@ -499,7 +481,7 @@ class CanvasGraph(tk.Canvas):
|
||||||
self.selection.clear()
|
self.selection.clear()
|
||||||
return nodes
|
return nodes
|
||||||
|
|
||||||
def zoom(self, event, factor=None):
|
def zoom(self, event: tk.Event, factor: Optional[float] = None):
|
||||||
if not factor:
|
if not factor:
|
||||||
factor = ZOOM_IN if event.delta > 0 else ZOOM_OUT
|
factor = ZOOM_IN if event.delta > 0 else ZOOM_OUT
|
||||||
event.x, event.y = self.canvasx(event.x), self.canvasy(event.y)
|
event.x, event.y = self.canvasx(event.x), self.canvasy(event.y)
|
||||||
|
@ -517,12 +499,9 @@ class CanvasGraph(tk.Canvas):
|
||||||
if self.wallpaper:
|
if self.wallpaper:
|
||||||
self.redraw_wallpaper()
|
self.redraw_wallpaper()
|
||||||
|
|
||||||
def click_press(self, event):
|
def click_press(self, event: tk.Event):
|
||||||
"""
|
"""
|
||||||
Start drawing an edge if mouse click is on a node
|
Start drawing an edge if mouse click is on a node
|
||||||
|
|
||||||
:param event: mouse event
|
|
||||||
:return: nothing
|
|
||||||
"""
|
"""
|
||||||
x, y = self.canvas_xy(event)
|
x, y = self.canvas_xy(event)
|
||||||
if not self.inside_canvas(x, y):
|
if not self.inside_canvas(x, y):
|
||||||
|
@ -581,7 +560,7 @@ class CanvasGraph(tk.Canvas):
|
||||||
self.select_box = shape
|
self.select_box = shape
|
||||||
self.clear_selection()
|
self.clear_selection()
|
||||||
|
|
||||||
def ctrl_click(self, event):
|
def ctrl_click(self, event: tk.Event):
|
||||||
# update cursor location
|
# update cursor location
|
||||||
x, y = self.canvas_xy(event)
|
x, y = self.canvas_xy(event)
|
||||||
if not self.inside_canvas(x, y):
|
if not self.inside_canvas(x, y):
|
||||||
|
@ -599,12 +578,9 @@ class CanvasGraph(tk.Canvas):
|
||||||
):
|
):
|
||||||
self.select_object(selected, choose_multiple=True)
|
self.select_object(selected, choose_multiple=True)
|
||||||
|
|
||||||
def click_motion(self, event):
|
def click_motion(self, event: tk.Event):
|
||||||
"""
|
"""
|
||||||
Redraw drawing edge according to the current position of the mouse
|
Redraw drawing edge according to the current position of the mouse
|
||||||
|
|
||||||
:param event: mouse event
|
|
||||||
:return: nothing
|
|
||||||
"""
|
"""
|
||||||
x, y = self.canvas_xy(event)
|
x, y = self.canvas_xy(event)
|
||||||
if not self.inside_canvas(x, y):
|
if not self.inside_canvas(x, y):
|
||||||
|
@ -658,7 +634,7 @@ class CanvasGraph(tk.Canvas):
|
||||||
if self.select_box and self.mode == GraphMode.SELECT:
|
if self.select_box and self.mode == GraphMode.SELECT:
|
||||||
self.select_box.shape_motion(x, y)
|
self.select_box.shape_motion(x, y)
|
||||||
|
|
||||||
def click_context(self, event):
|
def click_context(self, event: tk.Event):
|
||||||
logging.info("context event: %s", self.context)
|
logging.info("context event: %s", self.context)
|
||||||
if not self.context:
|
if not self.context:
|
||||||
selected = self.get_selected(event)
|
selected = self.get_selected(event)
|
||||||
|
@ -670,24 +646,22 @@ class CanvasGraph(tk.Canvas):
|
||||||
else:
|
else:
|
||||||
self.hide_context()
|
self.hide_context()
|
||||||
|
|
||||||
def press_delete(self, event):
|
def press_delete(self, event: tk.Event):
|
||||||
"""
|
"""
|
||||||
delete selected nodes and any data that relates to it
|
delete selected nodes and any data that relates to it
|
||||||
:param event:
|
|
||||||
:return:
|
|
||||||
"""
|
"""
|
||||||
logging.debug("press delete key")
|
logging.debug("press delete key")
|
||||||
nodes = self.delete_selection_objects()
|
nodes = self.delete_selection_objects()
|
||||||
self.core.delete_graph_nodes(nodes)
|
self.core.delete_graph_nodes(nodes)
|
||||||
|
|
||||||
def double_click(self, event):
|
def double_click(self, event: tk.Event):
|
||||||
selected = self.get_selected(event)
|
selected = self.get_selected(event)
|
||||||
if selected is not None and selected in self.shapes:
|
if selected is not None and selected in self.shapes:
|
||||||
shape = self.shapes[selected]
|
shape = self.shapes[selected]
|
||||||
dialog = ShapeDialog(self.app, self.app, shape)
|
dialog = ShapeDialog(self.app, self.app, shape)
|
||||||
dialog.show()
|
dialog.show()
|
||||||
|
|
||||||
def add_node(self, x, y):
|
def add_node(self, x: float, y: float) -> CanvasNode:
|
||||||
if self.selected is None or self.selected in self.shapes:
|
if self.selected is None or self.selected in self.shapes:
|
||||||
actual_x, actual_y = self.get_actual_coords(x, y)
|
actual_x, actual_y = self.get_actual_coords(x, y)
|
||||||
core_node = self.core.create_node(
|
core_node = self.core.create_node(
|
||||||
|
@ -701,26 +675,28 @@ class CanvasGraph(tk.Canvas):
|
||||||
def width_and_height(self):
|
def width_and_height(self):
|
||||||
"""
|
"""
|
||||||
retrieve canvas width and height in pixels
|
retrieve canvas width and height in pixels
|
||||||
|
|
||||||
:return: nothing
|
|
||||||
"""
|
"""
|
||||||
x0, y0, x1, y1 = self.coords(self.grid)
|
x0, y0, x1, y1 = self.coords(self.grid)
|
||||||
canvas_w = abs(x0 - x1)
|
canvas_w = abs(x0 - x1)
|
||||||
canvas_h = abs(y0 - y1)
|
canvas_h = abs(y0 - y1)
|
||||||
return canvas_w, canvas_h
|
return canvas_w, canvas_h
|
||||||
|
|
||||||
def get_wallpaper_image(self):
|
def get_wallpaper_image(self) -> Image.Image:
|
||||||
width = int(self.wallpaper.width * self.ratio)
|
width = int(self.wallpaper.width * self.ratio)
|
||||||
height = int(self.wallpaper.height * self.ratio)
|
height = int(self.wallpaper.height * self.ratio)
|
||||||
image = self.wallpaper.resize((width, height), Image.ANTIALIAS)
|
image = self.wallpaper.resize((width, height), Image.ANTIALIAS)
|
||||||
return image
|
return image
|
||||||
|
|
||||||
def draw_wallpaper(self, image, x=None, y=None):
|
def draw_wallpaper(
|
||||||
|
self,
|
||||||
|
image: ImageTk.PhotoImage,
|
||||||
|
x: Optional[float] = None,
|
||||||
|
y: Optional[float] = None,
|
||||||
|
):
|
||||||
if x is None and y is None:
|
if x is None and y is None:
|
||||||
x1, y1, x2, y2 = self.bbox(self.grid)
|
x1, y1, x2, y2 = self.bbox(self.grid)
|
||||||
x = (x1 + x2) / 2
|
x = (x1 + x2) / 2
|
||||||
y = (y1 + y2) / 2
|
y = (y1 + y2) / 2
|
||||||
|
|
||||||
self.wallpaper_id = self.create_image((x, y), image=image, tags=tags.WALLPAPER)
|
self.wallpaper_id = self.create_image((x, y), image=image, tags=tags.WALLPAPER)
|
||||||
self.wallpaper_drawn = image
|
self.wallpaper_drawn = image
|
||||||
|
|
||||||
|
@ -748,8 +724,6 @@ class CanvasGraph(tk.Canvas):
|
||||||
def wallpaper_center(self):
|
def wallpaper_center(self):
|
||||||
"""
|
"""
|
||||||
place the image at the center of canvas
|
place the image at the center of canvas
|
||||||
|
|
||||||
:return: nothing
|
|
||||||
"""
|
"""
|
||||||
self.delete(self.wallpaper_id)
|
self.delete(self.wallpaper_id)
|
||||||
|
|
||||||
|
@ -773,8 +747,6 @@ class CanvasGraph(tk.Canvas):
|
||||||
def wallpaper_scaled(self):
|
def wallpaper_scaled(self):
|
||||||
"""
|
"""
|
||||||
scale image based on canvas dimension
|
scale image based on canvas dimension
|
||||||
|
|
||||||
:return: nothing
|
|
||||||
"""
|
"""
|
||||||
self.delete(self.wallpaper_id)
|
self.delete(self.wallpaper_id)
|
||||||
canvas_w, canvas_h = self.width_and_height()
|
canvas_w, canvas_h = self.width_and_height()
|
||||||
|
@ -788,7 +760,7 @@ class CanvasGraph(tk.Canvas):
|
||||||
self.redraw_canvas((image.width(), image.height()))
|
self.redraw_canvas((image.width(), image.height()))
|
||||||
self.draw_wallpaper(image)
|
self.draw_wallpaper(image)
|
||||||
|
|
||||||
def redraw_canvas(self, dimensions=None):
|
def redraw_canvas(self, dimensions: Optional[List[int]] = None):
|
||||||
logging.info("redrawing canvas to dimensions: %s", dimensions)
|
logging.info("redrawing canvas to dimensions: %s", dimensions)
|
||||||
|
|
||||||
# reset scale and move back to original position
|
# reset scale and move back to original position
|
||||||
|
@ -836,7 +808,7 @@ class CanvasGraph(tk.Canvas):
|
||||||
else:
|
else:
|
||||||
self.itemconfig(tags.GRIDLINE, state=tk.HIDDEN)
|
self.itemconfig(tags.GRIDLINE, state=tk.HIDDEN)
|
||||||
|
|
||||||
def set_wallpaper(self, filename):
|
def set_wallpaper(self, filename: str):
|
||||||
logging.info("setting wallpaper: %s", filename)
|
logging.info("setting wallpaper: %s", filename)
|
||||||
if filename:
|
if filename:
|
||||||
img = Image.open(filename)
|
img = Image.open(filename)
|
||||||
|
@ -849,16 +821,12 @@ class CanvasGraph(tk.Canvas):
|
||||||
self.wallpaper = None
|
self.wallpaper = None
|
||||||
self.wallpaper_file = None
|
self.wallpaper_file = None
|
||||||
|
|
||||||
def is_selection_mode(self):
|
def is_selection_mode(self) -> bool:
|
||||||
return self.mode == GraphMode.SELECT
|
return self.mode == GraphMode.SELECT
|
||||||
|
|
||||||
def create_edge(self, source, dest):
|
def create_edge(self, source: CanvasNode, dest: CanvasNode):
|
||||||
"""
|
"""
|
||||||
create an edge between source node and destination node
|
create an edge between source node and destination node
|
||||||
|
|
||||||
:param CanvasNode source: source node
|
|
||||||
:param CanvasNode dest: destination node
|
|
||||||
:return: nothing
|
|
||||||
"""
|
"""
|
||||||
if (source.id, dest.id) not in self.edges:
|
if (source.id, dest.id) not in self.edges:
|
||||||
pos0 = source.core_node.position
|
pos0 = source.core_node.position
|
||||||
|
|
|
@ -20,7 +20,7 @@ NODE_TEXT_OFFSET = 5
|
||||||
|
|
||||||
|
|
||||||
class CanvasNode:
|
class CanvasNode:
|
||||||
def __init__(self, app, x: int, y: int, core_node: core_pb2.Node, image):
|
def __init__(self, app, x: float, y: float, core_node: core_pb2.Node, image):
|
||||||
self.app = app
|
self.app = app
|
||||||
self.canvas = app.canvas
|
self.canvas = app.canvas
|
||||||
self.image = image
|
self.image = image
|
||||||
|
@ -70,8 +70,6 @@ class CanvasNode:
|
||||||
def delete_antenna(self):
|
def delete_antenna(self):
|
||||||
"""
|
"""
|
||||||
delete one antenna
|
delete one antenna
|
||||||
|
|
||||||
:return: nothing
|
|
||||||
"""
|
"""
|
||||||
if self.antennae:
|
if self.antennae:
|
||||||
antenna_id = self.antennae.pop()
|
antenna_id = self.antennae.pop()
|
||||||
|
@ -80,8 +78,6 @@ class CanvasNode:
|
||||||
def delete_antennae(self):
|
def delete_antennae(self):
|
||||||
"""
|
"""
|
||||||
delete all antennas
|
delete all antennas
|
||||||
|
|
||||||
:return: nothing
|
|
||||||
"""
|
"""
|
||||||
for antenna_id in self.antennae:
|
for antenna_id in self.antennae:
|
||||||
self.canvas.delete(antenna_id)
|
self.canvas.delete(antenna_id)
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
import logging
|
import logging
|
||||||
|
from typing import List, Optional, Union
|
||||||
|
|
||||||
from core.gui.dialogs.shapemod import ShapeDialog
|
from core.gui.dialogs.shapemod import ShapeDialog
|
||||||
from core.gui.graph import tags
|
from core.gui.graph import tags
|
||||||
|
@ -8,16 +9,16 @@ from core.gui.graph.shapeutils import ShapeType
|
||||||
class AnnotationData:
|
class AnnotationData:
|
||||||
def __init__(
|
def __init__(
|
||||||
self,
|
self,
|
||||||
text="",
|
text: Optional[str] = "",
|
||||||
font="Arial",
|
font: Optional[str] = "Arial",
|
||||||
font_size=12,
|
font_size: Optional[int] = 12,
|
||||||
text_color="#000000",
|
text_color: Optional[str] = "#000000",
|
||||||
fill_color="",
|
fill_color: Optional[str] = "",
|
||||||
border_color="#000000",
|
border_color: Optional[str] = "#000000",
|
||||||
border_width=1,
|
border_width: Optional[int] = 1,
|
||||||
bold=False,
|
bold: Optional[bool] = False,
|
||||||
italic=False,
|
italic: Optional[bool] = False,
|
||||||
underline=False,
|
underline: Optional[bool] = False,
|
||||||
):
|
):
|
||||||
self.text = text
|
self.text = text
|
||||||
self.font = font
|
self.font = font
|
||||||
|
@ -99,7 +100,7 @@ class Shape:
|
||||||
logging.error("unknown shape type: %s", self.shape_type)
|
logging.error("unknown shape type: %s", self.shape_type)
|
||||||
self.created = True
|
self.created = True
|
||||||
|
|
||||||
def get_font(self):
|
def get_font(self) -> List[Union[int, str]]:
|
||||||
font = [self.shape_data.font, self.shape_data.font_size]
|
font = [self.shape_data.font, self.shape_data.font_size]
|
||||||
if self.shape_data.bold:
|
if self.shape_data.bold:
|
||||||
font.append("bold")
|
font.append("bold")
|
||||||
|
@ -123,10 +124,10 @@ class Shape:
|
||||||
font=font,
|
font=font,
|
||||||
)
|
)
|
||||||
|
|
||||||
def shape_motion(self, x1: int, y1: int):
|
def shape_motion(self, x1: float, y1: float):
|
||||||
self.canvas.coords(self.id, self.x1, self.y1, x1, y1)
|
self.canvas.coords(self.id, self.x1, self.y1, x1, y1)
|
||||||
|
|
||||||
def shape_complete(self, x, y):
|
def shape_complete(self, x: float, y: float):
|
||||||
for component in tags.ABOVE_SHAPE:
|
for component in tags.ABOVE_SHAPE:
|
||||||
self.canvas.tag_raise(component)
|
self.canvas.tag_raise(component)
|
||||||
s = ShapeDialog(self.app, self.app, self)
|
s = ShapeDialog(self.app, self.app, self)
|
||||||
|
@ -135,7 +136,7 @@ class Shape:
|
||||||
def disappear(self):
|
def disappear(self):
|
||||||
self.canvas.delete(self.id)
|
self.canvas.delete(self.id)
|
||||||
|
|
||||||
def motion(self, x_offset: int, y_offset: int):
|
def motion(self, x_offset: float, y_offset: float):
|
||||||
original_position = self.canvas.coords(self.id)
|
original_position = self.canvas.coords(self.id)
|
||||||
self.canvas.move(self.id, x_offset, y_offset)
|
self.canvas.move(self.id, x_offset, y_offset)
|
||||||
coords = self.canvas.coords(self.id)
|
coords = self.canvas.coords(self.id)
|
||||||
|
|
|
@ -11,13 +11,13 @@ class ShapeType(enum.Enum):
|
||||||
SHAPES = {ShapeType.OVAL, ShapeType.RECTANGLE}
|
SHAPES = {ShapeType.OVAL, ShapeType.RECTANGLE}
|
||||||
|
|
||||||
|
|
||||||
def is_draw_shape(shape_type):
|
def is_draw_shape(shape_type: ShapeType) -> bool:
|
||||||
return shape_type in SHAPES
|
return shape_type in SHAPES
|
||||||
|
|
||||||
|
|
||||||
def is_shape_text(shape_type):
|
def is_shape_text(shape_type: ShapeType) -> bool:
|
||||||
return shape_type == ShapeType.TEXT
|
return shape_type == ShapeType.TEXT
|
||||||
|
|
||||||
|
|
||||||
def is_marker(shape_type):
|
def is_marker(shape_type: ShapeType) -> bool:
|
||||||
return shape_type == ShapeType.MARKER
|
return shape_type == ShapeType.MARKER
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
import tkinter as tk
|
import tkinter as tk
|
||||||
from tkinter import ttk
|
from tkinter import ttk
|
||||||
|
from typing import Optional
|
||||||
|
|
||||||
from core.gui.themes import Styles
|
from core.gui.themes import Styles
|
||||||
|
|
||||||
|
@ -30,10 +31,10 @@ class CanvasTooltip:
|
||||||
self.id = None
|
self.id = None
|
||||||
self.tw = None
|
self.tw = None
|
||||||
|
|
||||||
def on_enter(self, event=None):
|
def on_enter(self, event: Optional[tk.Event] = None):
|
||||||
self.schedule()
|
self.schedule()
|
||||||
|
|
||||||
def on_leave(self, event=None):
|
def on_leave(self, event: Optional[tk.Event] = None):
|
||||||
self.unschedule()
|
self.unschedule()
|
||||||
self.hide()
|
self.hide()
|
||||||
|
|
||||||
|
@ -47,7 +48,7 @@ class CanvasTooltip:
|
||||||
if id_:
|
if id_:
|
||||||
self.canvas.after_cancel(id_)
|
self.canvas.after_cancel(id_)
|
||||||
|
|
||||||
def show(self, event=None):
|
def show(self, event: Optional[tk.Event] = None):
|
||||||
def tip_pos_calculator(canvas, label, *, tip_delta=(10, 5), pad=(5, 3, 5, 3)):
|
def tip_pos_calculator(canvas, label, *, tip_delta=(10, 5), pad=(5, 3, 5, 3)):
|
||||||
c = canvas
|
c = canvas
|
||||||
s_width, s_height = c.winfo_screenwidth(), c.winfo_screenheight()
|
s_width, s_height = c.winfo_screenwidth(), c.winfo_screenheight()
|
||||||
|
|
|
@ -1,8 +1,10 @@
|
||||||
import logging
|
import logging
|
||||||
import random
|
import random
|
||||||
|
from typing import Optional, Set
|
||||||
|
|
||||||
from netaddr import IPNetwork
|
from netaddr import IPNetwork
|
||||||
|
|
||||||
|
from core.gui.graph.node import CanvasNode
|
||||||
from core.gui.nodeutils import NodeUtils
|
from core.gui.nodeutils import NodeUtils
|
||||||
|
|
||||||
|
|
||||||
|
@ -11,7 +13,9 @@ def random_mac():
|
||||||
|
|
||||||
|
|
||||||
class InterfaceManager:
|
class InterfaceManager:
|
||||||
def __init__(self, app, address="10.0.0.0", mask=24):
|
def __init__(
|
||||||
|
self, app, address: Optional[str] = "10.0.0.0", mask: Optional[int] = 24
|
||||||
|
):
|
||||||
self.app = app
|
self.app = app
|
||||||
self.mask = mask
|
self.mask = mask
|
||||||
self.base_prefix = max(self.mask - 8, 0)
|
self.base_prefix = max(self.mask - 8, 0)
|
||||||
|
@ -38,7 +42,7 @@ class InterfaceManager:
|
||||||
def reset(self):
|
def reset(self):
|
||||||
self.current_subnet = None
|
self.current_subnet = None
|
||||||
|
|
||||||
def get_ips(self, node_id):
|
def get_ips(self, node_id: int):
|
||||||
ip4 = self.current_subnet[node_id]
|
ip4 = self.current_subnet[node_id]
|
||||||
ip6 = ip4.ipv6()
|
ip6 = ip4.ipv6()
|
||||||
prefix = self.current_subnet.prefixlen
|
prefix = self.current_subnet.prefixlen
|
||||||
|
@ -48,7 +52,9 @@ class InterfaceManager:
|
||||||
def get_subnet(cls, interface):
|
def get_subnet(cls, interface):
|
||||||
return IPNetwork(f"{interface.ip4}/{interface.ip4mask}").cidr
|
return IPNetwork(f"{interface.ip4}/{interface.ip4mask}").cidr
|
||||||
|
|
||||||
def determine_subnet(self, canvas_src_node, canvas_dst_node):
|
def determine_subnet(
|
||||||
|
self, canvas_src_node: CanvasNode, canvas_dst_node: CanvasNode
|
||||||
|
):
|
||||||
src_node = canvas_src_node.core_node
|
src_node = canvas_src_node.core_node
|
||||||
dst_node = canvas_dst_node.core_node
|
dst_node = canvas_dst_node.core_node
|
||||||
is_src_container = NodeUtils.is_container_node(src_node.type)
|
is_src_container = NodeUtils.is_container_node(src_node.type)
|
||||||
|
@ -70,7 +76,7 @@ class InterfaceManager:
|
||||||
else:
|
else:
|
||||||
logging.info("ignoring subnet change for link between network nodes")
|
logging.info("ignoring subnet change for link between network nodes")
|
||||||
|
|
||||||
def find_subnet(self, canvas_node, visited=None):
|
def find_subnet(self, canvas_node: CanvasNode, visited: Optional[Set[int]] = None):
|
||||||
logging.info("finding subnet for node: %s", canvas_node.core_node.name)
|
logging.info("finding subnet for node: %s", canvas_node.core_node.name)
|
||||||
canvas = self.app.canvas
|
canvas = self.app.canvas
|
||||||
cidr = None
|
cidr = None
|
||||||
|
|
|
@ -32,14 +32,14 @@ class MenuAction:
|
||||||
self.app = app
|
self.app = app
|
||||||
self.canvas = app.canvas
|
self.canvas = app.canvas
|
||||||
|
|
||||||
def cleanup_old_session(self, quitapp: bool = False):
|
def cleanup_old_session(self, quitapp: Optional[bool] = False):
|
||||||
logging.info("cleaning up old session")
|
logging.info("cleaning up old session")
|
||||||
self.app.core.stop_session()
|
self.app.core.stop_session()
|
||||||
self.app.core.delete_session()
|
self.app.core.delete_session()
|
||||||
# if quitapp:
|
# if quitapp:
|
||||||
# self.app.quit()
|
# self.app.quit()
|
||||||
|
|
||||||
def prompt_save_running_session(self, quitapp: bool = False):
|
def prompt_save_running_session(self, quitapp: Optional[bool] = False):
|
||||||
"""
|
"""
|
||||||
Prompt use to stop running session before application is closed
|
Prompt use to stop running session before application is closed
|
||||||
|
|
||||||
|
|
|
@ -13,10 +13,6 @@ class Menubar(tk.Menu):
|
||||||
def __init__(self, master, app, cnf={}, **kwargs):
|
def __init__(self, master, app, cnf={}, **kwargs):
|
||||||
"""
|
"""
|
||||||
Create a CoreMenubar instance
|
Create a CoreMenubar instance
|
||||||
|
|
||||||
:param master:
|
|
||||||
:param tkinter.Menu menubar: menubar object
|
|
||||||
:param coretk.app.Application app: application object
|
|
||||||
"""
|
"""
|
||||||
super().__init__(master, cnf, **kwargs)
|
super().__init__(master, cnf, **kwargs)
|
||||||
self.master.config(menu=self)
|
self.master.config(menu=self)
|
||||||
|
@ -27,8 +23,6 @@ class Menubar(tk.Menu):
|
||||||
def draw(self):
|
def draw(self):
|
||||||
"""
|
"""
|
||||||
Create core menubar and bind the hot keys to their matching command
|
Create core menubar and bind the hot keys to their matching command
|
||||||
|
|
||||||
:return: nothing
|
|
||||||
"""
|
"""
|
||||||
self.draw_file_menu()
|
self.draw_file_menu()
|
||||||
self.draw_edit_menu()
|
self.draw_edit_menu()
|
||||||
|
@ -42,8 +36,6 @@ class Menubar(tk.Menu):
|
||||||
def draw_file_menu(self):
|
def draw_file_menu(self):
|
||||||
"""
|
"""
|
||||||
Create file menu
|
Create file menu
|
||||||
|
|
||||||
:return: nothing
|
|
||||||
"""
|
"""
|
||||||
menu = tk.Menu(self)
|
menu = tk.Menu(self)
|
||||||
menu.add_command(
|
menu.add_command(
|
||||||
|
@ -81,8 +73,6 @@ class Menubar(tk.Menu):
|
||||||
def draw_edit_menu(self):
|
def draw_edit_menu(self):
|
||||||
"""
|
"""
|
||||||
Create edit menu
|
Create edit menu
|
||||||
|
|
||||||
:return: nothing
|
|
||||||
"""
|
"""
|
||||||
menu = tk.Menu(self)
|
menu = tk.Menu(self)
|
||||||
menu.add_command(label="Preferences", command=self.menuaction.gui_preferences)
|
menu.add_command(label="Preferences", command=self.menuaction.gui_preferences)
|
||||||
|
@ -112,8 +102,6 @@ class Menubar(tk.Menu):
|
||||||
def draw_canvas_menu(self):
|
def draw_canvas_menu(self):
|
||||||
"""
|
"""
|
||||||
Create canvas menu
|
Create canvas menu
|
||||||
|
|
||||||
:return: nothing
|
|
||||||
"""
|
"""
|
||||||
menu = tk.Menu(self)
|
menu = tk.Menu(self)
|
||||||
menu.add_command(
|
menu.add_command(
|
||||||
|
@ -136,8 +124,6 @@ class Menubar(tk.Menu):
|
||||||
def draw_view_menu(self):
|
def draw_view_menu(self):
|
||||||
"""
|
"""
|
||||||
Create view menu
|
Create view menu
|
||||||
|
|
||||||
:return: nothing
|
|
||||||
"""
|
"""
|
||||||
view_menu = tk.Menu(self)
|
view_menu = tk.Menu(self)
|
||||||
self.create_show_menu(view_menu)
|
self.create_show_menu(view_menu)
|
||||||
|
@ -152,9 +138,6 @@ class Menubar(tk.Menu):
|
||||||
def create_show_menu(self, view_menu: tk.Menu):
|
def create_show_menu(self, view_menu: tk.Menu):
|
||||||
"""
|
"""
|
||||||
Create the menu items in View/Show
|
Create the menu items in View/Show
|
||||||
|
|
||||||
:param tkinter.Menu view_menu: the view menu
|
|
||||||
:return: nothing
|
|
||||||
"""
|
"""
|
||||||
menu = tk.Menu(view_menu)
|
menu = tk.Menu(view_menu)
|
||||||
menu.add_command(label="All", state=tk.DISABLED)
|
menu.add_command(label="All", state=tk.DISABLED)
|
||||||
|
@ -172,9 +155,6 @@ class Menubar(tk.Menu):
|
||||||
def create_experimental_menu(self, tools_menu: tk.Menu):
|
def create_experimental_menu(self, tools_menu: tk.Menu):
|
||||||
"""
|
"""
|
||||||
Create experimental menu item and the sub menu items inside
|
Create experimental menu item and the sub menu items inside
|
||||||
|
|
||||||
:param tkinter.Menu tools_menu: tools menu
|
|
||||||
:return: nothing
|
|
||||||
"""
|
"""
|
||||||
menu = tk.Menu(tools_menu)
|
menu = tk.Menu(tools_menu)
|
||||||
menu.add_command(label="Plugins...", state=tk.DISABLED)
|
menu.add_command(label="Plugins...", state=tk.DISABLED)
|
||||||
|
@ -185,9 +165,6 @@ class Menubar(tk.Menu):
|
||||||
def create_random_menu(self, topology_generator_menu: tk.Menu):
|
def create_random_menu(self, topology_generator_menu: tk.Menu):
|
||||||
"""
|
"""
|
||||||
Create random menu item and the sub menu items inside
|
Create random menu item and the sub menu items inside
|
||||||
|
|
||||||
:param tkinter.Menu topology_generator_menu: topology generator menu
|
|
||||||
:return: nothing
|
|
||||||
"""
|
"""
|
||||||
menu = tk.Menu(topology_generator_menu)
|
menu = tk.Menu(topology_generator_menu)
|
||||||
# list of number of random nodes to create
|
# list of number of random nodes to create
|
||||||
|
@ -200,9 +177,6 @@ class Menubar(tk.Menu):
|
||||||
def create_grid_menu(self, topology_generator_menu: tk.Menu):
|
def create_grid_menu(self, topology_generator_menu: tk.Menu):
|
||||||
"""
|
"""
|
||||||
Create grid menu item and the sub menu items inside
|
Create grid menu item and the sub menu items inside
|
||||||
|
|
||||||
:param tkinter.Menu topology_generator_menu: topology_generator_menu
|
|
||||||
:return: nothing
|
|
||||||
"""
|
"""
|
||||||
menu = tk.Menu(topology_generator_menu)
|
menu = tk.Menu(topology_generator_menu)
|
||||||
# list of number of nodes to create
|
# list of number of nodes to create
|
||||||
|
@ -215,9 +189,6 @@ class Menubar(tk.Menu):
|
||||||
def create_connected_grid_menu(self, topology_generator_menu: tk.Menu):
|
def create_connected_grid_menu(self, topology_generator_menu: tk.Menu):
|
||||||
"""
|
"""
|
||||||
Create connected grid menu items and the sub menu items inside
|
Create connected grid menu items and the sub menu items inside
|
||||||
|
|
||||||
:param tkinter.Menu topology_generator_menu: topology generator menu
|
|
||||||
:return: nothing
|
|
||||||
"""
|
"""
|
||||||
menu = tk.Menu(topology_generator_menu)
|
menu = tk.Menu(topology_generator_menu)
|
||||||
for i in range(1, 11, 1):
|
for i in range(1, 11, 1):
|
||||||
|
@ -232,9 +203,6 @@ class Menubar(tk.Menu):
|
||||||
def create_chain_menu(self, topology_generator_menu: tk.Menu):
|
def create_chain_menu(self, topology_generator_menu: tk.Menu):
|
||||||
"""
|
"""
|
||||||
Create chain menu item and the sub menu items inside
|
Create chain menu item and the sub menu items inside
|
||||||
|
|
||||||
:param tkinter.Menu topology_generator_menu: topology generator menu
|
|
||||||
:return: nothing
|
|
||||||
"""
|
"""
|
||||||
menu = tk.Menu(topology_generator_menu)
|
menu = tk.Menu(topology_generator_menu)
|
||||||
# number of nodes to create
|
# number of nodes to create
|
||||||
|
@ -247,9 +215,6 @@ class Menubar(tk.Menu):
|
||||||
def create_star_menu(self, topology_generator_menu: tk.Menu):
|
def create_star_menu(self, topology_generator_menu: tk.Menu):
|
||||||
"""
|
"""
|
||||||
Create star menu item and the sub menu items inside
|
Create star menu item and the sub menu items inside
|
||||||
|
|
||||||
:param tkinter.Menu topology_generator_menu: topology generator menu
|
|
||||||
:return: nothing
|
|
||||||
"""
|
"""
|
||||||
menu = tk.Menu(topology_generator_menu)
|
menu = tk.Menu(topology_generator_menu)
|
||||||
for i in range(3, 26, 1):
|
for i in range(3, 26, 1):
|
||||||
|
@ -260,9 +225,6 @@ class Menubar(tk.Menu):
|
||||||
def create_cycle_menu(self, topology_generator_menu: tk.Menu):
|
def create_cycle_menu(self, topology_generator_menu: tk.Menu):
|
||||||
"""
|
"""
|
||||||
Create cycle menu item and the sub items inside
|
Create cycle menu item and the sub items inside
|
||||||
|
|
||||||
:param tkinter.Menu topology_generator_menu: topology generator menu
|
|
||||||
:return: nothing
|
|
||||||
"""
|
"""
|
||||||
menu = tk.Menu(topology_generator_menu)
|
menu = tk.Menu(topology_generator_menu)
|
||||||
for i in range(3, 25, 1):
|
for i in range(3, 25, 1):
|
||||||
|
@ -273,9 +235,6 @@ class Menubar(tk.Menu):
|
||||||
def create_wheel_menu(self, topology_generator_menu: tk.Menu):
|
def create_wheel_menu(self, topology_generator_menu: tk.Menu):
|
||||||
"""
|
"""
|
||||||
Create wheel menu item and the sub menu items inside
|
Create wheel menu item and the sub menu items inside
|
||||||
|
|
||||||
:param tkinter.Menu topology_generator_menu: topology generator menu
|
|
||||||
:return: nothing
|
|
||||||
"""
|
"""
|
||||||
menu = tk.Menu(topology_generator_menu)
|
menu = tk.Menu(topology_generator_menu)
|
||||||
for i in range(4, 26, 1):
|
for i in range(4, 26, 1):
|
||||||
|
@ -286,9 +245,6 @@ class Menubar(tk.Menu):
|
||||||
def create_cube_menu(self, topology_generator_menu: tk.Menu):
|
def create_cube_menu(self, topology_generator_menu: tk.Menu):
|
||||||
"""
|
"""
|
||||||
Create cube menu item and the sub menu items inside
|
Create cube menu item and the sub menu items inside
|
||||||
|
|
||||||
:param tkinter.Menu topology_generator_menu: topology generator menu
|
|
||||||
:return: nothing
|
|
||||||
"""
|
"""
|
||||||
menu = tk.Menu(topology_generator_menu)
|
menu = tk.Menu(topology_generator_menu)
|
||||||
for i in range(2, 7, 1):
|
for i in range(2, 7, 1):
|
||||||
|
@ -299,9 +255,6 @@ class Menubar(tk.Menu):
|
||||||
def create_clique_menu(self, topology_generator_menu: tk.Menu):
|
def create_clique_menu(self, topology_generator_menu: tk.Menu):
|
||||||
"""
|
"""
|
||||||
Create clique menu item and the sub menu items inside
|
Create clique menu item and the sub menu items inside
|
||||||
|
|
||||||
:param tkinter.Menu topology_generator_menu: topology generator menu
|
|
||||||
:return: nothing
|
|
||||||
"""
|
"""
|
||||||
menu = tk.Menu(topology_generator_menu)
|
menu = tk.Menu(topology_generator_menu)
|
||||||
for i in range(3, 25, 1):
|
for i in range(3, 25, 1):
|
||||||
|
@ -312,9 +265,6 @@ class Menubar(tk.Menu):
|
||||||
def create_bipartite_menu(self, topology_generator_menu: tk.Menu):
|
def create_bipartite_menu(self, topology_generator_menu: tk.Menu):
|
||||||
"""
|
"""
|
||||||
Create bipartite menu item and the sub menu items inside
|
Create bipartite menu item and the sub menu items inside
|
||||||
|
|
||||||
:param tkinter.Menu topology_generator_menu: topology_generator_menu
|
|
||||||
:return: nothing
|
|
||||||
"""
|
"""
|
||||||
menu = tk.Menu(topology_generator_menu)
|
menu = tk.Menu(topology_generator_menu)
|
||||||
temp = 24
|
temp = 24
|
||||||
|
@ -331,10 +281,6 @@ class Menubar(tk.Menu):
|
||||||
def create_topology_generator_menu(self, tools_menu: tk.Menu):
|
def create_topology_generator_menu(self, tools_menu: tk.Menu):
|
||||||
"""
|
"""
|
||||||
Create topology menu item and its sub menu items
|
Create topology menu item and its sub menu items
|
||||||
|
|
||||||
:param tkinter.Menu tools_menu: tools menu
|
|
||||||
|
|
||||||
:return: nothing
|
|
||||||
"""
|
"""
|
||||||
menu = tk.Menu(tools_menu)
|
menu = tk.Menu(tools_menu)
|
||||||
self.create_random_menu(menu)
|
self.create_random_menu(menu)
|
||||||
|
@ -352,8 +298,6 @@ class Menubar(tk.Menu):
|
||||||
def draw_tools_menu(self):
|
def draw_tools_menu(self):
|
||||||
"""
|
"""
|
||||||
Create tools menu
|
Create tools menu
|
||||||
|
|
||||||
:return: nothing
|
|
||||||
"""
|
"""
|
||||||
menu = tk.Menu(self)
|
menu = tk.Menu(self)
|
||||||
menu.add_command(label="Auto rearrange all", state=tk.DISABLED)
|
menu.add_command(label="Auto rearrange all", state=tk.DISABLED)
|
||||||
|
@ -374,9 +318,6 @@ class Menubar(tk.Menu):
|
||||||
def create_observer_widgets_menu(self, widget_menu: tk.Menu):
|
def create_observer_widgets_menu(self, widget_menu: tk.Menu):
|
||||||
"""
|
"""
|
||||||
Create observer widget menu item and create the sub menu items inside
|
Create observer widget menu item and create the sub menu items inside
|
||||||
|
|
||||||
:param tkinter.Menu widget_menu: widget_menu
|
|
||||||
:return: nothing
|
|
||||||
"""
|
"""
|
||||||
var = tk.StringVar(value="none")
|
var = tk.StringVar(value="none")
|
||||||
menu = tk.Menu(widget_menu)
|
menu = tk.Menu(widget_menu)
|
||||||
|
@ -412,9 +353,6 @@ class Menubar(tk.Menu):
|
||||||
def create_adjacency_menu(self, widget_menu: tk.Menu):
|
def create_adjacency_menu(self, widget_menu: tk.Menu):
|
||||||
"""
|
"""
|
||||||
Create adjacency menu item and the sub menu items inside
|
Create adjacency menu item and the sub menu items inside
|
||||||
|
|
||||||
:param tkinter.Menu widget_menu: widget menu
|
|
||||||
:return: nothing
|
|
||||||
"""
|
"""
|
||||||
menu = tk.Menu(widget_menu)
|
menu = tk.Menu(widget_menu)
|
||||||
menu.add_command(label="OSPFv2", state=tk.DISABLED)
|
menu.add_command(label="OSPFv2", state=tk.DISABLED)
|
||||||
|
@ -426,8 +364,6 @@ class Menubar(tk.Menu):
|
||||||
def draw_widgets_menu(self):
|
def draw_widgets_menu(self):
|
||||||
"""
|
"""
|
||||||
Create widget menu
|
Create widget menu
|
||||||
|
|
||||||
:return: nothing
|
|
||||||
"""
|
"""
|
||||||
menu = tk.Menu(self)
|
menu = tk.Menu(self)
|
||||||
self.create_observer_widgets_menu(menu)
|
self.create_observer_widgets_menu(menu)
|
||||||
|
@ -443,8 +379,6 @@ class Menubar(tk.Menu):
|
||||||
def draw_session_menu(self):
|
def draw_session_menu(self):
|
||||||
"""
|
"""
|
||||||
Create session menu
|
Create session menu
|
||||||
|
|
||||||
:return: nothing
|
|
||||||
"""
|
"""
|
||||||
menu = tk.Menu(self)
|
menu = tk.Menu(self)
|
||||||
menu.add_command(
|
menu.add_command(
|
||||||
|
@ -461,8 +395,6 @@ class Menubar(tk.Menu):
|
||||||
def draw_help_menu(self):
|
def draw_help_menu(self):
|
||||||
"""
|
"""
|
||||||
Create help menu
|
Create help menu
|
||||||
|
|
||||||
:return: nothing
|
|
||||||
"""
|
"""
|
||||||
menu = tk.Menu(self)
|
menu = tk.Menu(self)
|
||||||
menu.add_command(
|
menu.add_command(
|
||||||
|
|
|
@ -53,31 +53,31 @@ class NodeUtils:
|
||||||
ANTENNA_ICON = None
|
ANTENNA_ICON = None
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def is_ignore_node(cls, node_type):
|
def is_ignore_node(cls, node_type) -> bool:
|
||||||
return node_type in cls.IGNORE_NODES
|
return node_type in cls.IGNORE_NODES
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def is_container_node(cls, node_type):
|
def is_container_node(cls, node_type) -> bool:
|
||||||
return node_type in cls.CONTAINER_NODES
|
return node_type in cls.CONTAINER_NODES
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def is_model_node(cls, node_type):
|
def is_model_node(cls, node_type) -> bool:
|
||||||
return node_type == NodeType.DEFAULT
|
return node_type == NodeType.DEFAULT
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def is_image_node(cls, node_type):
|
def is_image_node(cls, node_type) -> bool:
|
||||||
return node_type in cls.IMAGE_NODES
|
return node_type in cls.IMAGE_NODES
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def is_wireless_node(cls, node_type):
|
def is_wireless_node(cls, node_type) -> bool:
|
||||||
return node_type in cls.WIRELESS_NODES
|
return node_type in cls.WIRELESS_NODES
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def is_rj45_node(cls, node_type):
|
def is_rj45_node(cls, node_type) -> bool:
|
||||||
return node_type in cls.RJ45_NODES
|
return node_type in cls.RJ45_NODES
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def node_icon(cls, node_type, model):
|
def node_icon(cls, node_type, model: str) -> bool:
|
||||||
if model == "":
|
if model == "":
|
||||||
model = None
|
model = None
|
||||||
return cls.NODE_ICONS[(node_type, model)]
|
return cls.NODE_ICONS[(node_type, model)]
|
||||||
|
|
|
@ -1,4 +1,6 @@
|
||||||
"status bar"
|
"""
|
||||||
|
status bar
|
||||||
|
"""
|
||||||
import tkinter as tk
|
import tkinter as tk
|
||||||
from tkinter import ttk
|
from tkinter import ttk
|
||||||
|
|
||||||
|
|
|
@ -4,6 +4,9 @@ import tkinter as tk
|
||||||
from functools import partial
|
from functools import partial
|
||||||
from tkinter import messagebox, ttk
|
from tkinter import messagebox, ttk
|
||||||
from tkinter.font import Font
|
from tkinter.font import Font
|
||||||
|
from typing import Callable
|
||||||
|
|
||||||
|
from PIL import ImageTk
|
||||||
|
|
||||||
from core.api.grpc import core_pb2
|
from core.api.grpc import core_pb2
|
||||||
from core.gui.dialogs.customnodes import CustomNodesDialog
|
from core.gui.dialogs.customnodes import CustomNodesDialog
|
||||||
|
@ -196,7 +199,9 @@ class Toolbar(ttk.Frame):
|
||||||
self.wait_window(picker)
|
self.wait_window(picker)
|
||||||
self.app.unbind_all("<ButtonRelease-1>")
|
self.app.unbind_all("<ButtonRelease-1>")
|
||||||
|
|
||||||
def create_picker_button(self, image, func, frame: ttk.Frame, label: str):
|
def create_picker_button(
|
||||||
|
self, image: ImageTk.PhotoImage, func: Callable, frame: ttk.Frame, label: str
|
||||||
|
):
|
||||||
"""
|
"""
|
||||||
Create button and put it on the frame
|
Create button and put it on the frame
|
||||||
|
|
||||||
|
@ -204,7 +209,6 @@ class Toolbar(ttk.Frame):
|
||||||
:param func: the command that is executed when button is clicked
|
:param func: the command that is executed when button is clicked
|
||||||
:param tkinter.Frame frame: frame that contains the button
|
:param tkinter.Frame frame: frame that contains the button
|
||||||
:param str label: button label
|
:param str label: button label
|
||||||
:return: nothing
|
|
||||||
"""
|
"""
|
||||||
button = ttk.Button(
|
button = ttk.Button(
|
||||||
frame, image=image, text=label, compound=tk.TOP, style=Styles.picker_button
|
frame, image=image, text=label, compound=tk.TOP, style=Styles.picker_button
|
||||||
|
@ -213,7 +217,9 @@ class Toolbar(ttk.Frame):
|
||||||
button.bind("<ButtonRelease-1>", lambda e: func())
|
button.bind("<ButtonRelease-1>", lambda e: func())
|
||||||
button.grid(pady=1)
|
button.grid(pady=1)
|
||||||
|
|
||||||
def create_button(self, frame: ttk.Frame, image, func, tooltip: str):
|
def create_button(
|
||||||
|
self, frame: ttk.Frame, image: ImageTk.PhotoImage, func: Callable, tooltip: str
|
||||||
|
):
|
||||||
button = ttk.Button(frame, image=image, command=func)
|
button = ttk.Button(frame, image=image, command=func)
|
||||||
button.image = image
|
button.image = image
|
||||||
button.grid(sticky="ew")
|
button.grid(sticky="ew")
|
||||||
|
@ -234,8 +240,6 @@ class Toolbar(ttk.Frame):
|
||||||
"""
|
"""
|
||||||
Start session handler redraw buttons, send node and link messages to grpc
|
Start session handler redraw buttons, send node and link messages to grpc
|
||||||
server.
|
server.
|
||||||
|
|
||||||
:return: nothing
|
|
||||||
"""
|
"""
|
||||||
self.app.canvas.hide_context()
|
self.app.canvas.hide_context()
|
||||||
self.app.statusbar.progress_bar.start(5)
|
self.app.statusbar.progress_bar.start(5)
|
||||||
|
@ -299,8 +303,6 @@ class Toolbar(ttk.Frame):
|
||||||
def create_node_button(self):
|
def create_node_button(self):
|
||||||
"""
|
"""
|
||||||
Create network layer button
|
Create network layer button
|
||||||
|
|
||||||
:return: nothing
|
|
||||||
"""
|
"""
|
||||||
image = icon(ImageEnum.ROUTER)
|
image = icon(ImageEnum.ROUTER)
|
||||||
self.node_button = ttk.Button(
|
self.node_button = ttk.Button(
|
||||||
|
@ -313,8 +315,6 @@ class Toolbar(ttk.Frame):
|
||||||
def draw_network_picker(self):
|
def draw_network_picker(self):
|
||||||
"""
|
"""
|
||||||
Draw the options for link-layer button.
|
Draw the options for link-layer button.
|
||||||
|
|
||||||
:return: nothing
|
|
||||||
"""
|
"""
|
||||||
self.hide_pickers()
|
self.hide_pickers()
|
||||||
self.network_picker = ttk.Frame(self.master)
|
self.network_picker = ttk.Frame(self.master)
|
||||||
|
@ -338,8 +338,6 @@ class Toolbar(ttk.Frame):
|
||||||
"""
|
"""
|
||||||
Create link-layer node button and the options that represent different
|
Create link-layer node button and the options that represent different
|
||||||
link-layer node types.
|
link-layer node types.
|
||||||
|
|
||||||
:return: nothing
|
|
||||||
"""
|
"""
|
||||||
image = icon(ImageEnum.HUB)
|
image = icon(ImageEnum.HUB)
|
||||||
self.network_button = ttk.Button(
|
self.network_button = ttk.Button(
|
||||||
|
@ -352,8 +350,6 @@ class Toolbar(ttk.Frame):
|
||||||
def draw_annotation_picker(self):
|
def draw_annotation_picker(self):
|
||||||
"""
|
"""
|
||||||
Draw the options for marker button.
|
Draw the options for marker button.
|
||||||
|
|
||||||
:return: nothing
|
|
||||||
"""
|
"""
|
||||||
self.hide_pickers()
|
self.hide_pickers()
|
||||||
self.annotation_picker = ttk.Frame(self.master)
|
self.annotation_picker = ttk.Frame(self.master)
|
||||||
|
@ -380,8 +376,6 @@ class Toolbar(ttk.Frame):
|
||||||
def create_annotation_button(self):
|
def create_annotation_button(self):
|
||||||
"""
|
"""
|
||||||
Create marker button and options that represent different marker types
|
Create marker button and options that represent different marker types
|
||||||
|
|
||||||
:return: nothing
|
|
||||||
"""
|
"""
|
||||||
image = icon(ImageEnum.MARKER)
|
image = icon(ImageEnum.MARKER)
|
||||||
self.annotation_button = ttk.Button(
|
self.annotation_button = ttk.Button(
|
||||||
|
@ -418,8 +412,6 @@ class Toolbar(ttk.Frame):
|
||||||
def click_stop(self):
|
def click_stop(self):
|
||||||
"""
|
"""
|
||||||
redraw buttons on the toolbar, send node and link messages to grpc server
|
redraw buttons on the toolbar, send node and link messages to grpc server
|
||||||
|
|
||||||
:return: nothing
|
|
||||||
"""
|
"""
|
||||||
self.app.canvas.hide_context()
|
self.app.canvas.hide_context()
|
||||||
self.app.statusbar.progress_bar.start(5)
|
self.app.statusbar.progress_bar.start(5)
|
||||||
|
|
|
@ -40,7 +40,7 @@ class InputValidation:
|
||||||
if value == "":
|
if value == "":
|
||||||
event.widget.insert(tk.END, default)
|
event.widget.insert(tk.END, default)
|
||||||
|
|
||||||
def check_positive_int(self, s: str):
|
def check_positive_int(self, s: str) -> bool:
|
||||||
if len(s) == 0:
|
if len(s) == 0:
|
||||||
return True
|
return True
|
||||||
try:
|
try:
|
||||||
|
@ -51,7 +51,7 @@ class InputValidation:
|
||||||
except ValueError:
|
except ValueError:
|
||||||
return False
|
return False
|
||||||
|
|
||||||
def check_positive_float(self, s: str):
|
def check_positive_float(self, s: str) -> bool:
|
||||||
if len(s) == 0:
|
if len(s) == 0:
|
||||||
return True
|
return True
|
||||||
try:
|
try:
|
||||||
|
@ -62,7 +62,7 @@ class InputValidation:
|
||||||
except ValueError:
|
except ValueError:
|
||||||
return False
|
return False
|
||||||
|
|
||||||
def check_node_name(self, s: str):
|
def check_node_name(self, s: str) -> bool:
|
||||||
if len(s) < 0:
|
if len(s) < 0:
|
||||||
return False
|
return False
|
||||||
if len(s) == 0:
|
if len(s) == 0:
|
||||||
|
@ -72,7 +72,7 @@ class InputValidation:
|
||||||
return False
|
return False
|
||||||
return True
|
return True
|
||||||
|
|
||||||
def check_canvas_int(self, s: str):
|
def check_canvas_int(self, s: str) -> bool:
|
||||||
if len(s) == 0:
|
if len(s) == 0:
|
||||||
return True
|
return True
|
||||||
try:
|
try:
|
||||||
|
@ -83,7 +83,7 @@ class InputValidation:
|
||||||
except ValueError:
|
except ValueError:
|
||||||
return False
|
return False
|
||||||
|
|
||||||
def check_canvas_float(self, s: str):
|
def check_canvas_float(self, s: str) -> bool:
|
||||||
if not s:
|
if not s:
|
||||||
return True
|
return True
|
||||||
try:
|
try:
|
||||||
|
@ -94,7 +94,7 @@ class InputValidation:
|
||||||
except ValueError:
|
except ValueError:
|
||||||
return False
|
return False
|
||||||
|
|
||||||
def check_ip4(self, s: str):
|
def check_ip4(self, s: str) -> bool:
|
||||||
if not s:
|
if not s:
|
||||||
return True
|
return True
|
||||||
pat = re.compile("^([0-9]+[.])*[0-9]*$")
|
pat = re.compile("^([0-9]+[.])*[0-9]*$")
|
||||||
|
@ -113,7 +113,7 @@ class InputValidation:
|
||||||
else:
|
else:
|
||||||
return False
|
return False
|
||||||
|
|
||||||
def check_rbg(self, s: str):
|
def check_rbg(self, s: str) -> bool:
|
||||||
if not s:
|
if not s:
|
||||||
return True
|
return True
|
||||||
if s.startswith("0") and len(s) >= 2:
|
if s.startswith("0") and len(s) >= 2:
|
||||||
|
@ -127,7 +127,7 @@ class InputValidation:
|
||||||
except ValueError:
|
except ValueError:
|
||||||
return False
|
return False
|
||||||
|
|
||||||
def check_hex(self, s: str):
|
def check_hex(self, s: str) -> bool:
|
||||||
if not s:
|
if not s:
|
||||||
return True
|
return True
|
||||||
pat = re.compile("^([#]([0-9]|[a-f])+)$|^[#]$")
|
pat = re.compile("^([#]([0-9]|[a-f])+)$|^[#]$")
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
import logging
|
import logging
|
||||||
import tkinter as tk
|
import tkinter as tk
|
||||||
from functools import partial
|
from functools import partial
|
||||||
|
from pathlib import PosixPath
|
||||||
from tkinter import filedialog, font, ttk
|
from tkinter import filedialog, font, ttk
|
||||||
|
|
||||||
from core.api.grpc import core_pb2
|
from core.api.grpc import core_pb2
|
||||||
|
@ -19,7 +20,7 @@ INT_TYPES = {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
def file_button_click(value, parent):
|
def file_button_click(value: tk.StringVar, parent: tk.Widget):
|
||||||
file_path = filedialog.askopenfilename(title="Select File", parent=parent)
|
file_path = filedialog.askopenfilename(title="Select File", parent=parent)
|
||||||
if file_path:
|
if file_path:
|
||||||
value.set(file_path)
|
value.set(file_path)
|
||||||
|
@ -49,13 +50,13 @@ class FrameScroll(ttk.Frame):
|
||||||
self.frame.bind("<Configure>", self._configure_frame)
|
self.frame.bind("<Configure>", self._configure_frame)
|
||||||
self.canvas.bind("<Configure>", self._configure_canvas)
|
self.canvas.bind("<Configure>", self._configure_canvas)
|
||||||
|
|
||||||
def _configure_frame(self, event):
|
def _configure_frame(self, event: tk.Event):
|
||||||
req_width = self.frame.winfo_reqwidth()
|
req_width = self.frame.winfo_reqwidth()
|
||||||
if req_width != self.canvas.winfo_reqwidth():
|
if req_width != self.canvas.winfo_reqwidth():
|
||||||
self.canvas.configure(width=req_width)
|
self.canvas.configure(width=req_width)
|
||||||
self.canvas.configure(scrollregion=self.canvas.bbox("all"))
|
self.canvas.configure(scrollregion=self.canvas.bbox("all"))
|
||||||
|
|
||||||
def _configure_canvas(self, event):
|
def _configure_canvas(self, event: tk.Event):
|
||||||
self.canvas.itemconfig(self.frame_id, width=event.width)
|
self.canvas.itemconfig(self.frame_id, width=event.width)
|
||||||
|
|
||||||
def clear(self):
|
def clear(self):
|
||||||
|
@ -238,7 +239,7 @@ class Spinbox(ttk.Entry):
|
||||||
self.tk.call(self._w, "set", value)
|
self.tk.call(self._w, "set", value)
|
||||||
|
|
||||||
|
|
||||||
def image_chooser(parent, path):
|
def image_chooser(parent: tk.Widget, path: PosixPath):
|
||||||
return filedialog.askopenfilename(
|
return filedialog.askopenfilename(
|
||||||
parent=parent,
|
parent=parent,
|
||||||
initialdir=str(path),
|
initialdir=str(path),
|
||||||
|
|
Loading…
Add table
Reference in a new issue