initial classes to help support creating layers for toggling visibility on the canvas for associated items

This commit is contained in:
Blake Harnden 2020-07-20 23:50:01 -07:00
parent 5e2ca0f549
commit f72d0d8a69
5 changed files with 176 additions and 0 deletions

View file

@ -0,0 +1,60 @@
import tkinter as tk
from tkinter import messagebox, ttk
from typing import TYPE_CHECKING, Optional
from core.gui.dialogs.dialog import Dialog
from core.gui.dialogs.simple import SimpleStringDialog
from core.gui.themes import PADX, PADY
from core.gui.widgets import ListboxScroll
if TYPE_CHECKING:
from core.gui.app import Application
class LayersDialog(Dialog):
def __init__(self, app: "Application") -> None:
super().__init__(app, "Canvas Layers", modal=False)
self.list: Optional[ListboxScroll] = None
self.draw()
def draw(self) -> None:
self.top.columnconfigure(0, weight=1)
self.list = ListboxScroll(self.top)
self.list.grid(sticky=tk.EW, pady=PADY)
for name in self.app.canvas.layers.names():
self.list.listbox.insert(tk.END, name)
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)
def click_add(self):
name = SimpleStringDialog(self, self.app, "Add Layer", "Layer Name").ask()
if name:
result = self.app.canvas.layers.add_layer(name)
if result:
self.list.listbox.insert(tk.END, name)
else:
messagebox.showerror(
"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 click_toggle(self):
selection = self.list.listbox.curselection()
if not selection:
return
name = self.list.listbox.get(selection)
print(name)

View file

@ -0,0 +1,48 @@
import tkinter as tk
from tkinter import ttk
from typing import TYPE_CHECKING, Optional
from core.gui.dialogs.dialog import Dialog
from core.gui.themes import PADX, PADY
if TYPE_CHECKING:
from core.gui.app import Application
class SimpleStringDialog(Dialog):
def __init__(
self, master: tk.BaseWidget, app: "Application", title: str, prompt: str
):
super().__init__(app, title, master=master)
self.prompt: str = prompt
self.value = tk.StringVar()
self.entry: Optional[ttk.Entry] = None
self.canceled = False
self.draw()
def draw(self) -> None:
self.top.columnconfigure(0, weight=1)
label = ttk.Label(self.top, text=self.prompt)
label.grid(sticky=tk.EW, pady=PADY)
entry = ttk.Entry(self.top, textvariable=self.value)
entry.grid(stick=tk.EW, pady=PADY)
entry.focus_set()
frame = ttk.Frame(self.top)
frame.grid(sticky=tk.EW)
for i in range(2):
frame.columnconfigure(i, weight=1)
button = ttk.Button(frame, text="Submit", command=self.destroy)
button.grid(row=0, column=0, sticky=tk.EW, padx=PADX)
button = ttk.Button(frame, text="Cancel", command=self.click_cancel)
button.grid(row=0, column=1, sticky=tk.EW)
def click_cancel(self):
self.canceled = True
self.destroy()
def ask(self) -> Optional[str]:
self.show()
if self.canceled:
return None
else:
return self.value.get()

View file

@ -25,6 +25,7 @@ from core.gui.graph.edges import (
create_edge_token, create_edge_token,
) )
from core.gui.graph.enums import GraphMode, ScaleOption from core.gui.graph.enums import GraphMode, ScaleOption
from core.gui.graph.layers import CanvasLayers
from core.gui.graph.node import CanvasNode from core.gui.graph.node import CanvasNode
from core.gui.graph.shape import Shape from core.gui.graph.shape import Shape
from core.gui.graph.shapeutils import ShapeType, is_draw_shape, is_marker from core.gui.graph.shapeutils import ShapeType, is_draw_shape, is_marker
@ -62,6 +63,7 @@ class CanvasGraph(tk.Canvas):
super().__init__(master, highlightthickness=0, background="#cccccc") super().__init__(master, highlightthickness=0, background="#cccccc")
self.app: "Application" = app self.app: "Application" = app
self.core: "CoreClient" = core self.core: "CoreClient" = core
self.layers = CanvasLayers(self)
self.mode: GraphMode = GraphMode.SELECT self.mode: GraphMode = GraphMode.SELECT
self.annotation_type: Optional[ShapeType] = None self.annotation_type: Optional[ShapeType] = None
self.selection: Dict[int, int] = {} self.selection: Dict[int, int] = {}

View file

@ -0,0 +1,58 @@
import tkinter as tk
from typing import TYPE_CHECKING, Dict, Iterable, Set
if TYPE_CHECKING:
from core.gui.graph.graph import CanvasGraph
class CanvasLayers:
def __init__(self, canvas: "CanvasGraph"):
self.canvas: "CanvasGraph" = canvas
self.layers: Dict[str, Set[int]] = {}
self.hidden: Set[str] = set()
def names(self) -> Iterable[str]:
return self.layers.keys()
def add_layer(self, name: str) -> bool:
if name in self.layers:
return False
else:
self.layers[name] = set()
return True
def delete_layer(self, name: str) -> None:
items = self.layers.pop(name, set())
hidden_items = self.all_hidden()
items -= hidden_items
self.canvas.config(items, state=tk.NORMAL)
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)
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)
def toggle_layer(self, name: str) -> None:
items = self.layers[name]
if name in self.hidden:
self.hidden.remove(name)
hidden_items = self.all_hidden()
items -= hidden_items
self.canvas.config(items, state=tk.NORMAL)
else:
self.hidden.add(name)
self.canvas.config(items, state=tk.HIDDEN)
def all_hidden(self) -> Set[int]:
items = set()
for name in self.hidden:
items |= self.layers[name]
return items

View file

@ -9,6 +9,7 @@ from PIL.ImageTk import PhotoImage
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
from core.gui.dialogs.layers import LayersDialog
from core.gui.dialogs.runtool import RunToolDialog from core.gui.dialogs.runtool import RunToolDialog
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
@ -237,6 +238,9 @@ class Toolbar(ttk.Frame):
"Annotation Tools", "Annotation Tools",
radio=True, radio=True,
) )
self.design_frame.create_button(
self.annotation_enum, self.show_layers, "Layers"
)
def draw_runtime_frame(self) -> None: def draw_runtime_frame(self) -> None:
self.runtime_frame = ButtonBar(self, self.app) self.runtime_frame = ButtonBar(self, self.app)
@ -256,6 +260,10 @@ class Toolbar(ttk.Frame):
ImageEnum.RUN, self.click_run_button, "Run Tool" ImageEnum.RUN, self.click_run_button, "Run Tool"
) )
def show_layers(self) -> None:
dialog = LayersDialog(self.app)
dialog.show()
def draw_node_picker(self) -> None: def draw_node_picker(self) -> None:
self.hide_marker() self.hide_marker()
self.app.canvas.mode = GraphMode.NODE self.app.canvas.mode = GraphMode.NODE