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:
super().__init__(app, "Canvas Layers", modal=False)
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()
def draw(self) -> None:
@ -23,18 +27,23 @@ class LayersDialog(Dialog):
self.list.grid(sticky=tk.EW, pady=PADY)
for name in self.app.canvas.layers.names():
self.list.listbox.insert(tk.END, name)
self.list.listbox.bind("<<ListboxSelect>>", self.list_select)
frame = ttk.Frame(self.top)
frame.grid(sticky=tk.EW)
for i in range(3):
frame.columnconfigure(i, weight=1)
button = ttk.Button(frame, text="Add", command=self.click_add)
button.grid(row=0, column=0, sticky=tk.EW, padx=PADX)
button = ttk.Button(frame, text="Delete", command=self.click_delete)
button.grid(row=0, column=1, sticky=tk.EW, padx=PADX)
button = ttk.Button(frame, text="Toggle", command=self.click_toggle)
button.grid(row=0, column=2, sticky=tk.EW)
self.delete_button = ttk.Button(
frame, text="Delete", command=self.click_delete, state=tk.DISABLED
)
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()
if name:
result = self.app.canvas.layers.add_layer(name)
@ -45,16 +54,21 @@ class LayersDialog(Dialog):
"Add Layer", f"Duplicate Layer: {name}", parent=self
)
def click_delete(self):
selection = self.list.listbox.curselection()
if not selection:
return
name = self.list.listbox.get(selection)
print(name)
def list_select(self, event: tk.Event) -> None:
self.selection_index = self.list.listbox.curselection()
if not self.selection_index:
self.selection = None
state = tk.DISABLED
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):
selection = self.list.listbox.curselection()
if not selection:
return
name = self.list.listbox.get(selection)
print(name)
def click_delete(self) -> None:
self.app.canvas.layers.delete_layer(self.selection)
self.list.listbox.delete(self.selection_index)
self.list.listbox.event_generate("<<ListboxSelect>>")
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
):
super().__init__(app, title, master=master)
self.bind("<Return>", lambda e: self.destroy())
self.prompt: str = prompt
self.value = tk.StringVar()
self.entry: Optional[ttk.Entry] = None

View file

@ -1,10 +1,40 @@
import tkinter as tk
from functools import partial
from typing import TYPE_CHECKING, Dict, Iterable, Set
from core.gui import themes
if TYPE_CHECKING:
from core.gui.app import Application
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:
def __init__(self, canvas: "CanvasGraph"):
self.canvas: "CanvasGraph" = canvas
@ -25,20 +55,24 @@ class CanvasLayers:
items = self.layers.pop(name, set())
hidden_items = self.all_hidden()
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:
if name in self.layers:
self.layers[name].add(item)
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:
if name in self.layers:
self.layers[name].remove(item)
hidden_items = self.all_hidden()
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:
items = self.layers[name]
@ -46,10 +80,12 @@ class CanvasLayers:
self.hidden.remove(name)
hidden_items = self.all_hidden()
items -= hidden_items
self.canvas.config(items, state=tk.NORMAL)
for item in items:
self.canvas.itemconfig(item, state=tk.NORMAL)
else:
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]:
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.graph import tags
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.images import ImageEnum
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="Delete", command=self.canvas_delete)
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)
def click_cut(self) -> None: