This commit is contained in:
Huy Pham 2020-01-14 11:06:52 -08:00
parent b9b8e3a5f1
commit 6c8a2526d9
40 changed files with 219 additions and 141 deletions

View file

@ -1,6 +1,5 @@
import tkinter as tk
from tkinter import ttk
from typing import Optional
from core.gui import appconfig, themes
from core.gui.coreclient import CoreClient
@ -18,7 +17,7 @@ HEIGHT = 800
class Application(tk.Frame):
def __init__(self, master: Optional[tk.Widget] = None):
def __init__(self, master: tk.Widget = None):
super().__init__(master)
# load node icons
NodeUtils.setup()

View file

@ -5,7 +5,7 @@ import json
import logging
import os
from pathlib import Path
from typing import Dict, List, Optional
from typing import TYPE_CHECKING, Dict, List, Optional
import grpc
@ -22,6 +22,9 @@ from core.gui.graph.shapeutils import ShapeType
from core.gui.interface import InterfaceManager
from core.gui.nodeutils import NodeDraw, NodeUtils
if TYPE_CHECKING:
from core.gui.app import Application
GUI_SOURCE = "gui"
OBSERVERS = {
"processes": "ps",
@ -50,7 +53,7 @@ class Observer:
class CoreClient:
def __init__(self, app):
def __init__(self, app: "Application"):
"""
Create a CoreGrpc instance
"""
@ -137,7 +140,7 @@ class CoreClient:
def handle_events(self, event: core_pb2.Event):
if event.session_id != self.session_id:
logging.warn(
logging.warning(
"ignoring event session(%s) current(%s)",
event.session_id,
self.session_id,

View file

@ -35,7 +35,7 @@ THE POSSIBILITY OF SUCH DAMAGE.\
class AboutDialog(Dialog):
def __init__(self, master: tk.Widget, app: "Application"):
def __init__(self, master: "Application", app: "Application"):
super().__init__(master, app, "About CORE", modal=True)
self.draw()

View file

@ -15,7 +15,7 @@ if TYPE_CHECKING:
class AlertsDialog(Dialog):
def __init__(self, master: tk.Widget, app: "Application"):
def __init__(self, master: "Application", app: "Application"):
super().__init__(master, app, "Alerts", modal=True)
self.app = app
self.tree = None
@ -124,7 +124,7 @@ class AlertsDialog(Dialog):
class DaemonLog(Dialog):
def __init__(self, master, app):
def __init__(self, master: tk.Widget, app: "Application"):
super().__init__(master, app, "core-daemon log", modal=True)
self.columnconfigure(0, weight=1)
self.path = tk.StringVar(value="/var/log/core-daemon.log")

View file

@ -17,11 +17,9 @@ if TYPE_CHECKING:
class CanvasWallpaperDialog(Dialog):
def __init__(self, master: tk.Widget, app: "Application"):
def __init__(self, master: "Application", app: "Application"):
"""
create an instance of CanvasWallpaper object
:param coretk.app.Application app: root application
"""
super().__init__(master, app, "Canvas Background", modal=True)
self.canvas = self.app.canvas

View file

@ -4,7 +4,7 @@ custom color picker
import logging
import tkinter as tk
from tkinter import ttk
from typing import TYPE_CHECKING, Optional
from typing import TYPE_CHECKING, Any, Optional
from core.gui.dialogs.dialog import Dialog
@ -14,10 +14,7 @@ if TYPE_CHECKING:
class ColorPickerDialog(Dialog):
def __init__(
self,
master: tk.Widget,
app: "Application",
initcolor: Optional[str] = "#000000",
self, master: Any, app: "Application", initcolor: Optional[str] = "#000000"
):
super().__init__(master, app, "color picker", modal=True)
self.red_entry = None

View file

@ -5,7 +5,7 @@ copy service config dialog
import logging
import tkinter as tk
from tkinter import ttk
from typing import TYPE_CHECKING, Tuple
from typing import TYPE_CHECKING, Any, Tuple
from core.gui.dialogs.dialog import Dialog
from core.gui.themes import FRAME_PAD, PADX
@ -13,11 +13,10 @@ from core.gui.widgets import CodeText
if TYPE_CHECKING:
from core.gui.app import Application
from core.gui.dialogs.serviceconfig import ServiceConfigDialog
class CopyServiceConfigDialog(Dialog):
def __init__(self, master: "ServiceConfigDialog", app: "Application", node_id: int):
def __init__(self, master: Any, app: "Application", node_id: int):
super().__init__(master, app, f"Copy services to node {node_id}", modal=True)
self.parent = master
self.app = app
@ -133,6 +132,7 @@ class CopyServiceConfigDialog(Dialog):
def click_view(self):
selected = self.tree.selection()
data = ""
if selected:
item = self.tree.item(selected[0])
if "file" in item["tags"]:
@ -161,7 +161,7 @@ class CopyServiceConfigDialog(Dialog):
class ViewConfigDialog(Dialog):
def __init__(self, master, app, node_id, data):
def __init__(self, master: Any, app: "Application", node_id: int, data: bytes):
super().__init__(master, app, f"n{node_id} config data", modal=True)
self.data = data
self.service_data = None

View file

@ -2,7 +2,7 @@ import logging
import tkinter as tk
from pathlib import Path
from tkinter import ttk
from typing import TYPE_CHECKING, Set
from typing import TYPE_CHECKING, Any, Set
from core.gui import nodeutils
from core.gui.appconfig import ICONS_PATH
@ -17,7 +17,7 @@ if TYPE_CHECKING:
class ServicesSelectDialog(Dialog):
def __init__(self, master, app: "Application", current_services: Set[str]):
def __init__(self, master: Any, app: "Application", current_services: Set[str]):
super().__init__(master, app, "Node Services", modal=True)
self.groups = None
self.services = None
@ -100,7 +100,7 @@ class ServicesSelectDialog(Dialog):
class CustomNodesDialog(Dialog):
def __init__(self, master, app: "Application"):
def __init__(self, master: "Application", app: "Application"):
super().__init__(master, app, "Custom Nodes", modal=True)
self.edit_button = None
self.delete_button = None
@ -245,7 +245,7 @@ class CustomNodesDialog(Dialog):
self.nodes_list.listbox.selection_clear(0, tk.END)
self.nodes_list.listbox.event_generate("<<ListboxSelect>>")
def handle_node_select(self, event):
def handle_node_select(self, event: tk.Event):
selection = self.nodes_list.listbox.curselection()
if selection:
self.selected_index = selection[0]

View file

@ -5,7 +5,7 @@ import logging
import tkinter as tk
import webbrowser
from tkinter import ttk
from typing import TYPE_CHECKING, Optional
from typing import TYPE_CHECKING, Any, Optional
import grpc
@ -22,7 +22,7 @@ if TYPE_CHECKING:
class GlobalEmaneDialog(Dialog):
def __init__(self, master, app: "Application"):
def __init__(self, master: Any, app: "Application"):
super().__init__(master, app, "EMANE Configuration", modal=True)
self.config_frame = None
self.draw()
@ -55,7 +55,7 @@ class GlobalEmaneDialog(Dialog):
class EmaneModelDialog(Dialog):
def __init__(
self,
master,
master: Any,
app: "Application",
node: core_pb2.Node,
model: str,
@ -104,7 +104,9 @@ class EmaneModelDialog(Dialog):
class EmaneConfigDialog(Dialog):
def __init__(self, master, app: "Application", canvas_node: "CanvasNode"):
def __init__(
self, master: "Application", app: "Application", canvas_node: "CanvasNode"
):
super().__init__(
master, app, f"{canvas_node.core_node.name} EMANE Configuration", modal=True
)

View file

@ -1,6 +1,6 @@
import tkinter as tk
from tkinter import ttk
from typing import TYPE_CHECKING
from typing import TYPE_CHECKING, Union
from core.api.grpc import core_pb2
from core.gui.dialogs.dialog import Dialog
@ -12,7 +12,7 @@ if TYPE_CHECKING:
class HookDialog(Dialog):
def __init__(self, master, app: "Application"):
def __init__(self, master: Union[tk.Widget, Dialog], app: "Application"):
super().__init__(master, app, "Hook", modal=True)
self.name = tk.StringVar()
self.codetext = None
@ -88,7 +88,7 @@ class HookDialog(Dialog):
class HooksDialog(Dialog):
def __init__(self, master, app: "Application"):
def __init__(self, master: "Application", app: "Application"):
super().__init__(master, app, "Hooks", modal=True)
self.listbox = None
self.edit_button = None

View file

@ -13,7 +13,7 @@ from core.gui.themes import PADX, PADY
if TYPE_CHECKING:
from core.gui.app import Application
from core.gui.graph.edges import CanvasEdge
from core.gui.graph.graph import CanvasGraph, CanvasEdge
def get_int(var: tk.StringVar) -> Union[int, None]:
@ -33,7 +33,7 @@ def get_float(var: tk.StringVar) -> Union[float, None]:
class LinkConfigurationDialog(Dialog):
def __init__(self, master, app: "Application", edge: "CanvasEdge"):
def __init__(self, master: "CanvasGraph", app: "Application", edge: "CanvasEdge"):
super().__init__(master, app, "Link Configuration", modal=True)
self.app = app
self.edge = edge

View file

@ -17,7 +17,10 @@ MARKER_THICKNESS = [3, 5, 8, 10]
class MarkerDialog(Dialog):
def __init__(
self, master, app: "Application", initcolor: Optional[str] = "#000000"
self,
master: "Application",
app: "Application",
initcolor: Optional[str] = "#000000",
):
super().__init__(master, app, "marker tool", modal=False)
self.app = app

View file

@ -17,7 +17,9 @@ if TYPE_CHECKING:
class MobilityConfigDialog(Dialog):
def __init__(self, master, app: "Application", canvas_node: "CanvasNode"):
def __init__(
self, master: "Application", app: "Application", canvas_node: "CanvasNode"
):
super().__init__(
master,
app,

View file

@ -18,7 +18,13 @@ ICON_SIZE = 16
class MobilityPlayer:
def __init__(self, master, app: "Application", canvas_node: "CanvasNode", config):
def __init__(
self,
master: "Application",
app: "Application",
canvas_node: "CanvasNode",
config,
):
self.master = master
self.app = app
self.canvas_node = canvas_node
@ -62,7 +68,9 @@ class MobilityPlayer:
class MobilityPlayerDialog(Dialog):
def __init__(self, master, app, canvas_node, config):
def __init__(
self, master: Dialog, app: "Application", canvas_node: "CanvasNode", config
):
super().__init__(
master, app, f"{canvas_node.core_node.name} Mobility Player", modal=False
)

View file

@ -18,7 +18,7 @@ if TYPE_CHECKING:
from core.gui.graph.node import CanvasNode
def mac_auto(is_auto, entry: ttk.Entry):
def mac_auto(is_auto, entry):
logging.info("mac auto clicked")
if is_auto.get():
logging.info("disabling mac")
@ -38,13 +38,11 @@ class InterfaceData:
class NodeConfigDialog(Dialog):
def __init__(self, master, app: "Application", canvas_node: "CanvasNode"):
def __init__(
self, master: "Application", app: "Application", canvas_node: "CanvasNode"
):
"""
create an instance of node configuration
:param master: dialog master
:param coretk.app.Application: main app
:param coretk.graph.CanvasNode canvas_node: canvas node object
"""
super().__init__(
master, app, f"{canvas_node.core_node.name} Configuration", modal=True

View file

@ -3,7 +3,7 @@ core node services
"""
import tkinter as tk
from tkinter import messagebox, ttk
from typing import TYPE_CHECKING
from typing import TYPE_CHECKING, Any
from core.gui.dialogs.dialog import Dialog
from core.gui.dialogs.serviceconfig import ServiceConfigDialog
@ -17,7 +17,7 @@ if TYPE_CHECKING:
class NodeServiceDialog(Dialog):
def __init__(
self, master, app: "Application", canvas_node: "CanvasNode", services=None
self, master: Any, app: "Application", canvas_node: "CanvasNode", services=None
):
title = f"{canvas_node.core_node.name} Services"
super().__init__(master, app, title, modal=True)

View file

@ -12,7 +12,7 @@ if TYPE_CHECKING:
class ObserverDialog(Dialog):
def __init__(self, master, app: "Application"):
def __init__(self, master: "Application", app: "Application"):
super().__init__(master, app, "Observer Widgets", modal=True)
self.observers = None
self.save_button = None

View file

@ -12,7 +12,7 @@ if TYPE_CHECKING:
class PreferencesDialog(Dialog):
def __init__(self, master, app: "Application"):
def __init__(self, master: "Application", app: "Application"):
super().__init__(master, app, "Preferences", modal=True)
preferences = self.app.guiconfig["preferences"]
self.editor = tk.StringVar(value=preferences["editor"])

View file

@ -16,7 +16,7 @@ DEFAULT_PORT = 50051
class ServersDialog(Dialog):
def __init__(self, master, app: "Application"):
def __init__(self, master: "Application", app: "Application"):
super().__init__(master, app, "CORE Servers", modal=True)
self.name = tk.StringVar(value=DEFAULT_NAME)
self.address = tk.StringVar(value=DEFAULT_ADDRESS)

View file

@ -1,7 +1,9 @@
"Service configuration dialog"
"""
Service configuration dialog
"""
import tkinter as tk
from tkinter import ttk
from typing import TYPE_CHECKING, List
from typing import TYPE_CHECKING, Any, List
import grpc
@ -18,7 +20,9 @@ if TYPE_CHECKING:
class ServiceConfigDialog(Dialog):
def __init__(self, master, app: "Application", service_name: str, node_id: int):
def __init__(
self, master: Any, app: "Application", service_name: str, node_id: int
):
title = f"{service_name} Service"
super().__init__(master, app, title, modal=True)
self.master = master
@ -229,7 +233,7 @@ class ServiceConfigDialog(Dialog):
for i in range(3):
tab.rowconfigure(i, weight=1)
self.notebook.add(tab, text="Startup/Shutdown")
commands = []
# tab 3
for i in range(3):
label_frame = None

View file

@ -14,7 +14,7 @@ if TYPE_CHECKING:
class SessionOptionsDialog(Dialog):
def __init__(self, master, app: "Application"):
def __init__(self, master: "Application", app: "Application"):
super().__init__(master, app, "Session Options", modal=True)
self.config_frame = None
self.config = self.get_config()

View file

@ -17,7 +17,7 @@ if TYPE_CHECKING:
class SessionsDialog(Dialog):
def __init__(self, master, app: "Application"):
def __init__(self, master: "Application", app: "Application"):
super().__init__(master, app, "Sessions", modal=True)
self.selected = False
self.selected_id = None

View file

@ -20,7 +20,7 @@ BORDER_WIDTH = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
class ShapeDialog(Dialog):
def __init__(self, master, app: "Application", shape: "Shape"):
def __init__(self, master: "Application", app: "Application", shape: "Shape"):
if is_draw_shape(shape.shape_type):
title = "Add Shape"
else:

View file

@ -14,7 +14,7 @@ if TYPE_CHECKING:
class ThroughputDialog(Dialog):
def __init__(self, master, app: "Application"):
def __init__(self, master: "Application", app: "Application"):
super().__init__(master, app, "Throughput Config", modal=False)
self.app = app
self.canvas = app.canvas

View file

@ -18,7 +18,9 @@ if TYPE_CHECKING:
class WlanConfigDialog(Dialog):
def __init__(self, master, app: "Application", canvas_node: "CanvasNode"):
def __init__(
self, master: "Application", app: "Application", canvas_node: "CanvasNode"
):
super().__init__(
master, app, f"{canvas_node.core_node.name} Wlan Configuration", modal=True
)

View file

@ -1,9 +1,11 @@
from tkinter import messagebox
from typing import TYPE_CHECKING
import grpc
if TYPE_CHECKING:
import grpc
def show_grpc_error(e: grpc.RpcError):
def show_grpc_error(e: "grpc.RpcError"):
title = [x.capitalize() for x in e.code().name.lower().split("_")]
title = " ".join(title)
title = f"GRPC {title}"

View file

@ -1,13 +1,16 @@
import logging
import tkinter as tk
from tkinter.font import Font
from typing import Tuple
from typing import TYPE_CHECKING, Any, Tuple
from core.gui import themes
from core.gui.dialogs.linkconfig import LinkConfigurationDialog
from core.gui.graph import tags
from core.gui.nodeutils import NodeUtils
if TYPE_CHECKING:
from core.gui.graph.graph import CanvasGraph
TEXT_DISTANCE = 0.30
EDGE_WIDTH = 3
EDGE_COLOR = "#ff0000"
@ -16,11 +19,11 @@ EDGE_COLOR = "#ff0000"
class CanvasWirelessEdge:
def __init__(
self,
token: Tuple[int, int],
position: Tuple[int, int, int, int],
token: Tuple[Any, ...],
position: Tuple[float, float, float, float],
src: int,
dst: int,
canvas,
canvas: "CanvasGraph",
):
self.token = token
self.src = src
@ -39,10 +42,17 @@ class CanvasEdge:
Canvas edge class
"""
def __init__(self, x1: int, y1: int, x2: int, y2: int, src: int, canvas):
def __init__(
self,
x1: float,
y1: float,
x2: float,
y2: float,
src: int,
canvas: "CanvasGraph",
):
"""
Create an instance of canvas edge object
:param coretk.graph.graph.GraphCanvas canvas: canvas object
"""
self.src = src
self.dst = None
@ -69,7 +79,7 @@ class CanvasEdge:
self.link = link
self.draw_labels()
def get_coordinates(self) -> [int, int, int, int]:
def get_coordinates(self) -> [float, float, float, float]:
x1, y1, x2, y2 = self.canvas.coords(self.id)
v1 = x2 - x1
v2 = y2 - y1

View file

@ -1,6 +1,6 @@
import logging
import tkinter as tk
from typing import List, Optional
from typing import TYPE_CHECKING, List, Optional, Tuple
from PIL import Image, ImageTk
@ -16,12 +16,15 @@ from core.gui.graph.shapeutils import ShapeType, is_draw_shape, is_marker
from core.gui.images import Images
from core.gui.nodeutils import NodeUtils
if TYPE_CHECKING:
from core.gui.coreclient import CoreClient
ZOOM_IN = 1.1
ZOOM_OUT = 0.9
class CanvasGraph(tk.Canvas):
def __init__(self, master, core, width, height):
def __init__(self, master, core: "CoreClient", width: int, height: int):
super().__init__(master, highlightthickness=0, background="#cccccc")
self.app = master
self.core = core
@ -68,7 +71,7 @@ class CanvasGraph(tk.Canvas):
self.draw_canvas()
self.draw_grid()
def draw_canvas(self, dimensions=None):
def draw_canvas(self, dimensions: Optional[Tuple[int, int]] = None):
if self.grid is not None:
self.delete(self.grid)
if not dimensions:
@ -185,9 +188,6 @@ class CanvasGraph(tk.Canvas):
def add_wireless_edge(self, src: CanvasNode, dst: CanvasNode):
"""
add a wireless edge between 2 canvas nodes
:param CanvasNode src: source node
:param CanvasNode dst: destination node
"""
token = tuple(sorted((src.id, dst.id)))
x1, y1 = self.coords(src.id)
@ -319,9 +319,6 @@ class CanvasGraph(tk.Canvas):
def click_release(self, event: tk.Event):
"""
Draw a node or finish drawing an edge according to the current graph mode
:param event: mouse event
:return: nothing
"""
logging.debug("click release")
x, y = self.canvas_xy(event)
@ -760,7 +757,7 @@ class CanvasGraph(tk.Canvas):
self.redraw_canvas((image.width(), image.height()))
self.draw_wallpaper(image)
def redraw_canvas(self, dimensions: Optional[List[int]] = None):
def redraw_canvas(self, dimensions: Tuple[int, int] = None):
logging.info("redrawing canvas to dimensions: %s", dimensions)
# reset scale and move back to original position

View file

@ -253,7 +253,7 @@ class CanvasNode:
dialog = NodeServiceDialog(self.app.master, self.app, self)
dialog.show()
def has_emane_link(self, interface_id: int) -> bool:
def has_emane_link(self, interface_id: int) -> core_pb2.Node:
result = None
for edge in self.edges:
if self.id == edge.src:

View file

@ -1,24 +1,28 @@
import logging
from typing import List, Optional, Union
from typing import TYPE_CHECKING, Dict, List, Union
from core.gui.dialogs.shapemod import ShapeDialog
from core.gui.graph import tags
from core.gui.graph.shapeutils import ShapeType
if TYPE_CHECKING:
from core.gui.app import Application
from core.gui.graph.graph import CanvasGraph
class AnnotationData:
def __init__(
self,
text: Optional[str] = "",
font: Optional[str] = "Arial",
font_size: Optional[int] = 12,
text_color: Optional[str] = "#000000",
fill_color: Optional[str] = "",
border_color: Optional[str] = "#000000",
border_width: Optional[int] = 1,
bold: Optional[bool] = False,
italic: Optional[bool] = False,
underline: Optional[bool] = False,
text: str = "",
font: str = "Arial",
font_size: int = 12,
text_color: str = "#000000",
fill_color: str = "",
border_color: str = "#000000",
border_width: int = 1,
bold: bool = False,
italic: bool = False,
underline: bool = False,
):
self.text = text
self.font = font
@ -33,7 +37,17 @@ class AnnotationData:
class Shape:
def __init__(self, app, canvas, shape_type, x1, y1, x2=None, y2=None, data=None):
def __init__(
self,
app: "Application",
canvas: "CanvasGraph",
shape_type: ShapeType,
x1: float,
y1: float,
x2: float = None,
y2: float = None,
data: AnnotationData = None,
):
self.app = app
self.canvas = canvas
self.shape_type = shape_type
@ -152,7 +166,7 @@ class Shape:
self.canvas.delete(self.id)
self.canvas.delete(self.text_id)
def metadata(self):
def metadata(self) -> Dict[str, Union[str, int, bool]]:
coords = self.canvas.coords(self.id)
# update coords to actual positions
if len(coords) == 4:

View file

@ -1,9 +1,12 @@
import tkinter as tk
from tkinter import ttk
from typing import Optional
from typing import TYPE_CHECKING
from core.gui.themes import Styles
if TYPE_CHECKING:
from core.gui.graph.graph import CanvasGraph
class CanvasTooltip:
"""
@ -20,7 +23,14 @@ class CanvasTooltip:
Alberto Vassena on 2016.12.10.
"""
def __init__(self, canvas, *, pad=(5, 3, 5, 3), waittime=400, wraplength=600):
def __init__(
self,
canvas: "CanvasGraph",
*,
pad=(5, 3, 5, 3),
waittime: int = 400,
wraplength: int = 600
):
# in miliseconds, originally 500
self.waittime = waittime
# in pixels, originally 180
@ -31,10 +41,10 @@ class CanvasTooltip:
self.id = None
self.tw = None
def on_enter(self, event: Optional[tk.Event] = None):
def on_enter(self, event: tk.Event = None):
self.schedule()
def on_leave(self, event: Optional[tk.Event] = None):
def on_leave(self, event: tk.Event = None):
self.unschedule()
self.hide()
@ -48,7 +58,7 @@ class CanvasTooltip:
if id_:
self.canvas.after_cancel(id_)
def show(self, event: Optional[tk.Event] = None):
def show(self, event: tk.Event = None):
def tip_pos_calculator(canvas, label, *, tip_delta=(10, 5), pad=(5, 3, 5, 3)):
c = canvas
s_width, s_height = c.winfo_screenwidth(), c.winfo_screenheight()

View file

@ -1,21 +1,23 @@
import logging
import random
from typing import Optional, Set
from typing import TYPE_CHECKING, Set, Union
from netaddr import IPNetwork
from core.gui.graph.node import CanvasNode
from core.gui.nodeutils import NodeUtils
if TYPE_CHECKING:
from core.gui.app import Application
from core.api.grpc import core_pb2
from core.gui.graph.node import CanvasNode
def random_mac():
return ("{:02x}" * 6).format(*[random.randrange(256) for _ in range(6)])
class InterfaceManager:
def __init__(
self, app, address: Optional[str] = "10.0.0.0", mask: Optional[int] = 24
):
def __init__(self, app: "Application", address: str = "10.0.0.0", mask: int = 24):
self.app = app
self.mask = mask
self.base_prefix = max(self.mask - 8, 0)
@ -49,11 +51,11 @@ class InterfaceManager:
return str(ip4), str(ip6), prefix
@classmethod
def get_subnet(cls, interface):
def get_subnet(cls, interface: "core_pb2.Interface") -> IPNetwork:
return IPNetwork(f"{interface.ip4}/{interface.ip4mask}").cidr
def determine_subnet(
self, canvas_src_node: CanvasNode, canvas_dst_node: CanvasNode
self, canvas_src_node: "CanvasNode", canvas_dst_node: "CanvasNode"
):
src_node = canvas_src_node.core_node
dst_node = canvas_dst_node.core_node
@ -76,7 +78,9 @@ class InterfaceManager:
else:
logging.info("ignoring subnet change for link between network nodes")
def find_subnet(self, canvas_node: CanvasNode, visited: Optional[Set[int]] = None):
def find_subnet(
self, canvas_node: "CanvasNode", visited: Set[int] = None
) -> Union[IPNetwork, None]:
logging.info("finding subnet for node: %s", canvas_node.core_node.name)
canvas = self.app.canvas
cidr = None

View file

@ -6,7 +6,7 @@ import logging
import tkinter as tk
import webbrowser
from tkinter import filedialog, messagebox
from typing import Optional
from typing import TYPE_CHECKING, Optional
from core.gui.appconfig import XMLS_PATH
from core.gui.dialogs.about import AboutDialog
@ -21,13 +21,16 @@ from core.gui.dialogs.sessions import SessionsDialog
from core.gui.dialogs.throughput import ThroughputDialog
from core.gui.task import BackgroundTask
if TYPE_CHECKING:
from core.gui.app import Application
class MenuAction:
"""
Actions performed when choosing menu items
"""
def __init__(self, app, master):
def __init__(self, app: "Application", master: tk.Tk):
self.master = master
self.app = app
self.canvas = app.canvas
@ -39,11 +42,9 @@ class MenuAction:
# if quitapp:
# self.app.quit()
def prompt_save_running_session(self, quitapp: Optional[bool] = False):
def prompt_save_running_session(self, quitapp: bool = False):
"""
Prompt use to stop running session before application is closed
:return: nothing
"""
result = True
if self.app.core.is_runtime():
@ -58,15 +59,13 @@ class MenuAction:
elif quitapp:
self.app.quit()
def on_quit(self, event: Optional[tk.Event] = None):
def on_quit(self, event: tk.Event = None):
"""
Prompt user whether so save running session, and then close the application
:return: nothing
"""
self.prompt_save_running_session(quitapp=True)
def file_save_as_xml(self, event: Optional[tk.Event] = None):
def file_save_as_xml(self, event: tk.Event = None):
logging.info("menuaction.py file_save_as_xml()")
file_path = filedialog.asksaveasfilename(
initialdir=str(XMLS_PATH),

View file

@ -1,16 +1,20 @@
import tkinter as tk
from functools import partial
from typing import TYPE_CHECKING
import core.gui.menuaction as action
from core.gui.coreclient import OBSERVERS
if TYPE_CHECKING:
from core.gui.app import Application
class Menubar(tk.Menu):
"""
Core menubar
"""
def __init__(self, master, app, cnf={}, **kwargs):
def __init__(self, master: tk.Tk, app: "Application", cnf={}, **kwargs):
"""
Create a CoreMenubar instance
"""

View file

@ -3,13 +3,17 @@ status bar
"""
import tkinter as tk
from tkinter import ttk
from typing import TYPE_CHECKING
from core.gui.dialogs.alerts import AlertsDialog
from core.gui.themes import Styles
if TYPE_CHECKING:
from core.gui.app import Application
class StatusBar(ttk.Frame):
def __init__(self, master: tk.Widget, app, **kwargs):
def __init__(self, master: tk.Widget, app: "Application", **kwargs):
super().__init__(master, **kwargs)
self.app = app
self.status = None

View file

@ -159,7 +159,7 @@ def style_menu(widget: tk.Widget):
)
def style_listbox(widget: ttk.Widget):
def style_listbox(widget: tk.Widget):
style = ttk.Style()
bg = style.lookup(".", "background")
fg = style.lookup(".", "foreground")

View file

@ -4,9 +4,7 @@ import tkinter as tk
from functools import partial
from tkinter import messagebox, ttk
from tkinter.font import Font
from typing import Callable
from PIL import ImageTk
from typing import TYPE_CHECKING, Callable
from core.api.grpc import core_pb2
from core.gui.dialogs.customnodes import CustomNodesDialog
@ -14,11 +12,15 @@ from core.gui.dialogs.marker import MarkerDialog
from core.gui.graph.enums import GraphMode
from core.gui.graph.shapeutils import ShapeType, is_marker
from core.gui.images import ImageEnum, Images
from core.gui.nodeutils import NodeUtils
from core.gui.nodeutils import NodeDraw, NodeUtils
from core.gui.task import BackgroundTask
from core.gui.themes import Styles
from core.gui.tooltip import Tooltip
if TYPE_CHECKING:
from core.gui.app import Application
from PIL import ImageTk
TOOLBAR_SIZE = 32
PICKER_SIZE = 24
@ -32,11 +34,9 @@ class Toolbar(ttk.Frame):
Core toolbar class
"""
def __init__(self, master, app, **kwargs):
def __init__(self, master: "Application", app: "Application", **kwargs):
"""
Create a CoreToolbar instance
:param tkinter.Frame edit_frame: edit frame
"""
super().__init__(master, **kwargs)
self.app = app
@ -200,7 +200,7 @@ class Toolbar(ttk.Frame):
self.app.unbind_all("<ButtonRelease-1>")
def create_picker_button(
self, image: ImageTk.PhotoImage, func: Callable, frame: ttk.Frame, label: str
self, image: "ImageTk.PhotoImage", func: Callable, frame: ttk.Frame, label: str
):
"""
Create button and put it on the frame
@ -218,7 +218,11 @@ class Toolbar(ttk.Frame):
button.grid(pady=1)
def create_button(
self, frame: ttk.Frame, image: ImageTk.PhotoImage, func: Callable, tooltip: str
self,
frame: ttk.Frame,
image: "ImageTk.PhotoImage",
func: Callable,
tooltip: str,
):
button = ttk.Button(frame, image=image, command=func)
button.image = image
@ -280,7 +284,7 @@ class Toolbar(ttk.Frame):
dialog = CustomNodesDialog(self.app, self.app)
dialog.show()
def update_button(self, button: ttk.Button, image, node_draw):
def update_button(self, button: ttk.Button, image: "ImageTk", node_draw: NodeDraw):
logging.info("update button(%s): %s", button, node_draw)
self.hide_pickers()
button.configure(image=image)
@ -429,7 +433,7 @@ class Toolbar(ttk.Frame):
if not response.result:
messagebox.showerror("Stop Error", "Errors stopping session")
def update_annotation(self, image: ImageTk.PhotoImage, shape_type: str):
def update_annotation(self, image: "ImageTk.PhotoImage", shape_type: ShapeType):
logging.info("clicked annotation: ")
self.hide_pickers()
self.annotation_button.configure(image=image)
@ -439,7 +443,7 @@ class Toolbar(ttk.Frame):
if is_marker(shape_type):
if self.marker_tool:
self.marker_tool.destroy()
self.marker_tool = MarkerDialog(self.master, self.app)
self.marker_tool = MarkerDialog(self.app, self.app)
self.marker_tool.show()
def click_run_button(self):
@ -455,7 +459,7 @@ class Toolbar(ttk.Frame):
self.app.canvas.annotation_type = ShapeType.MARKER
if self.marker_tool:
self.marker_tool.destroy()
self.marker_tool = MarkerDialog(self.master, self.app)
self.marker_tool = MarkerDialog(self.app, self.app)
self.marker_tool.show()
def click_two_node_button(self):

View file

@ -1,6 +1,5 @@
import tkinter as tk
from tkinter import ttk
from typing import Optional
from core.gui.themes import Styles
@ -19,10 +18,10 @@ class Tooltip(object):
self.id = None
self.tw = None
def on_enter(self, event: Optional[tk.Event] = None):
def on_enter(self, event: tk.Event = None):
self.schedule()
def on_leave(self, event: Optional[tk.Event] = None):
def on_leave(self, event: tk.Event = None):
self.unschedule()
self.close(event)
@ -36,7 +35,7 @@ class Tooltip(object):
if id_:
self.widget.after_cancel(id_)
def enter(self, event: Optional[tk.Event] = None):
def enter(self, event: tk.Event = None):
x, y, cx, cy = self.widget.bbox("insert")
x += self.widget.winfo_rootx()
y += self.widget.winfo_rooty() + 32
@ -51,6 +50,6 @@ class Tooltip(object):
label = ttk.Label(frame, text=self.text, style=Styles.tooltip)
label.grid()
def close(self, event: Optional[tk.Event] = None):
def close(self, event: tk.Event = None):
if self.tw:
self.tw.destroy()

View file

@ -3,13 +3,17 @@ input validation
"""
import re
import tkinter as tk
from typing import TYPE_CHECKING
import netaddr
from netaddr import IPNetwork
if TYPE_CHECKING:
from core.gui.app import Application
class InputValidation:
def __init__(self, app):
def __init__(self, app: "Application"):
self.master = app.master
self.positive_int = None
self.positive_float = None

View file

@ -3,11 +3,16 @@ import tkinter as tk
from functools import partial
from pathlib import PosixPath
from tkinter import filedialog, font, ttk
from typing import TYPE_CHECKING, Dict, Optional
from core.api.grpc import core_pb2
from core.gui import themes
from core.gui.themes import FRAME_PAD, PADX, PADY
if TYPE_CHECKING:
from core.gui.app import Application
from core.gui.dialogs.dialog import Dialog
INT_TYPES = {
core_pb2.ConfigOptionType.UINT8,
core_pb2.ConfigOptionType.UINT16,
@ -27,7 +32,7 @@ def file_button_click(value: tk.StringVar, parent: tk.Widget):
class FrameScroll(ttk.Frame):
def __init__(self, master, app, _cls=ttk.Frame, **kw):
def __init__(self, master: ttk.Widget, app: "Application", _cls=ttk.Frame, **kw):
super().__init__(master, **kw)
self.app = app
self.rowconfigure(0, weight=1)
@ -65,7 +70,13 @@ class FrameScroll(ttk.Frame):
class ConfigFrame(ttk.Notebook):
def __init__(self, master, app, config, **kw):
def __init__(
self,
master: ttk.Widget,
app: "Application",
config: Dict[str, core_pb2.ConfigOption],
**kw
):
super().__init__(master, **kw)
self.app = app
self.config = config
@ -175,7 +186,7 @@ class ConfigFrame(ttk.Notebook):
class ListboxScroll(ttk.Frame):
def __init__(self, master=None, **kw):
def __init__(self, master: Optional[ttk.Widget] = None, **kw):
super().__init__(master, **kw)
self.columnconfigure(0, weight=1)
self.rowconfigure(0, weight=1)
@ -190,7 +201,7 @@ class ListboxScroll(ttk.Frame):
class CheckboxList(FrameScroll):
def __init__(self, master, app, clicked=None, **kw):
def __init__(self, master: ttk.Widget, app: "Application", clicked=None, **kw):
super().__init__(master, app, **kw)
self.clicked = clicked
self.frame.columnconfigure(0, weight=1)
@ -208,7 +219,7 @@ class CodeFont(font.Font):
class CodeText(ttk.Frame):
def __init__(self, master, **kwargs):
def __init__(self, master: ttk.Widget, **kwargs):
super().__init__(master, **kwargs)
self.rowconfigure(0, weight=1)
self.columnconfigure(0, weight=1)
@ -232,14 +243,14 @@ class CodeText(ttk.Frame):
class Spinbox(ttk.Entry):
def __init__(self, master=None, **kwargs):
def __init__(self, master: Optional[ttk.Widget] = None, **kwargs):
super().__init__(master, "ttk::spinbox", **kwargs)
def set(self, value):
self.tk.call(self._w, "set", value)
def image_chooser(parent: tk.Widget, path: PosixPath):
def image_chooser(parent: "Dialog", path: PosixPath):
return filedialog.askopenfilename(
parent=parent,
initialdir=str(path),