From 2b3e071045f4aa3c4ad1199210c87ec27c7bd915 Mon Sep 17 00:00:00 2001 From: bharnden <32446120+bharnden@users.noreply.github.com> Date: Tue, 5 Nov 2019 22:44:50 -0800 Subject: [PATCH] updated nodeicondialog to just icondialog, added custom widgets for convenience, listboxscroll and checkboxlist --- coretk/coretk/dialogs/customnodes.py | 94 +++++++++++++++++++++++++--- coretk/coretk/dialogs/nodeconfig.py | 6 +- coretk/coretk/dialogs/nodeicon.py | 14 ++--- coretk/coretk/dialogs/wlanconfig.py | 6 +- coretk/coretk/widgets.py | 58 +++++++++++++++++ 5 files changed, 155 insertions(+), 23 deletions(-) create mode 100644 coretk/coretk/widgets.py diff --git a/coretk/coretk/dialogs/customnodes.py b/coretk/coretk/dialogs/customnodes.py index b38196fe..841b2dcf 100644 --- a/coretk/coretk/dialogs/customnodes.py +++ b/coretk/coretk/dialogs/customnodes.py @@ -1,6 +1,68 @@ import tkinter as tk from coretk.dialogs.dialog import Dialog +from coretk.dialogs.nodeicon import IconDialog +from coretk.widgets import CheckboxList, ListboxScroll + + +class ServicesSelectDialog(Dialog): + def __init__(self, master, app): + super().__init__(master, app, "Node Services", modal=True) + self.groups = None + self.services = None + self.current = None + self.current_services = set() + self.draw() + + def draw(self): + self.columnconfigure(0, weight=1) + self.rowconfigure(0, weight=1) + + frame = tk.Frame(self) + frame.grid(stick="nsew") + frame.rowconfigure(0, weight=1) + for i in range(3): + frame.columnconfigure(i, weight=1) + self.groups = ListboxScroll(frame, text="Groups") + self.groups.grid(row=0, column=0, sticky="nsew") + for group in sorted(self.app.core.services): + self.groups.listbox.insert(tk.END, group) + self.groups.listbox.bind("<>", self.handle_group_change) + + self.services = CheckboxList( + frame, text="Services", clicked=self.service_clicked + ) + self.services.grid(row=0, column=1, sticky="nsew") + + self.current = ListboxScroll(frame, text="Selected") + self.current.grid(row=0, column=2, sticky="nsew") + + frame = tk.Frame(self) + frame.grid(stick="ew") + for i in range(2): + frame.columnconfigure(i, weight=1) + button = tk.Button(frame, text="Save") + button.grid(row=0, column=0, sticky="ew") + button = tk.Button(frame, text="Cancel", command=self.destroy) + button.grid(row=0, column=1, sticky="ew") + + def handle_group_change(self, event): + selection = self.groups.listbox.curselection() + if selection: + index = selection[0] + group = self.groups.listbox.get(index) + self.services.clear() + for service in sorted(self.app.core.services[group], key=lambda x: x.name): + self.services.add(service.name) + + def service_clicked(self, name, var): + if var.get() and name not in self.current_services: + self.current_services.add(name) + elif not var.get() and name in self.current_services: + self.current_services.remove(name) + self.current.listbox.delete(0, tk.END) + for name in sorted(self.current_services): + self.current.listbox.insert(tk.END, name) class CustomNodesDialog(Dialog): @@ -8,6 +70,9 @@ class CustomNodesDialog(Dialog): super().__init__(master, app, "Custom Nodes", modal=True) self.save_button = None self.delete_button = None + self.name = tk.StringVar() + self.image_button = None + self.image = None self.draw() def draw(self): @@ -26,20 +91,20 @@ class CustomNodesDialog(Dialog): scrollbar = tk.Scrollbar(frame, orient=tk.VERTICAL) scrollbar.grid(row=0, column=1, sticky="ns") - listbox = tk.Listbox(frame) - listbox.grid( - row=0, - column=0, - selectmode=tk.SINGLE, - yscrollcommand=scrollbar.set, - sticky="nsew", - ) + listbox = tk.Listbox(frame, selectmode=tk.SINGLE, yscrollcommand=scrollbar.set) + listbox.grid(row=0, column=0, sticky="nsew") scrollbar.config(command=listbox.yview) frame = tk.Frame(frame) frame.grid(row=0, column=2, sticky="nsew") frame.columnconfigure(0, weight=1) + entry = tk.Entry(frame, textvariable=self.name) + entry.grid(sticky="ew") + self.image_button = tk.Button(frame, text="Icon", command=self.click_icon) + self.image_button.grid(sticky="ew") + button = tk.Button(frame, text="Services", command=self.click_services) + button.grid(sticky="ew") def draw_node_buttons(self): frame = tk.Frame(self) @@ -66,12 +131,23 @@ class CustomNodesDialog(Dialog): for i in range(2): frame.columnconfigure(i, weight=1) - button = tk.Button(frame, text="Save Configuration") + button = tk.Button(frame, text="Save", command=self.click_save) button.grid(row=0, column=0, sticky="ew") button = tk.Button(frame, text="Cancel", command=self.destroy) button.grid(row=0, column=1, sticky="ew") + def click_icon(self): + dialog = IconDialog(self, self.app, self.name.get(), self.image) + dialog.show() + if dialog.image: + self.image = dialog.image + self.image_button.config(image=self.image) + + def click_services(self): + dialog = ServicesSelectDialog(self, self.app) + dialog.show() + def click_create(self): pass diff --git a/coretk/coretk/dialogs/nodeconfig.py b/coretk/coretk/dialogs/nodeconfig.py index b8548c51..bc03dc51 100644 --- a/coretk/coretk/dialogs/nodeconfig.py +++ b/coretk/coretk/dialogs/nodeconfig.py @@ -2,7 +2,7 @@ import tkinter as tk from tkinter import ttk from coretk.dialogs.dialog import Dialog -from coretk.dialogs.nodeicon import NodeIconDialog +from coretk.dialogs.nodeicon import IconDialog from coretk.dialogs.nodeservice import NodeServicesDialog NETWORKNODETYPES = ["switch", "hub", "wlan", "rj45", "tunnel"] @@ -91,7 +91,9 @@ class NodeConfigDialog(Dialog): dialog.show() def click_icon(self): - dialog = NodeIconDialog(self, self.app, self.canvas_node) + dialog = IconDialog( + self, self.app, self.canvas_node.name, self.canvas_node.image + ) dialog.show() if dialog.image: self.image = dialog.image diff --git a/coretk/coretk/dialogs/nodeicon.py b/coretk/coretk/dialogs/nodeicon.py index d82c0756..4d26e29f 100644 --- a/coretk/coretk/dialogs/nodeicon.py +++ b/coretk/coretk/dialogs/nodeicon.py @@ -6,18 +6,12 @@ from coretk.dialogs.dialog import Dialog from coretk.images import Images -class NodeIconDialog(Dialog): - def __init__(self, master, app, canvas_node): - """ - create an instance of ImageModification - :param master: dialog master - :param coretk.app.Application: main app - :param coretk.graph.CanvasNode canvas_node: node object - """ - super().__init__(master, app, f"{canvas_node.name} Icon", modal=True) +class IconDialog(Dialog): + def __init__(self, master, app, name, image): + super().__init__(master, app, f"{name} Icon", modal=True) self.file_path = tk.StringVar() self.image_label = None - self.image = canvas_node.image + self.image = image self.draw() def draw(self): diff --git a/coretk/coretk/dialogs/wlanconfig.py b/coretk/coretk/dialogs/wlanconfig.py index ad10bf40..d57c8935 100644 --- a/coretk/coretk/dialogs/wlanconfig.py +++ b/coretk/coretk/dialogs/wlanconfig.py @@ -5,7 +5,7 @@ wlan configuration import tkinter as tk from coretk.dialogs.dialog import Dialog -from coretk.dialogs.nodeicon import NodeIconDialog +from coretk.dialogs.nodeicon import IconDialog class WlanConfigDialog(Dialog): @@ -167,7 +167,9 @@ class WlanConfigDialog(Dialog): button.grid(row=0, column=1, padx=2, sticky="ew") def click_icon(self): - dialog = NodeIconDialog(self, self.app, self.canvas_node) + dialog = IconDialog( + self, self.app, self.canvas_node.name, self.canvas_node.image + ) dialog.show() if dialog.image: self.image = dialog.image diff --git a/coretk/coretk/widgets.py b/coretk/coretk/widgets.py new file mode 100644 index 00000000..80347e73 --- /dev/null +++ b/coretk/coretk/widgets.py @@ -0,0 +1,58 @@ +import tkinter as tk +from functools import partial + + +class ListboxScroll(tk.LabelFrame): + def __init__(self, master=None, cnf={}, **kw): + super().__init__(master, cnf, **kw) + self.columnconfigure(0, weight=1) + self.rowconfigure(0, weight=1) + self.scrollbar = tk.Scrollbar(self, orient=tk.VERTICAL) + self.scrollbar.grid(row=0, column=1, sticky="ns") + self.listbox = tk.Listbox( + self, selectmode=tk.SINGLE, yscrollcommand=self.scrollbar.set + ) + self.listbox.grid(row=0, column=0, sticky="nsew") + self.scrollbar.config(command=self.listbox.yview) + + +class CheckboxList(tk.LabelFrame): + def __init__(self, master=None, cnf={}, clicked=None, **kw): + super().__init__(master, cnf, **kw) + self.clicked = clicked + self.rowconfigure(0, weight=1) + self.columnconfigure(0, weight=1) + self.columnconfigure(1, weight=1) + self.canvas = tk.Canvas(self, highlightthickness=0) + self.canvas.grid(row=0, columnspan=2, sticky="nsew", padx=2, pady=2) + self.canvas.columnconfigure(0, weight=1) + self.canvas.rowconfigure(0, weight=1) + self.scrollbar = tk.Scrollbar( + self, orient="vertical", command=self.canvas.yview + ) + self.scrollbar.grid(row=0, column=2, sticky="ns") + self.frame = tk.Frame(self.canvas, padx=2, pady=2) + self.frame.columnconfigure(0, weight=1) + self.frame_id = self.canvas.create_window(0, 0, anchor="nw", window=self.frame) + self.canvas.update_idletasks() + self.canvas.configure( + scrollregion=self.canvas.bbox("all"), yscrollcommand=self.scrollbar.set + ) + self.frame.bind( + "", + lambda event: self.canvas.configure(scrollregion=self.canvas.bbox("all")), + ) + self.canvas.bind( + "", + lambda event: self.canvas.itemconfig(self.frame_id, width=event.width), + ) + + def clear(self): + for widget in self.frame.winfo_children(): + widget.destroy() + + def add(self, name): + var = tk.BooleanVar() + func = partial(self.clicked, name, var) + checkbox = tk.Checkbutton(self.frame, text=name, variable=var, command=func) + checkbox.grid(sticky="w")