From 44df926fb9d221fb0c4415d52d121144c1e84ae2 Mon Sep 17 00:00:00 2001 From: Blake Harnden <32446120+bharnden@users.noreply.github.com> Date: Mon, 16 Dec 2019 12:21:03 -0800 Subject: [PATCH 1/7] updated events streamed from sessions to include session id for easy identification --- coretk/coretk/coreclient.py | 18 ++++++++++++++++-- daemon/core/api/grpc/events.py | 11 +---------- daemon/proto/core/api/grpc/core.proto | 25 +++++++++++-------------- daemon/tests/test_grpc.py | 7 +++++++ 4 files changed, 35 insertions(+), 26 deletions(-) diff --git a/coretk/coretk/coreclient.py b/coretk/coretk/coreclient.py index b1d4d22f..8b01a468 100644 --- a/coretk/coretk/coreclient.py +++ b/coretk/coretk/coreclient.py @@ -20,6 +20,7 @@ from coretk.graph.shapeutils import ShapeType from coretk.interface import InterfaceManager from coretk.nodeutils import NodeDraw, NodeUtils +GUI_SOURCE = "gui" OBSERVERS = { "processes": "ps", "ifconfig": "ifconfig", @@ -133,6 +134,14 @@ class CoreClient: self.custom_observers[observer.name] = observer def handle_events(self, event): + if event.session_id != self.session_id: + logging.warn( + "ignoring event session(%s) current(%s)", + event.session_id, + self.session_id, + ) + return + if event.HasField("link_event"): logging.info("link event: %s", event) self.handle_link_event(event.link_event) @@ -176,7 +185,7 @@ class CoreClient: logging.warning("unknown link event: %s", event.message_type) def handle_node_event(self, event): - if event.source == "gui": + if event.source == GUI_SOURCE: return node_id = event.node.id x = event.node.position.x @@ -195,6 +204,11 @@ class CoreClient: def handle_throughputs(self, event): if event.session_id != self.session_id: + logging.warn( + "ignoring throughput event session(%s) current(%s)", + event.session_id, + self.session_id, + ) return logging.info("handling throughputs event: %s", event) self.app.canvas.throughput_draw.process_grpc_throughput_event( @@ -424,7 +438,7 @@ class CoreClient: def edit_node(self, core_node): try: self.client.edit_node( - self.session_id, core_node.id, core_node.position, source="gui" + self.session_id, core_node.id, core_node.position, source=GUI_SOURCE ) except grpc.RpcError as e: show_grpc_error(e) diff --git a/daemon/core/api/grpc/events.py b/daemon/core/api/grpc/events.py index d7a3094e..7b4756b1 100644 --- a/daemon/core/api/grpc/events.py +++ b/daemon/core/api/grpc/events.py @@ -107,7 +107,6 @@ def handle_session_event(event): name=event.name, data=event.data, time=event_time, - session_id=event.session, ) @@ -119,9 +118,6 @@ def handle_config_event(event): :return: configuration event :rtype: core.api.grpc.core_pb2.ConfigEvent """ - session_id = None - if event.session is not None: - session_id = int(event.session) return core_pb2.ConfigEvent( message_type=event.message_type, node_id=event.node, @@ -132,7 +128,6 @@ def handle_config_event(event): data_values=event.data_values, possible_values=event.possible_values, groups=event.groups, - session_id=session_id, interface=event.interface_number, network_id=event.network_id, opaque=event.opaque, @@ -150,7 +145,6 @@ def handle_exception_event(event): """ return core_pb2.ExceptionEvent( node_id=event.node, - session_id=int(event.session), level=event.level, source=event.source, date=event.date, @@ -175,7 +169,6 @@ def handle_file_event(event): number=event.number, type=event.type, source=event.source, - session_id=event.session, data=event.data, compressed_data=event.compressed_data, ) @@ -224,7 +217,7 @@ class EventStreamer: :return: grpc event, or None when invalid event or queue timeout :rtype: core.api.grpc.core_pb2.Event """ - event = core_pb2.Event() + event = core_pb2.Event(session_id=self.session.id) try: data = self.queue.get(timeout=1) if isinstance(data, NodeData): @@ -235,8 +228,6 @@ class EventStreamer: event.session_event.CopyFrom(handle_session_event(data)) elif isinstance(data, ConfigData): event.config_event.CopyFrom(handle_config_event(data)) - # TODO: remove when config events are fixed - event.config_event.session_id = self.session.id elif isinstance(data, ExceptionData): event.exception_event.CopyFrom(handle_exception_event(data)) elif isinstance(data, FileData): diff --git a/daemon/proto/core/api/grpc/core.proto b/daemon/proto/core/api/grpc/core.proto index ee099b31..ec7bf49c 100644 --- a/daemon/proto/core/api/grpc/core.proto +++ b/daemon/proto/core/api/grpc/core.proto @@ -301,6 +301,7 @@ message Event { ExceptionEvent exception_event = 5; FileEvent file_event = 6; } + int32 session_id = 7; } message NodeEvent { @@ -319,7 +320,6 @@ message SessionEvent { string name = 3; string data = 4; float time = 5; - int32 session_id = 6; } message ConfigEvent { @@ -333,20 +333,18 @@ message ConfigEvent { string bitmap = 8; string possible_values = 9; string groups = 10; - int32 session_id = 11; - int32 interface = 12; - int32 network_id = 13; - string opaque = 14; + int32 interface = 11; + int32 network_id = 12; + string opaque = 13; } message ExceptionEvent { int32 node_id = 1; - int32 session_id = 2; - ExceptionLevel.Enum level = 3; - string source = 4; - string date = 5; - string text = 6; - string opaque = 7; + ExceptionLevel.Enum level = 2; + string source = 3; + string date = 4; + string text = 5; + string opaque = 6; } message FileEvent { @@ -357,9 +355,8 @@ message FileEvent { int32 number = 5; string type = 6; string source = 7; - int32 session_id = 8; - string data = 9; - string compressed_data = 10; + string data = 8; + string compressed_data = 9; } message AddNodeRequest { diff --git a/daemon/tests/test_grpc.py b/daemon/tests/test_grpc.py index 72e469f3..89e46f9b 100644 --- a/daemon/tests/test_grpc.py +++ b/daemon/tests/test_grpc.py @@ -990,6 +990,7 @@ class TestGrpc: queue = Queue() def handle_event(event_data): + assert event_data.session_id == session.id assert event_data.HasField("node_event") queue.put(event_data) @@ -1014,6 +1015,7 @@ class TestGrpc: queue = Queue() def handle_event(event_data): + assert event_data.session_id == session.id assert event_data.HasField("link_event") queue.put(event_data) @@ -1036,6 +1038,7 @@ class TestGrpc: queue = Queue() def handle_event(event_data): + assert event_data.session_id == session.id queue.put(event_data) # then @@ -1053,6 +1056,7 @@ class TestGrpc: queue = Queue() def handle_event(event_data): + assert event_data.session_id == session.id assert event_data.HasField("session_event") queue.put(event_data) @@ -1075,6 +1079,7 @@ class TestGrpc: queue = Queue() def handle_event(event_data): + assert event_data.session_id == session.id assert event_data.HasField("config_event") queue.put(event_data) @@ -1098,6 +1103,7 @@ class TestGrpc: queue = Queue() def handle_event(event_data): + assert event_data.session_id == session.id assert event_data.HasField("exception_event") queue.put(event_data) @@ -1120,6 +1126,7 @@ class TestGrpc: queue = Queue() def handle_event(event_data): + assert event_data.session_id == session.id assert event_data.HasField("file_event") queue.put(event_data) From 585d10dd28a9fb74d00d6c43f97819e7e2ab04ae Mon Sep 17 00:00:00 2001 From: Blake Harnden <32446120+bharnden@users.noreply.github.com> Date: Mon, 16 Dec 2019 12:34:22 -0800 Subject: [PATCH 2/7] small tweaks to alert dialog --- coretk/coretk/dialogs/alerts.py | 21 ++++++++++----------- 1 file changed, 10 insertions(+), 11 deletions(-) diff --git a/coretk/coretk/dialogs/alerts.py b/coretk/coretk/dialogs/alerts.py index 58f65933..89e78f02 100644 --- a/coretk/coretk/dialogs/alerts.py +++ b/coretk/coretk/dialogs/alerts.py @@ -24,10 +24,11 @@ class AlertsDialog(Dialog): self.top.columnconfigure(0, weight=1) self.top.rowconfigure(0, weight=1) self.top.rowconfigure(1, weight=1) - row = 0 + frame = ttk.Frame(self.top) frame.columnconfigure(0, weight=1) - frame.grid(row=row, column=0, sticky="nsew", pady=PADY) + frame.rowconfigure(0, weight=1) + frame.grid(sticky="nsew", pady=PADY) self.tree = ttk.Treeview( frame, columns=("time", "level", "session_id", "node", "source"), @@ -35,15 +36,15 @@ class AlertsDialog(Dialog): ) self.tree.grid(row=0, column=0, sticky="nsew") self.tree.column("time", stretch=tk.YES) - self.tree.heading("time", text="time", anchor="w") + self.tree.heading("time", text="Time") self.tree.column("level", stretch=tk.YES) - self.tree.heading("level", text="level", anchor="w") + self.tree.heading("level", text="Level") self.tree.column("session_id", stretch=tk.YES) - self.tree.heading("session_id", text="session id", anchor="w") + self.tree.heading("session_id", text="Session ID") self.tree.column("node", stretch=tk.YES) - self.tree.heading("node", text="node", anchor="w") + self.tree.heading("node", text="Node") self.tree.column("source", stretch=tk.YES) - self.tree.heading("source", text="source", anchor="w") + self.tree.heading("source", text="Source") self.tree.bind("<>", self.click_select) for alarm in self.app.statusbar.core_alarms: @@ -74,15 +75,13 @@ class AlertsDialog(Dialog): xscrollbar = ttk.Scrollbar(frame, orient="horizontal", command=self.tree.xview) xscrollbar.grid(row=1, sticky="ew") self.tree.configure(xscrollcommand=xscrollbar.set) - row = row + 1 self.text = CodeText(self.top) self.text.config(state=tk.DISABLED) - self.text.grid(row=row, column=0, sticky="nsew", pady=PADY) - row = row + 1 + self.text.grid(sticky="nsew", pady=PADY) frame = ttk.Frame(self.top) - frame.grid(row=row, column=0, sticky="nsew") + frame.grid(sticky="ew") frame.columnconfigure(0, weight=1) frame.columnconfigure(1, weight=1) frame.columnconfigure(2, weight=1) From 713c42a64edfcb79c316d24d5e9b5b8621d3c02b Mon Sep 17 00:00:00 2001 From: Blake Harnden <32446120+bharnden@users.noreply.github.com> Date: Mon, 16 Dec 2019 13:11:23 -0800 Subject: [PATCH 3/7] added styling for listboxes, made use of listbox scroll where all other basic listboxes were being used --- coretk/coretk/dialogs/hooks.py | 7 ++++--- coretk/coretk/dialogs/observers.py | 19 ++++++------------- coretk/coretk/dialogs/servers.py | 18 ++++++------------ coretk/coretk/themes.py | 17 ++++++++++++++++- coretk/coretk/widgets.py | 2 ++ 5 files changed, 34 insertions(+), 29 deletions(-) diff --git a/coretk/coretk/dialogs/hooks.py b/coretk/coretk/dialogs/hooks.py index 40101823..9aeebecc 100644 --- a/coretk/coretk/dialogs/hooks.py +++ b/coretk/coretk/dialogs/hooks.py @@ -4,7 +4,7 @@ from tkinter import ttk from core.api.grpc import core_pb2 from coretk.dialogs.dialog import Dialog from coretk.themes import PADX, PADY -from coretk.widgets import CodeText +from coretk.widgets import CodeText, ListboxScroll class HookDialog(Dialog): @@ -96,8 +96,9 @@ class HooksDialog(Dialog): self.top.columnconfigure(0, weight=1) self.top.rowconfigure(0, weight=1) - self.listbox = tk.Listbox(self.top) - self.listbox.grid(sticky="nsew", pady=PADY) + listbox_scroll = ListboxScroll(self.top) + listbox_scroll.grid(sticky="nsew", pady=PADY) + self.listbox = listbox_scroll.listbox self.listbox.bind("<>", self.select) for hook_file in self.app.core.hooks: self.listbox.insert(tk.END, hook_file) diff --git a/coretk/coretk/dialogs/observers.py b/coretk/coretk/dialogs/observers.py index f496f7ef..de857b76 100644 --- a/coretk/coretk/dialogs/observers.py +++ b/coretk/coretk/dialogs/observers.py @@ -4,6 +4,7 @@ from tkinter import ttk from coretk.coreclient import Observer from coretk.dialogs.dialog import Dialog from coretk.themes import PADX, PADY +from coretk.widgets import ListboxScroll class ObserverDialog(Dialog): @@ -27,24 +28,16 @@ class ObserverDialog(Dialog): self.draw_apply_buttons() def draw_listbox(self): - frame = ttk.Frame(self.top) - frame.grid(sticky="nsew", pady=PADY) - frame.columnconfigure(0, weight=1) - frame.rowconfigure(0, weight=1) - - scrollbar = ttk.Scrollbar(frame, orient=tk.VERTICAL) - scrollbar.grid(row=0, column=1, sticky="ns") - - self.observers = tk.Listbox( - frame, selectmode=tk.SINGLE, yscrollcommand=scrollbar.set - ) + listbox_scroll = ListboxScroll(self.top) + listbox_scroll.grid(sticky="nsew", pady=PADY) + listbox_scroll.columnconfigure(0, weight=1) + listbox_scroll.rowconfigure(0, weight=1) + self.observers = listbox_scroll.listbox self.observers.grid(row=0, column=0, sticky="nsew") self.observers.bind("<>", self.handle_observer_change) for name in sorted(self.app.core.custom_observers): self.observers.insert(tk.END, name) - scrollbar.config(command=self.observers.yview) - def draw_form_fields(self): frame = ttk.Frame(self.top) frame.grid(sticky="ew", pady=PADY) diff --git a/coretk/coretk/dialogs/servers.py b/coretk/coretk/dialogs/servers.py index ef406ecb..c380c63d 100644 --- a/coretk/coretk/dialogs/servers.py +++ b/coretk/coretk/dialogs/servers.py @@ -4,6 +4,7 @@ from tkinter import ttk from coretk.coreclient import CoreServer from coretk.dialogs.dialog import Dialog from coretk.themes import FRAME_PAD, PADX, PADY +from coretk.widgets import ListboxScroll DEFAULT_NAME = "example" DEFAULT_ADDRESS = "127.0.0.1" @@ -32,25 +33,18 @@ class ServersDialog(Dialog): self.draw_apply_buttons() def draw_servers(self): - frame = ttk.Frame(self.top) - frame.grid(pady=PADY, sticky="nsew") - frame.columnconfigure(0, weight=1) - frame.rowconfigure(0, weight=1) + listbox_scroll = ListboxScroll(self.top) + listbox_scroll.grid(pady=PADY, sticky="nsew") + listbox_scroll.columnconfigure(0, weight=1) + listbox_scroll.rowconfigure(0, weight=1) - scrollbar = ttk.Scrollbar(frame, orient=tk.VERTICAL) - scrollbar.grid(row=0, column=1, sticky="ns") - - self.servers = tk.Listbox( - frame, selectmode=tk.SINGLE, yscrollcommand=scrollbar.set - ) + self.servers = listbox_scroll.listbox self.servers.grid(row=0, column=0, sticky="nsew") self.servers.bind("<>", self.handle_server_change) for server in self.app.core.servers: self.servers.insert(tk.END, server) - scrollbar.config(command=self.servers.yview) - def draw_server_configuration(self): frame = ttk.LabelFrame(self.top, text="Server Configuration", padding=FRAME_PAD) frame.grid(pady=PADY, sticky="ew") diff --git a/coretk/coretk/themes.py b/coretk/coretk/themes.py index 43b59ffd..685a8350 100644 --- a/coretk/coretk/themes.py +++ b/coretk/coretk/themes.py @@ -1,5 +1,6 @@ import logging import tkinter as tk +from tkinter import ttk THEME_DARK = "black" PADX = (0, 5) @@ -160,7 +161,21 @@ def update_menu(style, widget): if not abg: abg = bg widget.config( - background=bg, foreground=fg, activebackground=abg, activeforeground=fg + background=bg, foreground=fg, activebackground=abg, activeforeground=fg, bd=0 + ) + + +def update_listbox(widget): + style = ttk.Style() + bg = style.lookup(".", "background") + fg = style.lookup(".", "foreground") + widget.config( + background=bg, + foreground=fg, + highlightthickness=1, + highlightcolor="black", + highlightbackground="black", + bd=0, ) diff --git a/coretk/coretk/widgets.py b/coretk/coretk/widgets.py index 349401c5..a00b590a 100644 --- a/coretk/coretk/widgets.py +++ b/coretk/coretk/widgets.py @@ -5,6 +5,7 @@ from tkinter import filedialog, font, ttk from tkinter.scrolledtext import ScrolledText from core.api.grpc import core_pb2 +from coretk import themes from coretk.appconfig import ICONS_PATH from coretk.themes import FRAME_PAD, PADX, PADY @@ -184,6 +185,7 @@ class ListboxScroll(ttk.LabelFrame): self.listbox = tk.Listbox( self, selectmode=tk.SINGLE, yscrollcommand=self.scrollbar.set ) + themes.update_listbox(self.listbox) self.listbox.grid(row=0, column=0, sticky="nsew") self.scrollbar.config(command=self.listbox.yview) From 69494b600f31d2d3c411274a9e29904b08760ad0 Mon Sep 17 00:00:00 2001 From: Blake Harnden <32446120+bharnden@users.noreply.github.com> Date: Mon, 16 Dec 2019 13:26:55 -0800 Subject: [PATCH 4/7] fixes for parsing grpc throughputs --- daemon/core/api/grpc/server.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/daemon/core/api/grpc/server.py b/daemon/core/api/grpc/server.py index 53c1d6d6..068d3eeb 100644 --- a/daemon/core/api/grpc/server.py +++ b/daemon/core/api/grpc/server.py @@ -27,7 +27,7 @@ from core.nodes.lxd import LxcNode from core.services.coreservices import ServiceManager _ONE_DAY_IN_SECONDS = 60 * 60 * 24 -_INTERFACE_REGEX = re.compile(r"[0-9a-fA-F]+") +_INTERFACE_REGEX = re.compile(r"veth(?P[0-9a-fA-F]+)") class CoreGrpcServer(core_pb2_grpc.CoreApiServicer): @@ -479,7 +479,8 @@ class CoreGrpcServer(core_pb2_grpc.CoreApiServicer): throughput = rx_kbps + tx_kbps if key.startswith("veth"): key = key.split(".") - node_id = int(_INTERFACE_REGEX.search(key[0]).group(), base=16) + node_id = _INTERFACE_REGEX.search(key[0]).group("node") + node_id = int(node_id, base=16) interface_id = int(key[1], base=16) session_id = int(key[2], base=16) if session.id != session_id: From c4f21e8a2ee12f7797594715f910b3721e16eb8a Mon Sep 17 00:00:00 2001 From: Blake Harnden <32446120+bharnden@users.noreply.github.com> Date: Mon, 16 Dec 2019 14:17:05 -0800 Subject: [PATCH 5/7] cleaned up listboxscroll widgets to not default to a labeleframe, updated code that really needed a lebelframe --- coretk/coretk/dialogs/customnodes.py | 22 ++++++++++----- coretk/coretk/dialogs/nodeservice.py | 16 ++++++++--- coretk/coretk/dialogs/serviceconfiguration.py | 28 ++++++++++++------- coretk/coretk/widgets.py | 2 +- 4 files changed, 46 insertions(+), 22 deletions(-) diff --git a/coretk/coretk/dialogs/customnodes.py b/coretk/coretk/dialogs/customnodes.py index 6aabf417..7effd11a 100644 --- a/coretk/coretk/dialogs/customnodes.py +++ b/coretk/coretk/dialogs/customnodes.py @@ -24,13 +24,17 @@ class ServicesSelectDialog(Dialog): self.top.columnconfigure(0, weight=1) self.top.rowconfigure(0, weight=1) - frame = ttk.Frame(self.top) + frame = ttk.LabelFrame(self.top) frame.grid(stick="nsew", pady=PADY) frame.rowconfigure(0, weight=1) for i in range(3): frame.columnconfigure(i, weight=1) - self.groups = ListboxScroll(frame, text="Groups", padding=FRAME_PAD) - self.groups.grid(row=0, column=0, sticky="nsew") + label_frame = ttk.LabelFrame(frame, text="Groups", padding=FRAME_PAD) + label_frame.grid(row=0, column=0, sticky="nsew") + label_frame.rowconfigure(0, weight=1) + label_frame.columnconfigure(0, weight=1) + self.groups = ListboxScroll(label_frame) + self.groups.grid(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) @@ -45,8 +49,12 @@ class ServicesSelectDialog(Dialog): ) self.services.grid(row=0, column=1, sticky="nsew") - self.current = ListboxScroll(frame, text="Selected", padding=FRAME_PAD) - self.current.grid(row=0, column=2, sticky="nsew") + label_frame = ttk.LabelFrame(frame, text="Selected", padding=FRAME_PAD) + label_frame.grid(row=0, column=2, sticky="nsew") + label_frame.rowconfigure(0, weight=1) + label_frame.columnconfigure(0, weight=1) + self.current = ListboxScroll(label_frame) + self.current.grid(sticky="nsew") for service in sorted(self.current_services): self.current.listbox.insert(tk.END, service) @@ -109,12 +117,12 @@ class CustomNodesDialog(Dialog): self.draw_buttons() def draw_node_config(self): - frame = ttk.Frame(self.top) + frame = ttk.LabelFrame(self.top, text="Nodes", padding=FRAME_PAD) frame.grid(sticky="nsew", pady=PADY) frame.columnconfigure(0, weight=1) frame.rowconfigure(0, weight=1) - self.nodes_list = ListboxScroll(frame, text="Nodes", padding=FRAME_PAD) + self.nodes_list = ListboxScroll(frame) self.nodes_list.grid(row=0, column=0, sticky="nsew", padx=PADX) self.nodes_list.listbox.bind("<>", self.handle_node_select) for name in sorted(self.app.core.custom_nodes): diff --git a/coretk/coretk/dialogs/nodeservice.py b/coretk/coretk/dialogs/nodeservice.py index 2aa9c6ad..59b8865b 100644 --- a/coretk/coretk/dialogs/nodeservice.py +++ b/coretk/coretk/dialogs/nodeservice.py @@ -40,8 +40,12 @@ class NodeService(Dialog): frame.rowconfigure(0, weight=1) for i in range(3): frame.columnconfigure(i, weight=1) - self.groups = ListboxScroll(frame, text="Groups", padding=FRAME_PAD) - self.groups.grid(row=0, column=0, sticky="nsew") + label_frame = ttk.LabelFrame(frame, text="Groups", padding=FRAME_PAD) + label_frame.grid(row=0, column=0, sticky="nsew") + label_frame.rowconfigure(0, weight=1) + label_frame.columnconfigure(0, weight=1) + self.groups = ListboxScroll(label_frame) + self.groups.grid(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) @@ -56,8 +60,12 @@ class NodeService(Dialog): ) self.services.grid(row=0, column=1, sticky="nsew") - self.current = ListboxScroll(frame, text="Selected", padding=FRAME_PAD) - self.current.grid(row=0, column=2, sticky="nsew") + label_frame = ttk.LabelFrame(frame, text="Selected", padding=FRAME_PAD) + label_frame.grid(row=0, column=2, sticky="nsew") + label_frame.rowconfigure(0, weight=1) + label_frame.columnconfigure(0, weight=1) + self.current = ListboxScroll(label_frame) + self.current.grid(sticky="nsew") for service in sorted(self.current_services): self.current.listbox.insert(tk.END, service) diff --git a/coretk/coretk/dialogs/serviceconfiguration.py b/coretk/coretk/dialogs/serviceconfiguration.py index a53c2aa1..0031ee31 100644 --- a/coretk/coretk/dialogs/serviceconfiguration.py +++ b/coretk/coretk/dialogs/serviceconfiguration.py @@ -216,32 +216,32 @@ class ServiceConfiguration(Dialog): tab.columnconfigure(0, weight=1) for i in range(3): tab.rowconfigure(i, weight=1) - self.notebook.add(tab, text="Startup/shutdown") + self.notebook.add(tab, text="Startup/Shutdown") # tab 3 for i in range(3): label_frame = None if i == 0: label_frame = ttk.LabelFrame( - tab, text="Startup commands", padding=FRAME_PAD + tab, text="Startup Commands", padding=FRAME_PAD ) commands = self.startup_commands elif i == 1: label_frame = ttk.LabelFrame( - tab, text="Shutdown commands", padding=FRAME_PAD + tab, text="Shutdown Commands", padding=FRAME_PAD ) commands = self.shutdown_commands elif i == 2: label_frame = ttk.LabelFrame( - tab, text="Validation commands", padding=FRAME_PAD + tab, text="Validation Commands", padding=FRAME_PAD ) commands = self.validation_commands label_frame.columnconfigure(0, weight=1) label_frame.rowconfigure(1, weight=1) - label_frame.grid(row=i, column=0, sticky="nsew") + label_frame.grid(row=i, column=0, sticky="nsew", pady=PADY) frame = ttk.Frame(label_frame) - frame.grid(row=0, column=0, sticky="nsew") + frame.grid(row=0, column=0, sticky="nsew", pady=PADY) frame.columnconfigure(0, weight=1) entry = ttk.Entry(frame, textvariable=tk.StringVar()) entry.grid(row=0, column=0, stick="ew", padx=PADX) @@ -251,7 +251,7 @@ class ServiceConfiguration(Dialog): button = ttk.Button(frame, image=self.editdelete_img) button.grid(row=0, column=2, sticky="ew") button.bind("", self.delete_command) - listbox_scroll = ListboxScroll(label_frame, borderwidth=0) + listbox_scroll = ListboxScroll(label_frame) listbox_scroll.listbox.bind("<>", self.update_entry) for command in commands: listbox_scroll.listbox.insert("end", command) @@ -303,13 +303,21 @@ class ServiceConfiguration(Dialog): ) self.validation_period_entry.grid(row=2, column=1, sticky="ew") - listbox_scroll = ListboxScroll(tab, text="Executables", padding=FRAME_PAD) - listbox_scroll.grid(sticky="nsew", pady=PADY) + label_frame = ttk.LabelFrame(tab, text="Executables", padding=FRAME_PAD) + label_frame.grid(sticky="nsew", pady=PADY) + label_frame.columnconfigure(0, weight=1) + label_frame.rowconfigure(0, weight=1) + listbox_scroll = ListboxScroll(label_frame) + listbox_scroll.grid(sticky="nsew") tab.rowconfigure(listbox_scroll.grid_info()["row"], weight=1) for executable in self.executables: listbox_scroll.listbox.insert("end", executable) - listbox_scroll = ListboxScroll(tab, text="Dependencies", padding=FRAME_PAD) + label_frame = ttk.LabelFrame(tab, text="Dependencies", padding=FRAME_PAD) + label_frame.grid(sticky="nsew", pady=PADY) + label_frame.columnconfigure(0, weight=1) + label_frame.rowconfigure(0, weight=1) + listbox_scroll = ListboxScroll(label_frame) listbox_scroll.grid(sticky="nsew") tab.rowconfigure(listbox_scroll.grid_info()["row"], weight=1) for dependency in self.dependencies: diff --git a/coretk/coretk/widgets.py b/coretk/coretk/widgets.py index a00b590a..feed7958 100644 --- a/coretk/coretk/widgets.py +++ b/coretk/coretk/widgets.py @@ -175,7 +175,7 @@ class ConfigFrame(FrameScroll): return {x: self.config[x].value for x in self.config} -class ListboxScroll(ttk.LabelFrame): +class ListboxScroll(ttk.Frame): def __init__(self, master=None, **kw): super().__init__(master, **kw) self.columnconfigure(0, weight=1) From dcdcb6a711b308dd882236aad40c53d2e83a4f0e Mon Sep 17 00:00:00 2001 From: Blake Harnden <32446120+bharnden@users.noreply.github.com> Date: Mon, 16 Dec 2019 14:21:30 -0800 Subject: [PATCH 6/7] updated theme style function names, removed unused function --- coretk/coretk/graph/node.py | 2 +- coretk/coretk/themes.py | 13 +++---------- coretk/coretk/widgets.py | 2 +- 3 files changed, 5 insertions(+), 12 deletions(-) diff --git a/coretk/coretk/graph/node.py b/coretk/coretk/graph/node.py index 93b6c390..105e21b7 100644 --- a/coretk/coretk/graph/node.py +++ b/coretk/coretk/graph/node.py @@ -168,7 +168,7 @@ class CanvasNode: is_wlan = self.core_node.type == NodeType.WIRELESS_LAN is_emane = self.core_node.type == NodeType.EMANE context = tk.Menu(self.canvas) - themes.update_menu(self.app.style, context) + themes.style_menu(self.app.style, context) if self.app.core.is_runtime(): context.add_command(label="Configure", command=self.show_config) if NodeUtils.is_container_node(self.core_node.type): diff --git a/coretk/coretk/themes.py b/coretk/coretk/themes.py index 685a8350..55b5732d 100644 --- a/coretk/coretk/themes.py +++ b/coretk/coretk/themes.py @@ -1,4 +1,3 @@ -import logging import tkinter as tk from tkinter import ttk @@ -142,19 +141,13 @@ def load(style): ) -def update_bg(style, event): - logging.info("updating background: %s", event.widget) - bg = style.lookup(".", "background") - event.widget.config(background=bg) - - def theme_change_menu(style, event): if not isinstance(event.widget, tk.Menu): return - update_menu(style, event.widget) + style_menu(style, event.widget) -def update_menu(style, widget): +def style_menu(style, widget): bg = style.lookup(".", "background") fg = style.lookup(".", "foreground") abg = style.lookup(".", "lightcolor") @@ -165,7 +158,7 @@ def update_menu(style, widget): ) -def update_listbox(widget): +def style_listbox(widget): style = ttk.Style() bg = style.lookup(".", "background") fg = style.lookup(".", "foreground") diff --git a/coretk/coretk/widgets.py b/coretk/coretk/widgets.py index feed7958..9ca96c0e 100644 --- a/coretk/coretk/widgets.py +++ b/coretk/coretk/widgets.py @@ -185,7 +185,7 @@ class ListboxScroll(ttk.Frame): self.listbox = tk.Listbox( self, selectmode=tk.SINGLE, yscrollcommand=self.scrollbar.set ) - themes.update_listbox(self.listbox) + themes.style_listbox(self.listbox) self.listbox.grid(row=0, column=0, sticky="nsew") self.scrollbar.config(command=self.listbox.yview) From 5dbd34f230eb20c93d4b3e6a23cc3cfc7d7f87bb Mon Sep 17 00:00:00 2001 From: Blake Harnden <32446120+bharnden@users.noreply.github.com> Date: Mon, 16 Dec 2019 14:30:38 -0800 Subject: [PATCH 7/7] cleanup for theming widgets --- coretk/coretk/app.py | 7 ++----- coretk/coretk/graph/node.py | 2 +- coretk/coretk/themes.py | 17 +++++++++++------ 3 files changed, 14 insertions(+), 12 deletions(-) diff --git a/coretk/coretk/app.py b/coretk/coretk/app.py index 7c2562a9..c8d4e597 100644 --- a/coretk/coretk/app.py +++ b/coretk/coretk/app.py @@ -1,6 +1,5 @@ import logging import tkinter as tk -from functools import partial from tkinter import ttk from coretk import appconfig, themes @@ -42,11 +41,9 @@ class Application(tk.Frame): def setup_theme(self): themes.load(self.style) + self.master.bind_class("Menu", "<>", themes.theme_change_menu) + self.master.bind("<>", themes.theme_change) self.style.theme_use(self.guiconfig["preferences"]["theme"]) - func = partial(themes.theme_change_menu, self.style) - self.master.bind_class("Menu", "<>", func) - func = partial(themes.theme_change, self.style) - self.master.bind("<>", func) def setup_app(self): self.master.title("CORE") diff --git a/coretk/coretk/graph/node.py b/coretk/coretk/graph/node.py index 105e21b7..e9f59882 100644 --- a/coretk/coretk/graph/node.py +++ b/coretk/coretk/graph/node.py @@ -168,7 +168,7 @@ class CanvasNode: is_wlan = self.core_node.type == NodeType.WIRELESS_LAN is_emane = self.core_node.type == NodeType.EMANE context = tk.Menu(self.canvas) - themes.style_menu(self.app.style, context) + themes.style_menu(context) if self.app.core.is_runtime(): context.add_command(label="Configure", command=self.show_config) if NodeUtils.is_container_node(self.core_node.type): diff --git a/coretk/coretk/themes.py b/coretk/coretk/themes.py index 55b5732d..66565f8d 100644 --- a/coretk/coretk/themes.py +++ b/coretk/coretk/themes.py @@ -141,13 +141,14 @@ def load(style): ) -def theme_change_menu(style, event): +def theme_change_menu(event): if not isinstance(event.widget, tk.Menu): return - style_menu(style, event.widget) + style_menu(event.widget) -def style_menu(style, widget): +def style_menu(widget): + style = ttk.Style() bg = style.lookup(".", "background") fg = style.lookup(".", "foreground") abg = style.lookup(".", "lightcolor") @@ -162,17 +163,21 @@ def style_listbox(widget): style = ttk.Style() bg = style.lookup(".", "background") fg = style.lookup(".", "foreground") + bc = style.lookup(".", "bordercolor") + if not bc: + bc = "black" widget.config( background=bg, foreground=fg, highlightthickness=1, - highlightcolor="black", - highlightbackground="black", + highlightcolor=bc, + highlightbackground=bc, bd=0, ) -def theme_change(style, event): +def theme_change(event): + style = ttk.Style() style.configure(Styles.picker_button, font=("TkDefaultFont", 8, "normal")) style.configure( Styles.green_alert,