pygui: added layer menu to nodes, simple toggle support for nodes alone

This commit is contained in:
Blake Harnden 2020-07-21 09:16:00 -07:00
parent f72d0d8a69
commit 1f55432ba2
4 changed files with 77 additions and 22 deletions

View file

@ -15,6 +15,10 @@ class LayersDialog(Dialog):
def __init__(self, app: "Application") -> None: def __init__(self, app: "Application") -> None:
super().__init__(app, "Canvas Layers", modal=False) super().__init__(app, "Canvas Layers", modal=False)
self.list: Optional[ListboxScroll] = None self.list: Optional[ListboxScroll] = None
self.selection: Optional[str] = None
self.selection_index: Optional[int] = None
self.delete_button: Optional[ttk.Button] = None
self.toggle_button: Optional[ttk.Button] = None
self.draw() self.draw()
def draw(self) -> None: def draw(self) -> None:
@ -23,18 +27,23 @@ class LayersDialog(Dialog):
self.list.grid(sticky=tk.EW, pady=PADY) self.list.grid(sticky=tk.EW, pady=PADY)
for name in self.app.canvas.layers.names(): for name in self.app.canvas.layers.names():
self.list.listbox.insert(tk.END, name) self.list.listbox.insert(tk.END, name)
self.list.listbox.bind("<<ListboxSelect>>", self.list_select)
frame = ttk.Frame(self.top) frame = ttk.Frame(self.top)
frame.grid(sticky=tk.EW) frame.grid(sticky=tk.EW)
for i in range(3): for i in range(3):
frame.columnconfigure(i, weight=1) frame.columnconfigure(i, weight=1)
button = ttk.Button(frame, text="Add", command=self.click_add) button = ttk.Button(frame, text="Add", command=self.click_add)
button.grid(row=0, column=0, sticky=tk.EW, padx=PADX) button.grid(row=0, column=0, sticky=tk.EW, padx=PADX)
button = ttk.Button(frame, text="Delete", command=self.click_delete) self.delete_button = ttk.Button(
button.grid(row=0, column=1, sticky=tk.EW, padx=PADX) frame, text="Delete", command=self.click_delete, state=tk.DISABLED
button = ttk.Button(frame, text="Toggle", command=self.click_toggle) )
button.grid(row=0, column=2, sticky=tk.EW) self.delete_button.grid(row=0, column=1, sticky=tk.EW, padx=PADX)
self.toggle_button = ttk.Button(
frame, text="Toggle", command=self.click_toggle, state=tk.DISABLED
)
self.toggle_button.grid(row=0, column=2, sticky=tk.EW)
def click_add(self): def click_add(self) -> None:
name = SimpleStringDialog(self, self.app, "Add Layer", "Layer Name").ask() name = SimpleStringDialog(self, self.app, "Add Layer", "Layer Name").ask()
if name: if name:
result = self.app.canvas.layers.add_layer(name) result = self.app.canvas.layers.add_layer(name)
@ -45,16 +54,21 @@ class LayersDialog(Dialog):
"Add Layer", f"Duplicate Layer: {name}", parent=self "Add Layer", f"Duplicate Layer: {name}", parent=self
) )
def click_delete(self): def list_select(self, event: tk.Event) -> None:
selection = self.list.listbox.curselection() self.selection_index = self.list.listbox.curselection()
if not selection: if not self.selection_index:
return self.selection = None
name = self.list.listbox.get(selection) state = tk.DISABLED
print(name) else:
self.selection = self.list.listbox.get(self.selection_index)
state = tk.NORMAL
self.toggle_button.config(state=state)
self.delete_button.config(state=state)
def click_toggle(self): def click_delete(self) -> None:
selection = self.list.listbox.curselection() self.app.canvas.layers.delete_layer(self.selection)
if not selection: self.list.listbox.delete(self.selection_index)
return self.list.listbox.event_generate("<<ListboxSelect>>")
name = self.list.listbox.get(selection)
print(name) def click_toggle(self) -> None:
self.app.canvas.layers.toggle_layer(self.selection)

View file

@ -14,6 +14,7 @@ class SimpleStringDialog(Dialog):
self, master: tk.BaseWidget, app: "Application", title: str, prompt: str self, master: tk.BaseWidget, app: "Application", title: str, prompt: str
): ):
super().__init__(app, title, master=master) super().__init__(app, title, master=master)
self.bind("<Return>", lambda e: self.destroy())
self.prompt: str = prompt self.prompt: str = prompt
self.value = tk.StringVar() self.value = tk.StringVar()
self.entry: Optional[ttk.Entry] = None self.entry: Optional[ttk.Entry] = None

View file

@ -1,10 +1,40 @@
import tkinter as tk import tkinter as tk
from functools import partial
from typing import TYPE_CHECKING, Dict, Iterable, Set from typing import TYPE_CHECKING, Dict, Iterable, Set
from core.gui import themes
if TYPE_CHECKING: if TYPE_CHECKING:
from core.gui.app import Application
from core.gui.graph.graph import CanvasGraph from core.gui.graph.graph import CanvasGraph
class LayersMenu(tk.Menu):
def __init__(self, master: tk.BaseWidget, app: "Application", item: int) -> None:
super().__init__(master)
themes.style_menu(self)
self.app: "Application" = app
self.item: int = item
self.buttons: Dict[str, tk.BooleanVar] = {}
self.draw()
def draw(self) -> None:
for name in self.app.canvas.layers.names():
value = self.app.canvas.layers.in_layer(name, self.item)
var = tk.BooleanVar(value=value)
self.buttons[name] = var
self.add_checkbutton(
label=name, variable=var, command=partial(self.click_layer, name)
)
def click_layer(self, name):
value = self.buttons[name].get()
if value:
self.app.canvas.layers.add_item(name, self.item)
else:
self.app.canvas.layers.delete_item(name, self.item)
class CanvasLayers: class CanvasLayers:
def __init__(self, canvas: "CanvasGraph"): def __init__(self, canvas: "CanvasGraph"):
self.canvas: "CanvasGraph" = canvas self.canvas: "CanvasGraph" = canvas
@ -25,20 +55,24 @@ class CanvasLayers:
items = self.layers.pop(name, set()) items = self.layers.pop(name, set())
hidden_items = self.all_hidden() hidden_items = self.all_hidden()
items -= hidden_items items -= hidden_items
self.canvas.config(items, state=tk.NORMAL) for item in items:
self.canvas.itemconfig(item, state=tk.NORMAL)
def in_layer(self, name: str, item: int) -> bool:
return item in self.layers.get(name, set())
def add_item(self, name: str, item: int) -> None: def add_item(self, name: str, item: int) -> None:
if name in self.layers: if name in self.layers:
self.layers[name].add(item) self.layers[name].add(item)
if name in self.hidden: if name in self.hidden:
self.canvas.config(item, state=tk.HIDDEN) self.canvas.itemconfig(item, state=tk.HIDDEN)
def delete_item(self, name: str, item: int) -> None: def delete_item(self, name: str, item: int) -> None:
if name in self.layers: if name in self.layers:
self.layers[name].remove(item) self.layers[name].remove(item)
hidden_items = self.all_hidden() hidden_items = self.all_hidden()
if item not in hidden_items: if item not in hidden_items:
self.canvas.config(item, state=tk.NORMAL) self.canvas.itemconfig(item, state=tk.NORMAL)
def toggle_layer(self, name: str) -> None: def toggle_layer(self, name: str) -> None:
items = self.layers[name] items = self.layers[name]
@ -46,10 +80,12 @@ class CanvasLayers:
self.hidden.remove(name) self.hidden.remove(name)
hidden_items = self.all_hidden() hidden_items = self.all_hidden()
items -= hidden_items items -= hidden_items
self.canvas.config(items, state=tk.NORMAL) for item in items:
self.canvas.itemconfig(item, state=tk.NORMAL)
else: else:
self.hidden.add(name) self.hidden.add(name)
self.canvas.config(items, state=tk.HIDDEN) for item in items:
self.canvas.itemconfig(item, state=tk.HIDDEN)
def all_hidden(self) -> Set[int]: def all_hidden(self) -> Set[int]:
items = set() items = set()

View file

@ -19,6 +19,7 @@ from core.gui.dialogs.wlanconfig import WlanConfigDialog
from core.gui.frames.node import NodeInfoFrame from core.gui.frames.node import NodeInfoFrame
from core.gui.graph import tags from core.gui.graph import tags
from core.gui.graph.edges import CanvasEdge, CanvasWirelessEdge from core.gui.graph.edges import CanvasEdge, CanvasWirelessEdge
from core.gui.graph.layers import LayersMenu
from core.gui.graph.tooltip import CanvasTooltip from core.gui.graph.tooltip import CanvasTooltip
from core.gui.images import ImageEnum from core.gui.images import ImageEnum
from core.gui.nodeutils import ANTENNA_SIZE, NodeUtils from core.gui.nodeutils import ANTENNA_SIZE, NodeUtils
@ -271,6 +272,9 @@ class CanvasNode:
edit_menu.add_command(label="Copy", command=self.canvas_copy) edit_menu.add_command(label="Copy", command=self.canvas_copy)
edit_menu.add_command(label="Delete", command=self.canvas_delete) edit_menu.add_command(label="Delete", command=self.canvas_delete)
self.context.add_cascade(label="Edit", menu=edit_menu) self.context.add_cascade(label="Edit", menu=edit_menu)
layer_menu = LayersMenu(self.context, self.app, self.id)
self.context.add_cascade(label="Layer", menu=layer_menu)
self.context.tk_popup(event.x_root, event.y_root) self.context.tk_popup(event.x_root, event.y_root)
def click_cut(self) -> None: def click_cut(self) -> None: