pygui: initial canvas manager with a single tab by default, updates to how throughputs are handled related to canvases

This commit is contained in:
Blake Harnden 2020-12-17 14:31:09 -08:00
parent 2f9c169e66
commit f9a4fe3331
8 changed files with 59 additions and 61 deletions

View file

@ -259,7 +259,7 @@ class CoreClient:
if self.handling_throughputs: if self.handling_throughputs:
self.handling_throughputs.cancel() self.handling_throughputs.cancel()
self.handling_throughputs = None self.handling_throughputs = None
self.app.canvas.clear_throughputs() self.app.manager.clear_throughputs()
def cancel_events(self) -> None: def cancel_events(self) -> None:
if self.handling_events: if self.handling_events:
@ -290,7 +290,7 @@ class CoreClient:
) )
return return
logging.debug("handling throughputs event: %s", event) logging.debug("handling throughputs event: %s", event)
self.app.after(0, self.app.canvas.set_throughputs, event) self.app.after(0, self.app.manager.set_throughputs, event)
def handle_cpu_event(self, event: core_pb2.CpuUsageEvent) -> None: def handle_cpu_event(self, event: core_pb2.CpuUsageEvent) -> None:
self.app.after(0, self.app.statusbar.set_cpu, event.usage) self.app.after(0, self.app.statusbar.set_cpu, event.usage)

View file

@ -134,7 +134,8 @@ class PreferencesDialog(Dialog):
# scale toolbar and canvas items # scale toolbar and canvas items
self.app.toolbar.scale() self.app.toolbar.scale()
self.app.canvas.scale_graph() for canvas in self.app.manager.all():
canvas.scale_graph()
def adjust_scale(self, arg1: str, arg2: str, arg3: str) -> None: def adjust_scale(self, arg1: str, arg2: str, arg3: str) -> None:
scale_value = self.gui_scale.get() scale_value = self.gui_scale.get()

View file

@ -7,7 +7,7 @@ from typing import TYPE_CHECKING, Optional
from core.gui.dialogs.colorpicker import ColorPickerDialog from core.gui.dialogs.colorpicker import ColorPickerDialog
from core.gui.dialogs.dialog import Dialog from core.gui.dialogs.dialog import Dialog
from core.gui.graph.graph import CanvasGraph from core.gui.graph.manager import CanvasManager
from core.gui.themes import FRAME_PAD, PADX, PADY from core.gui.themes import FRAME_PAD, PADX, PADY
if TYPE_CHECKING: if TYPE_CHECKING:
@ -17,16 +17,16 @@ if TYPE_CHECKING:
class ThroughputDialog(Dialog): class ThroughputDialog(Dialog):
def __init__(self, app: "Application") -> None: def __init__(self, app: "Application") -> None:
super().__init__(app, "Throughput Config") super().__init__(app, "Throughput Config")
self.canvas: CanvasGraph = app.canvas self.manager: CanvasManager = app.manager
self.show_throughput: tk.IntVar = tk.IntVar(value=1) self.show_throughput: tk.IntVar = tk.IntVar(value=1)
self.exponential_weight: tk.IntVar = tk.IntVar(value=1) self.exponential_weight: tk.IntVar = tk.IntVar(value=1)
self.transmission: tk.IntVar = tk.IntVar(value=1) self.transmission: tk.IntVar = tk.IntVar(value=1)
self.reception: tk.IntVar = tk.IntVar(value=1) self.reception: tk.IntVar = tk.IntVar(value=1)
self.threshold: tk.DoubleVar = tk.DoubleVar( self.threshold: tk.DoubleVar = tk.DoubleVar(
value=self.canvas.throughput_threshold value=self.manager.throughput_threshold
) )
self.width: tk.IntVar = tk.IntVar(value=self.canvas.throughput_width) self.width: tk.IntVar = tk.IntVar(value=self.manager.throughput_width)
self.color: str = self.canvas.throughput_color self.color: str = self.manager.throughput_color
self.color_button: Optional[tk.Button] = None self.color_button: Optional[tk.Button] = None
self.top.columnconfigure(0, weight=1) self.top.columnconfigure(0, weight=1)
self.draw() self.draw()
@ -106,7 +106,7 @@ class ThroughputDialog(Dialog):
self.color_button.config(bg=self.color, text=self.color, bd=0) self.color_button.config(bg=self.color, text=self.color, bd=0)
def click_save(self) -> None: def click_save(self) -> None:
self.canvas.throughput_threshold = self.threshold.get() self.manager.throughput_threshold = self.threshold.get()
self.canvas.throughput_width = self.width.get() self.manager.throughput_width = self.width.get()
self.canvas.throughput_color = self.color self.manager.throughput_color = self.color
self.destroy() self.destroy()

View file

@ -21,7 +21,7 @@ RANGE_WIDTH: int = 3
class WlanConfigDialog(Dialog): class WlanConfigDialog(Dialog):
def __init__(self, app: "Application", canvas_node: "CanvasNode") -> None: def __init__(self, app: "Application", canvas_node: "CanvasNode") -> None:
super().__init__(app, f"{canvas_node.core_node.name} WLAN Configuration") super().__init__(app, f"{canvas_node.core_node.name} WLAN Configuration")
self.canvas: "CanvasGraph" = app.canvas self.canvas: "CanvasGraph" = app.manager.current()
self.canvas_node: "CanvasNode" = canvas_node self.canvas_node: "CanvasNode" = canvas_node
self.node: Node = canvas_node.core_node self.node: Node = canvas_node.core_node
self.config_frame: Optional[ConfigFrame] = None self.config_frame: Optional[ConfigFrame] = None

View file

@ -357,9 +357,9 @@ class CanvasEdge(Edge):
throughput = 0.001 * throughput throughput = 0.001 * throughput
text = f"{throughput:.3f} kbps" text = f"{throughput:.3f} kbps"
self.middle_label_text(text) self.middle_label_text(text)
if throughput > self.canvas.throughput_threshold: if throughput > self.canvas.manager.throughput_threshold:
color = self.canvas.throughput_color color = self.canvas.manager.throughput_color
width = self.canvas.throughput_width width = self.canvas.manager.throughput_width
else: else:
color = self.color color = self.color
width = self.scaled_width() width = self.scaled_width()

View file

@ -7,14 +7,7 @@ from typing import TYPE_CHECKING, Any, Dict, List, Optional, Set, Tuple
from PIL import Image from PIL import Image
from PIL.ImageTk import PhotoImage from PIL.ImageTk import PhotoImage
from core.api.grpc.wrappers import ( from core.api.grpc.wrappers import Interface, Link, LinkType, Node, Session
Interface,
Link,
LinkType,
Node,
Session,
ThroughputsEvent,
)
from core.gui import appconfig from core.gui import appconfig
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
@ -90,11 +83,6 @@ class CanvasGraph(tk.Canvas):
self.scale_option: tk.IntVar = tk.IntVar(value=1) self.scale_option: tk.IntVar = tk.IntVar(value=1)
self.adjust_to_dim: tk.BooleanVar = tk.BooleanVar(value=False) self.adjust_to_dim: tk.BooleanVar = tk.BooleanVar(value=False)
# throughput related
self.throughput_threshold: float = 250.0
self.throughput_width: int = 10
self.throughput_color: str = "#FF0000"
# bindings # bindings
self.setup_bindings() self.setup_bindings()
@ -171,16 +159,6 @@ class CanvasGraph(tk.Canvas):
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: ThroughputsEvent) -> None:
for iface_throughput in throughputs_event.iface_throughputs:
node_id = iface_throughput.node_id
iface_id = iface_throughput.iface_id
throughput = iface_throughput.throughput
iface_to_edge_id = (node_id, iface_id)
edge = self.core.iface_to_edge.get(iface_to_edge_id)
if edge:
edge.set_throughput(throughput)
def draw_grid(self) -> None: def draw_grid(self) -> None:
""" """
Create grid. Create grid.

View file

@ -3,7 +3,7 @@ import tkinter as tk
from tkinter import BooleanVar, messagebox, ttk from tkinter import BooleanVar, messagebox, ttk
from typing import TYPE_CHECKING, Any, Dict, Optional, Set, Tuple, ValuesView from typing import TYPE_CHECKING, Any, Dict, Optional, Set, Tuple, ValuesView
from core.api.grpc.wrappers import LinkType, Session from core.api.grpc.wrappers import LinkType, Session, ThroughputsEvent
from core.gui.graph import tags from core.gui.graph import tags
from core.gui.graph.enums import GraphMode from core.gui.graph.enums import GraphMode
from core.gui.graph.graph import CanvasGraph from core.gui.graph.graph import CanvasGraph
@ -74,6 +74,9 @@ class CanvasManager:
self.unique_ids: Dict[str, int] = {} self.unique_ids: Dict[str, int] = {}
self.draw() self.draw()
# start with a single tab by default
self.add_canvas()
def draw(self) -> None: def draw(self) -> None:
self.notebook = ttk.Notebook(self.master) self.notebook = ttk.Notebook(self.master)
self.notebook.grid(sticky=tk.NSEW, pady=1) self.notebook.grid(sticky=tk.NSEW, pady=1)
@ -225,3 +228,18 @@ class CanvasManager:
continue continue
canvas = self.get(canvas_id) canvas = self.get(canvas_id)
canvas.parse_metadata(canvas_config) canvas.parse_metadata(canvas_config)
def set_throughputs(self, throughputs_event: ThroughputsEvent):
for iface_throughput in throughputs_event.iface_throughputs:
node_id = iface_throughput.node_id
iface_id = iface_throughput.iface_id
throughput = iface_throughput.throughput
iface_to_edge_id = (node_id, iface_id)
edge = self.core.iface_to_edge.get(iface_to_edge_id)
if edge:
edge.set_throughput(throughput)
def clear_throughputs(self) -> None:
for canvas in self.all():
for edge in canvas.edges.values():
edge.clear_throughput()

View file

@ -45,7 +45,7 @@ class Menubar(tk.Menu):
super().__init__(app) super().__init__(app)
self.app: "Application" = app self.app: "Application" = app
self.core: CoreClient = app.core self.core: CoreClient = app.core
self.canvas_manager: CanvasManager = app.manager self.manager: CanvasManager = app.manager
self.recent_menu: Optional[tk.Menu] = None self.recent_menu: Optional[tk.Menu] = None
self.edit_menu: Optional[tk.Menu] = None self.edit_menu: Optional[tk.Menu] = None
self.observers_menu: Optional[ObserversMenu] = None self.observers_menu: Optional[ObserversMenu] = None
@ -148,52 +148,52 @@ class Menubar(tk.Menu):
menu.add_checkbutton( menu.add_checkbutton(
label="Interface Names", label="Interface Names",
command=self.click_edge_label_change, command=self.click_edge_label_change,
variable=self.canvas_manager.show_iface_names, variable=self.manager.show_iface_names,
) )
menu.add_checkbutton( menu.add_checkbutton(
label="IPv4 Addresses", label="IPv4 Addresses",
command=self.click_edge_label_change, command=self.click_edge_label_change,
variable=self.canvas_manager.show_ip4s, variable=self.manager.show_ip4s,
) )
menu.add_checkbutton( menu.add_checkbutton(
label="IPv6 Addresses", label="IPv6 Addresses",
command=self.click_edge_label_change, command=self.click_edge_label_change,
variable=self.canvas_manager.show_ip6s, variable=self.manager.show_ip6s,
) )
menu.add_checkbutton( menu.add_checkbutton(
label="Node Labels", label="Node Labels",
command=self.canvas_manager.show_node_labels.click_handler, command=self.manager.show_node_labels.click_handler,
variable=self.canvas_manager.show_node_labels, variable=self.manager.show_node_labels,
) )
menu.add_checkbutton( menu.add_checkbutton(
label="Link Labels", label="Link Labels",
command=self.canvas_manager.show_link_labels.click_handler, command=self.manager.show_link_labels.click_handler,
variable=self.canvas_manager.show_link_labels, variable=self.manager.show_link_labels,
) )
menu.add_checkbutton( menu.add_checkbutton(
label="Links", label="Links",
command=self.canvas_manager.show_links.click_handler, command=self.manager.show_links.click_handler,
variable=self.canvas_manager.show_links, variable=self.manager.show_links,
) )
menu.add_checkbutton( menu.add_checkbutton(
label="Loss Links", label="Loss Links",
command=self.canvas_manager.show_loss_links.click_handler, command=self.manager.show_loss_links.click_handler,
variable=self.canvas_manager.show_loss_links, variable=self.manager.show_loss_links,
) )
menu.add_checkbutton( menu.add_checkbutton(
label="Wireless Links", label="Wireless Links",
command=self.canvas_manager.show_wireless.click_handler, command=self.manager.show_wireless.click_handler,
variable=self.canvas_manager.show_wireless, variable=self.manager.show_wireless,
) )
menu.add_checkbutton( menu.add_checkbutton(
label="Annotations", label="Annotations",
command=self.canvas_manager.show_annotations.click_handler, command=self.manager.show_annotations.click_handler,
variable=self.canvas_manager.show_annotations, variable=self.manager.show_annotations,
) )
menu.add_checkbutton( menu.add_checkbutton(
label="Canvas Grid", label="Canvas Grid",
command=self.canvas_manager.show_grid.click_handler, command=self.manager.show_grid.click_handler,
variable=self.canvas_manager.show_grid, variable=self.manager.show_grid,
) )
self.add_cascade(label="View", menu=menu) self.add_cascade(label="View", menu=menu)
@ -376,10 +376,10 @@ class Menubar(tk.Menu):
dialog.show() dialog.show()
def click_canvas_add(self) -> None: def click_canvas_add(self) -> None:
self.canvas_manager.add_canvas() self.manager.add_canvas()
def click_canvas_delete(self) -> None: def click_canvas_delete(self) -> None:
self.canvas_manager.delete_canvas() self.manager.delete_canvas()
def click_canvas_size_and_scale(self) -> None: def click_canvas_size_and_scale(self) -> None:
dialog = SizeAndScaleDialog(self.app) dialog = SizeAndScaleDialog(self.app)
@ -448,14 +448,15 @@ class Menubar(tk.Menu):
dialog.show() dialog.show()
def click_autogrid(self) -> None: def click_autogrid(self) -> None:
width, height = self.canvas.current_dimensions width, height = self.manager.current_dimensions
padding = (ICON_SIZE / 2) + 10 padding = (ICON_SIZE / 2) + 10
layout_size = padding + ICON_SIZE layout_size = padding + ICON_SIZE
col_count = width // layout_size col_count = width // layout_size
logging.info( logging.info(
"auto grid layout: dimension(%s, %s) col(%s)", width, height, col_count "auto grid layout: dimension(%s, %s) col(%s)", width, height, col_count
) )
for i, node in enumerate(self.canvas.nodes.values()): canvas = self.manager.current()
for i, node in enumerate(canvas.nodes.values()):
col = i % col_count col = i % col_count
row = i // col_count row = i // col_count
x = (col * layout_size) + padding x = (col * layout_size) + padding