updated config generation to use config frame where possible
This commit is contained in:
parent
9987637564
commit
0147bb9988
3 changed files with 65 additions and 140 deletions
|
@ -1,99 +0,0 @@
|
|||
import enum
|
||||
import logging
|
||||
import tkinter as tk
|
||||
from tkinter import ttk
|
||||
|
||||
|
||||
class ConfigType(enum.Enum):
|
||||
STRING = 10
|
||||
BOOL = 11
|
||||
EMANECONFIG = 7
|
||||
|
||||
|
||||
def create_config(master, config, padx=2, pady=2):
|
||||
"""
|
||||
Creates a scrollable canvas with an embedded window for displaying configuration
|
||||
options. Will use grid layout to consume row 0 and columns 0-2.
|
||||
|
||||
:param master: master to add scrollable canvas to
|
||||
:param dict config: config option mapping keys to config options
|
||||
:param int padx: x padding for widgets
|
||||
:param int pady: y padding for widgets
|
||||
:return: widget value mapping
|
||||
"""
|
||||
master.rowconfigure(0, weight=1)
|
||||
master.columnconfigure(0, weight=1)
|
||||
master.columnconfigure(1, weight=1)
|
||||
|
||||
canvas = tk.Canvas(master, highlightthickness=0)
|
||||
canvas.grid(row=0, columnspan=2, sticky="nsew", padx=padx, pady=pady)
|
||||
canvas.columnconfigure(0, weight=1)
|
||||
canvas.rowconfigure(0, weight=1)
|
||||
|
||||
scroll_y = tk.Scrollbar(master, orient="vertical", command=canvas.yview)
|
||||
scroll_y.grid(row=0, column=2, sticky="ns")
|
||||
|
||||
frame = tk.Frame(canvas, padx=padx, pady=pady)
|
||||
frame.columnconfigure(0, weight=1)
|
||||
frame.columnconfigure(1, weight=3)
|
||||
|
||||
values = {}
|
||||
for index, key in enumerate(sorted(config)):
|
||||
option = config[key]
|
||||
label = tk.Label(frame, text=option.label)
|
||||
label.grid(row=index, pady=pady, padx=padx, sticky="ew")
|
||||
value = tk.StringVar()
|
||||
config_type = ConfigType(option.type)
|
||||
if config_type == ConfigType.BOOL:
|
||||
select = tuple(option.select)
|
||||
combobox = ttk.Combobox(frame, textvariable=value, values=select)
|
||||
combobox.grid(row=index, column=1, sticky="ew", pady=pady)
|
||||
if option.value == "1":
|
||||
value.set("On")
|
||||
else:
|
||||
value.set("Off")
|
||||
elif config_type == ConfigType.STRING:
|
||||
value.set(option.value)
|
||||
entry = tk.Entry(frame, textvariable=value)
|
||||
entry.grid(row=index, column=1, sticky="ew", pady=pady)
|
||||
elif config_type == ConfigType.EMANECONFIG:
|
||||
value.set(option.value)
|
||||
entry = tk.Entry(frame, textvariable=value, bg="white")
|
||||
entry.grid(row=index, column=1, sticky="ew", pady=pady)
|
||||
else:
|
||||
logging.error("unhandled config option type: %s", config_type)
|
||||
values[key] = value
|
||||
|
||||
frame_id = canvas.create_window(0, 0, anchor="nw", window=frame)
|
||||
canvas.update_idletasks()
|
||||
canvas.configure(scrollregion=canvas.bbox("all"), yscrollcommand=scroll_y.set)
|
||||
|
||||
frame.bind(
|
||||
"<Configure>", lambda event: canvas.configure(scrollregion=canvas.bbox("all"))
|
||||
)
|
||||
canvas.bind(
|
||||
"<Configure>", lambda event: canvas.itemconfig(frame_id, width=event.width)
|
||||
)
|
||||
return values
|
||||
|
||||
|
||||
def parse_config(options, values):
|
||||
"""
|
||||
Given a set of configurations, parse out values and transform them when needed.
|
||||
|
||||
:param dict options: option key mapping to configuration options
|
||||
:param dict values: option key mapping to widget values
|
||||
:return: nothing
|
||||
"""
|
||||
for key in options:
|
||||
option = options[key]
|
||||
value = values[key]
|
||||
config_type = ConfigType(option.type)
|
||||
config_value = value.get()
|
||||
if config_type == ConfigType.BOOL:
|
||||
if config_value == "On":
|
||||
option.value = "1"
|
||||
else:
|
||||
option.value = "0"
|
||||
else:
|
||||
option.value = config_value
|
|
@ -7,9 +7,9 @@ import tkinter as tk
|
|||
import webbrowser
|
||||
from tkinter import ttk
|
||||
|
||||
from coretk import configutils
|
||||
from coretk.dialogs.dialog import Dialog
|
||||
from coretk.images import ImageEnum, Images
|
||||
from coretk.widgets import ConfigFrame
|
||||
|
||||
PAD_X = 2
|
||||
PAD_Y = 2
|
||||
|
@ -38,10 +38,10 @@ class EmaneConfiguration(Dialog):
|
|||
self.emane_options()
|
||||
self.draw_apply_and_cancel()
|
||||
|
||||
self.values = None
|
||||
self.emane_config_frame = None
|
||||
self.options = app.core.emane_config
|
||||
self.model_options = None
|
||||
self.model_values = None
|
||||
self.model_config_frame = None
|
||||
|
||||
def create_text_variable(self, val):
|
||||
"""
|
||||
|
@ -75,7 +75,7 @@ class EmaneConfiguration(Dialog):
|
|||
f.grid(row=0, column=0, sticky="nsew")
|
||||
|
||||
def save_emane_option(self):
|
||||
configutils.parse_config(self.options, self.values)
|
||||
self.emane_config_frame.parse_config()
|
||||
self.emane_dialog.destroy()
|
||||
|
||||
def draw_emane_options(self):
|
||||
|
@ -83,10 +83,6 @@ class EmaneConfiguration(Dialog):
|
|||
self.emane_dialog = Dialog(
|
||||
self, self.app, "emane configuration", modal=False
|
||||
)
|
||||
b1 = tk.Button(self.emane_dialog, text="Appy", command=self.save_emane_option)
|
||||
b2 = tk.Button(
|
||||
self.emane_dialog, text="Cancel", command=self.emane_dialog.destroy
|
||||
)
|
||||
|
||||
if self.options is None:
|
||||
session_id = self.app.core.session_id
|
||||
|
@ -94,11 +90,20 @@ class EmaneConfiguration(Dialog):
|
|||
logging.info("emane config: %s", response)
|
||||
self.options = response.config
|
||||
|
||||
self.values = configutils.create_config(
|
||||
self.emane_dialog, self.options, PAD_X, PAD_Y
|
||||
)
|
||||
b1.grid(row=1, column=0)
|
||||
b2.grid(row=1, column=1)
|
||||
self.emane_dialog.columnconfigure(0, weight=1)
|
||||
self.emane_dialog.rowconfigure(0, weight=1)
|
||||
self.emane_config_frame = ConfigFrame(self.emane_dialog, config=self.options)
|
||||
self.emane_config_frame.draw_config()
|
||||
self.emane_config_frame.grid(sticky="nsew")
|
||||
|
||||
frame = tk.Frame(self.emane_dialog)
|
||||
frame.grid(sticky="ew")
|
||||
for i in range(2):
|
||||
frame.columnconfigure(i, weight=1)
|
||||
b1 = tk.Button(frame, text="Appy", command=self.save_emane_option)
|
||||
b1.grid(row=0, column=0, sticky="ew")
|
||||
b2 = tk.Button(frame, text="Cancel", command=self.emane_dialog.destroy)
|
||||
b2.grid(row=0, column=1, sticky="ew")
|
||||
self.emane_dialog.show()
|
||||
|
||||
def save_emane_model_options(self):
|
||||
|
@ -111,8 +116,7 @@ class EmaneConfiguration(Dialog):
|
|||
model_name = self.emane_models[self.emane_model_combobox.current()]
|
||||
|
||||
# parse configuration
|
||||
configutils.parse_config(self.model_options, self.model_values)
|
||||
config = {x: self.model_options[x].value for x in self.model_options}
|
||||
config = self.model_config_frame.parse_config()
|
||||
|
||||
# add string emane_ infront for grpc call
|
||||
response = self.app.core.client.set_emane_model_config(
|
||||
|
@ -141,17 +145,10 @@ class EmaneConfiguration(Dialog):
|
|||
# create the dialog and the necessry widget
|
||||
if not self.emane_model_dialog or not self.emane_model_dialog.winfo_exists():
|
||||
self.emane_model_dialog = Dialog(
|
||||
self, self.app, model_name + " configuration", modal=False
|
||||
self, self.app, f"{model_name} configuration", modal=False
|
||||
)
|
||||
|
||||
b1 = tk.Button(
|
||||
self.emane_model_dialog, text="Apply", command=self.save_emane_model_options
|
||||
)
|
||||
b2 = tk.Button(
|
||||
self.emane_model_dialog,
|
||||
text="Cancel",
|
||||
command=self.emane_model_dialog.destroy,
|
||||
)
|
||||
self.emane_model_dialog.columnconfigure(0, weight=1)
|
||||
self.emane_model_dialog.rowconfigure(0, weight=1)
|
||||
|
||||
# query for configurations
|
||||
session_id = self.app.core.session_id
|
||||
|
@ -162,12 +159,20 @@ class EmaneConfiguration(Dialog):
|
|||
logging.info("emane model config %s", response)
|
||||
|
||||
self.model_options = response.config
|
||||
self.model_values = configutils.create_config(
|
||||
self.emane_model_dialog, self.model_options, PAD_X, PAD_Y
|
||||
self.model_config_frame = ConfigFrame(
|
||||
self.emane_model_dialog, config=self.model_options
|
||||
)
|
||||
self.model_config_frame.grid(sticky="nsew")
|
||||
self.model_config_frame.draw_config()
|
||||
|
||||
b1.grid(row=1, column=0, sticky="nsew")
|
||||
b2.grid(row=1, column=1, sticky="nsew")
|
||||
frame = tk.Frame(self.emane_model_dialog)
|
||||
frame.grid(sticky="ew")
|
||||
for i in range(2):
|
||||
frame.columnconfigure(i, weight=1)
|
||||
b1 = tk.Button(frame, text="Apply", command=self.save_emane_model_options)
|
||||
b1.grid(row=0, column=0, sticky="ew")
|
||||
b2 = tk.Button(frame, text="Cancel", command=self.emane_model_dialog.destroy)
|
||||
b2.grid(row=0, column=1, sticky="ew")
|
||||
self.emane_model_dialog.show()
|
||||
|
||||
def draw_option_buttons(self, parent):
|
||||
|
|
|
@ -3,7 +3,18 @@ import tkinter as tk
|
|||
from functools import partial
|
||||
from tkinter import ttk
|
||||
|
||||
from coretk.configutils import ConfigType
|
||||
from core.api.grpc import core_pb2
|
||||
|
||||
INT_TYPES = {
|
||||
core_pb2.ConfigOptionType.UINT8,
|
||||
core_pb2.ConfigOptionType.UINT16,
|
||||
core_pb2.ConfigOptionType.UINT32,
|
||||
core_pb2.ConfigOptionType.UINT64,
|
||||
core_pb2.ConfigOptionType.INT8,
|
||||
core_pb2.ConfigOptionType.INT16,
|
||||
core_pb2.ConfigOptionType.INT32,
|
||||
core_pb2.ConfigOptionType.INT64,
|
||||
}
|
||||
|
||||
|
||||
class FrameScroll(tk.LabelFrame):
|
||||
|
@ -30,11 +41,8 @@ class FrameScroll(tk.LabelFrame):
|
|||
|
||||
def _configure_frame(self, event):
|
||||
req_width = self.frame.winfo_reqwidth()
|
||||
req_height = self.frame.winfo_reqheight()
|
||||
if req_width != self.canvas.winfo_reqwidth():
|
||||
self.canvas.configure(width=req_width)
|
||||
if req_height != self.canvas.winfo_reqheight():
|
||||
self.canvas.configure(height=req_height)
|
||||
self.canvas.configure(scrollregion=self.canvas.bbox("all"))
|
||||
|
||||
def _configure_canvas(self, event):
|
||||
|
@ -68,34 +76,45 @@ class ConfigFrame(FrameScroll):
|
|||
label = tk.Label(self.frame, text=option.label)
|
||||
label.grid(row=index, pady=pady, padx=padx, sticky="w")
|
||||
value = tk.StringVar()
|
||||
config_type = ConfigType(option.type)
|
||||
if config_type == ConfigType.BOOL:
|
||||
if option.type == core_pb2.ConfigOptionType.BOOL:
|
||||
select = tuple(option.select)
|
||||
combobox = ttk.Combobox(self.frame, textvariable=value, values=select)
|
||||
combobox = ttk.Combobox(
|
||||
self.frame, textvariable=value, values=select, state="readonly"
|
||||
)
|
||||
combobox.grid(row=index, column=1, sticky="ew", pady=pady)
|
||||
if option.value == "1":
|
||||
value.set("On")
|
||||
else:
|
||||
value.set("Off")
|
||||
elif config_type == ConfigType.STRING:
|
||||
elif option.select:
|
||||
value.set(option.value)
|
||||
select = tuple(option.select)
|
||||
combobox = ttk.Combobox(
|
||||
self.frame, textvariable=value, values=select, state="readonly"
|
||||
)
|
||||
combobox.grid(row=index, column=1, sticky="ew", pady=pady)
|
||||
elif option.type == core_pb2.ConfigOptionType.STRING:
|
||||
value.set(option.value)
|
||||
entry = tk.Entry(self.frame, textvariable=value)
|
||||
entry.grid(row=index, column=1, sticky="ew", pady=pady)
|
||||
elif config_type == ConfigType.EMANECONFIG:
|
||||
elif option.type in INT_TYPES:
|
||||
value.set(option.value)
|
||||
entry = tk.Entry(self.frame, textvariable=value)
|
||||
entry.grid(row=index, column=1, sticky="ew", pady=pady)
|
||||
elif option.type == core_pb2.ConfigOptionType.FLOAT:
|
||||
value.set(option.value)
|
||||
entry = tk.Entry(self.frame, textvariable=value)
|
||||
entry.grid(row=index, column=1, sticky="ew", pady=pady)
|
||||
else:
|
||||
logging.error("unhandled config option type: %s", config_type)
|
||||
logging.error("unhandled config option type: %s", option.type)
|
||||
self.values[key] = value
|
||||
|
||||
def parse_config(self):
|
||||
for key in self.config:
|
||||
option = self.config[key]
|
||||
value = self.values[key]
|
||||
config_type = ConfigType(option.type)
|
||||
config_value = value.get()
|
||||
if config_type == ConfigType.BOOL:
|
||||
if option.type == core_pb2.ConfigOptionType.BOOL:
|
||||
if config_value == "On":
|
||||
option.value = "1"
|
||||
else:
|
||||
|
|
Loading…
Reference in a new issue