Merge branch 'coretk' into coretk-config

This commit is contained in:
Huy Pham 2019-11-11 16:36:33 -08:00
commit 66c9063d2e
22 changed files with 546 additions and 429 deletions

View file

@ -1,7 +1,7 @@
import logging import logging
import tkinter as tk import tkinter as tk
from coretk import appdirs from coretk import appconfig
from coretk.coreclient import CoreClient from coretk.coreclient import CoreClient
from coretk.graph import CanvasGraph from coretk.graph import CanvasGraph
from coretk.images import ImageEnum, Images from coretk.images import ImageEnum, Images
@ -26,7 +26,7 @@ class Application(tk.Frame):
self.radiovar = tk.IntVar(value=1) self.radiovar = tk.IntVar(value=1)
self.show_grid_var = tk.IntVar(value=1) self.show_grid_var = tk.IntVar(value=1)
self.adjust_to_dim_var = tk.IntVar(value=0) self.adjust_to_dim_var = tk.IntVar(value=0)
self.config = appdirs.read_config() self.config = appconfig.read()
self.core = CoreClient(self) self.core = CoreClient(self)
self.setup_app() self.setup_app()
self.draw() self.draw()
@ -70,10 +70,13 @@ class Application(tk.Frame):
menu_action = MenuAction(self, self.master) menu_action = MenuAction(self, self.master)
menu_action.on_quit() menu_action.on_quit()
def save_config(self):
appconfig.save(self.config)
if __name__ == "__main__": if __name__ == "__main__":
log_format = "%(asctime)s - %(levelname)s - %(module)s:%(funcName)s - %(message)s" log_format = "%(asctime)s - %(levelname)s - %(module)s:%(funcName)s - %(message)s"
logging.basicConfig(level=logging.DEBUG, format=log_format) logging.basicConfig(level=logging.DEBUG, format=log_format)
appdirs.check_directory() appconfig.check_directory()
app = Application() app = Application()
app.mainloop() app.mainloop()

View file

@ -1,4 +1,5 @@
import logging import logging
import os
import shutil import shutil
from pathlib import Path from pathlib import Path
@ -18,6 +19,20 @@ CONFIG_PATH = HOME_PATH.joinpath("gui.yaml")
LOCAL_ICONS_PATH = Path(__file__).parent.joinpath("icons").absolute() LOCAL_ICONS_PATH = Path(__file__).parent.joinpath("icons").absolute()
LOCAL_BACKGROUND_PATH = Path(__file__).parent.joinpath("backgrounds").absolute() LOCAL_BACKGROUND_PATH = Path(__file__).parent.joinpath("backgrounds").absolute()
# configuration data
TERMINALS = [
"$TERM",
"gnome-terminal --window --",
"lxterminal -e",
"konsole -e",
"xterm -e",
"aterm -e",
"eterm -e",
"rxvt -e",
"xfce4-terminal -x",
]
EDITORS = ["$EDITOR", "vim", "emacs", "gedit", "nano", "vi"]
class IndentDumper(yaml.Dumper): class IndentDumper(yaml.Dumper):
def increase_indent(self, flow=False, indentless=False): def increase_indent(self, flow=False, indentless=False):
@ -42,18 +57,33 @@ def check_directory():
for background in LOCAL_BACKGROUND_PATH.glob("*"): for background in LOCAL_BACKGROUND_PATH.glob("*"):
new_background = BACKGROUNDS_PATH.joinpath(background.name) new_background = BACKGROUNDS_PATH.joinpath(background.name)
shutil.copy(background, new_background) shutil.copy(background, new_background)
if "TERM" in os.environ:
terminal = TERMINALS[0]
else:
terminal = TERMINALS[1]
if "EDITOR" in os.environ:
editor = EDITORS[0]
else:
editor = EDITORS[1]
config = { config = {
"preferences": {
"editor": editor,
"terminal": terminal,
"gui3d": "/usr/local/bin/std3d.sh",
},
"servers": [{"name": "example", "address": "127.0.0.1", "port": 50051}], "servers": [{"name": "example", "address": "127.0.0.1", "port": 50051}],
"nodes": [], "nodes": [],
"observers": [{"name": "hello", "cmd": "echo hello"}],
} }
save_config(config) save(config)
def read_config(): def read():
with CONFIG_PATH.open("r") as f: with CONFIG_PATH.open("r") as f:
return yaml.load(f, Loader=yaml.SafeLoader) return yaml.load(f, Loader=yaml.SafeLoader)
def save_config(config): def save(config):
with CONFIG_PATH.open("w") as f: with CONFIG_PATH.open("w") as f:
yaml.dump(config, f, Dumper=IndentDumper, default_flow_style=False) yaml.dump(config, f, Dumper=IndentDumper, default_flow_style=False)

View file

@ -18,25 +18,14 @@ class CanvasTooltip:
""" """
def __init__( def __init__(
self, self, canvas, *, bg="#FFFFEA", pad=(5, 3, 5, 3), waittime=400, wraplength=600
canvas,
tag_or_id,
*,
bg="#FFFFEA",
pad=(5, 3, 5, 3),
text="canvas info",
waittime=400,
wraplength=250
): ):
# in miliseconds, originally 500 # in miliseconds, originally 500
self.waittime = waittime self.waittime = waittime
# in pixels, originally 180 # in pixels, originally 180
self.wraplength = wraplength self.wraplength = wraplength
self.canvas = canvas self.canvas = canvas
self.text = text self.text = tk.StringVar()
self.canvas.tag_bind(tag_or_id, "<Enter>", self.on_enter)
self.canvas.tag_bind(tag_or_id, "<Leave>", self.on_leave)
self.canvas.tag_bind(tag_or_id, "<ButtonPress>", self.on_leave)
self.bg = bg self.bg = bg
self.pad = pad self.pad = pad
self.id = None self.id = None
@ -61,18 +50,13 @@ class CanvasTooltip:
def show(self, event=None): def show(self, event=None):
def tip_pos_calculator(canvas, label, *, tip_delta=(10, 5), pad=(5, 3, 5, 3)): def tip_pos_calculator(canvas, label, *, tip_delta=(10, 5), pad=(5, 3, 5, 3)):
c = canvas c = canvas
s_width, s_height = c.winfo_screenwidth(), c.winfo_screenheight() s_width, s_height = c.winfo_screenwidth(), c.winfo_screenheight()
width, height = ( width, height = (
pad[0] + label.winfo_reqwidth() + pad[2], pad[0] + label.winfo_reqwidth() + pad[2],
pad[1] + label.winfo_reqheight() + pad[3], pad[1] + label.winfo_reqheight() + pad[3],
) )
mouse_x, mouse_y = c.winfo_pointerxy() mouse_x, mouse_y = c.winfo_pointerxy()
x1, y1 = mouse_x + tip_delta[0], mouse_y + tip_delta[1] x1, y1 = mouse_x + tip_delta[0], mouse_y + tip_delta[1]
x2, y2 = x1 + width, y1 + height x2, y2 = x1 + width, y1 + height
@ -84,20 +68,14 @@ class CanvasTooltip:
y_delta = 0 y_delta = 0
offscreen = (x_delta, y_delta) != (0, 0) offscreen = (x_delta, y_delta) != (0, 0)
if offscreen: if offscreen:
if x_delta: if x_delta:
x1 = mouse_x - tip_delta[0] - width x1 = mouse_x - tip_delta[0] - width
if y_delta: if y_delta:
y1 = mouse_y - tip_delta[1] - height y1 = mouse_y - tip_delta[1] - height
offscreen_again = y1 < 0 # out on the top offscreen_again = y1 < 0 # out on the top
if offscreen_again: if offscreen_again:
y1 = 0 y1 = 0
return x1, y1 return x1, y1
bg = self.bg bg = self.bg
@ -111,21 +89,18 @@ class CanvasTooltip:
self.tw.wm_overrideredirect(True) self.tw.wm_overrideredirect(True)
win = tk.Frame(self.tw, background=bg, borderwidth=0) win = tk.Frame(self.tw, background=bg, borderwidth=0)
win.grid()
label = ttk.Label( label = ttk.Label(
win, win,
text=self.text, textvariable=self.text,
justify=tk.LEFT, justify=tk.LEFT,
background=bg, background=bg,
relief=tk.SOLID, relief=tk.SOLID,
borderwidth=0, borderwidth=0,
wraplength=self.wraplength, wraplength=self.wraplength,
) )
label.grid(padx=(pad[0], pad[2]), pady=(pad[1], pad[3]), sticky=tk.NSEW) label.grid(padx=(pad[0], pad[2]), pady=(pad[1], pad[3]), sticky=tk.NSEW)
win.grid()
x, y = tip_pos_calculator(canvas, label) x, y = tip_pos_calculator(canvas, label)
self.tw.wm_geometry("+%d+%d" % (x, y)) self.tw.wm_geometry("+%d+%d" % (x, y))
def hide(self): def hide(self):

View file

@ -16,6 +16,17 @@ from coretk.wlannodeconfig import WlanNodeConfig
NETWORK_NODES = {"switch", "hub", "wlan", "rj45", "tunnel", "emane"} NETWORK_NODES = {"switch", "hub", "wlan", "rj45", "tunnel", "emane"}
DEFAULT_NODES = {"router", "host", "PC", "mdr", "prouter"} DEFAULT_NODES = {"router", "host", "PC", "mdr", "prouter"}
OBSERVERS = {
"processes": "ps",
"ifconfig": "ifconfig",
"IPV4 Routes": "ip -4 ro",
"IPV6 Routes": "ip -6 ro",
"Listening sockets": "netstat -tuwnl",
"IPv4 MFC entries": "ip -4 mroute show",
"IPv6 MFC entries": "ip -6 mroute show",
"firewall rules": "iptables -L",
"IPSec policies": "setkey -DP",
}
class Node: class Node:
@ -74,6 +85,12 @@ class CustomNode:
self.services = services self.services = services
class Observer:
def __init__(self, name, cmd):
self.name = name
self.cmd = cmd
class CoreClient: class CoreClient:
def __init__(self, app): def __init__(self, app):
""" """
@ -86,13 +103,16 @@ class CoreClient:
self.master = app.master self.master = app.master
self.interface_helper = None self.interface_helper = None
self.services = {} self.services = {}
self.observer = None
# loaded configuration data # loaded configuration data
self.servers = {} self.servers = {}
self.custom_nodes = {} self.custom_nodes = {}
self.custom_observers = {}
self.read_config() self.read_config()
# data for managing the current session # data for managing the current session
self.state = None
self.nodes = {} self.nodes = {}
self.edges = {} self.edges = {}
self.hooks = {} self.hooks = {}
@ -107,27 +127,36 @@ class CoreClient:
self.emane_config = None self.emane_config = None
self.serviceconfig_manager = ServiceNodeConfig(app) self.serviceconfig_manager = ServiceNodeConfig(app)
def set_observer(self, value):
self.observer = value
def read_config(self): def read_config(self):
# read distributed server # read distributed server
for server_config in self.app.config["servers"]: for config in self.app.config.get("servers", []):
server = CoreServer( server = CoreServer(config["name"], config["address"], config["port"])
server_config["name"], server_config["address"], server_config["port"]
)
self.servers[server.name] = server self.servers[server.name] = server
# read custom nodes # read custom nodes
for node in self.app.config["nodes"]: for config in self.app.config.get("nodes", []):
image_file = node["image"] image_file = config["image"]
image = Images.get_custom(image_file) image = Images.get_custom(image_file)
custom_node = CustomNode( custom_node = CustomNode(
node["name"], image, image_file, set(node["services"]) config["name"], image, image_file, set(config["services"])
) )
self.custom_nodes[custom_node.name] = custom_node self.custom_nodes[custom_node.name] = custom_node
# read observers
for config in self.app.config.get("observers", []):
observer = Observer(config["name"], config["cmd"])
self.custom_observers[observer.name] = observer
def handle_events(self, event): def handle_events(self, event):
logging.info("event: %s", event) logging.info("event: %s", event)
if event.link_event is not None: if event.HasField("link_event"):
self.app.canvas.wireless_draw.hangle_link_event(event.link_event) self.app.canvas.wireless_draw.hangle_link_event(event.link_event)
elif event.HasField("session_event"):
if event.session_event.event <= core_pb2.SessionState.SHUTDOWN:
self.state = event.session_event.event
def handle_throughputs(self, event): def handle_throughputs(self, event):
interface_throughputs = event.interface_throughputs interface_throughputs = event.interface_throughputs
@ -161,7 +190,7 @@ class CoreClient:
response = self.client.get_session(self.session_id) response = self.client.get_session(self.session_id)
logging.info("joining session(%s): %s", self.session_id, response) logging.info("joining session(%s): %s", self.session_id, response)
session = response.session session = response.session
session_state = session.state self.state = session.state
self.client.events(self.session_id, self.handle_events) self.client.events(self.session_id, self.handle_events)
# get hooks # get hooks
@ -209,11 +238,14 @@ class CoreClient:
self.app.canvas.canvas_reset_and_redraw(session) self.app.canvas.canvas_reset_and_redraw(session)
# draw tool bar appropritate with session state # draw tool bar appropritate with session state
if session_state == core_pb2.SessionState.RUNTIME: if self.is_runtime():
self.app.toolbar.runtime_frame.tkraise() self.app.toolbar.runtime_frame.tkraise()
else: else:
self.app.toolbar.design_frame.tkraise() self.app.toolbar.design_frame.tkraise()
def is_runtime(self):
return self.state == core_pb2.SessionState.RUNTIME
def create_new_session(self): def create_new_session(self):
""" """
Create a new session Create a new session
@ -769,3 +801,7 @@ class CoreClient:
) )
configs.append(config_proto) configs.append(config_proto)
return configs return configs
def run(self, node_id):
logging.info("running node(%s) cmd: %s", node_id, self.observer)
return self.client.node_command(self.session_id, node_id, self.observer).output

View file

@ -4,11 +4,11 @@ set wallpaper
import enum import enum
import logging import logging
import tkinter as tk import tkinter as tk
from tkinter import filedialog from tkinter import filedialog, ttk
from PIL import Image, ImageTk from PIL import Image, ImageTk
from coretk.appdirs import BACKGROUNDS_PATH from coretk.appconfig import BACKGROUNDS_PATH
from coretk.dialogs.dialog import Dialog from coretk.dialogs.dialog import Dialog
@ -39,7 +39,6 @@ class CanvasBackgroundDialog(Dialog):
def draw(self): def draw(self):
self.columnconfigure(0, weight=1) self.columnconfigure(0, weight=1)
self.rowconfigure(0, weight=1)
self.draw_image() self.draw_image()
self.draw_image_label() self.draw_image_label()
self.draw_image_selection() self.draw_image_selection()
@ -48,65 +47,67 @@ class CanvasBackgroundDialog(Dialog):
self.draw_buttons() self.draw_buttons()
def draw_image(self): def draw_image(self):
self.image_label = tk.Label( self.image_label = ttk.Label(
self, text="(image preview)", height=8, width=32, bg="white" self, text="(image preview)", width=32, anchor=tk.CENTER
) )
self.image_label.grid(row=0, column=0, pady=5, sticky="nsew") self.image_label.grid(row=0, column=0, pady=5)
def draw_image_label(self): def draw_image_label(self):
label = tk.Label(self, text="Image filename: ") label = ttk.Label(self, text="Image filename: ")
label.grid(row=1, column=0, sticky="ew") label.grid(row=1, column=0, sticky="ew")
def draw_image_selection(self): def draw_image_selection(self):
frame = tk.Frame(self) frame = ttk.Frame(self)
frame.columnconfigure(0, weight=2) frame.columnconfigure(0, weight=2)
frame.columnconfigure(1, weight=1) frame.columnconfigure(1, weight=1)
frame.columnconfigure(2, weight=1) frame.columnconfigure(2, weight=1)
frame.grid(row=2, column=0, sticky="ew") frame.grid(row=2, column=0, sticky="ew")
entry = tk.Entry(frame, textvariable=self.file_name) entry = ttk.Entry(frame, textvariable=self.file_name)
entry.focus() entry.focus()
entry.grid(row=0, column=0, sticky="ew") entry.grid(row=0, column=0, sticky="ew")
button = tk.Button(frame, text="...", command=self.click_open_image) button = ttk.Button(frame, text="...", command=self.click_open_image)
button.grid(row=0, column=1, sticky="ew") button.grid(row=0, column=1, sticky="ew")
button = tk.Button(frame, text="Clear", command=self.click_clear) button = ttk.Button(frame, text="Clear", command=self.click_clear)
button.grid(row=0, column=2, sticky="ew") button.grid(row=0, column=2, sticky="ew")
def draw_options(self): def draw_options(self):
frame = tk.Frame(self) frame = ttk.Frame(self)
frame.columnconfigure(0, weight=1) frame.columnconfigure(0, weight=1)
frame.columnconfigure(1, weight=1) frame.columnconfigure(1, weight=1)
frame.columnconfigure(2, weight=1) frame.columnconfigure(2, weight=1)
frame.columnconfigure(3, weight=1) frame.columnconfigure(3, weight=1)
frame.grid(row=3, column=0, sticky="ew") frame.grid(row=3, column=0, sticky="ew")
button = tk.Radiobutton( button = ttk.Radiobutton(
frame, text="upper-left", value=1, variable=self.radiovar frame, text="upper-left", value=1, variable=self.radiovar
) )
button.grid(row=0, column=0, sticky="ew") button.grid(row=0, column=0, sticky="ew")
self.options.append(button) self.options.append(button)
button = tk.Radiobutton(frame, text="centered", value=2, variable=self.radiovar) button = ttk.Radiobutton(
frame, text="centered", value=2, variable=self.radiovar
)
button.grid(row=0, column=1, sticky="ew") button.grid(row=0, column=1, sticky="ew")
self.options.append(button) self.options.append(button)
button = tk.Radiobutton(frame, text="scaled", value=3, variable=self.radiovar) button = ttk.Radiobutton(frame, text="scaled", value=3, variable=self.radiovar)
button.grid(row=0, column=2, sticky="ew") button.grid(row=0, column=2, sticky="ew")
self.options.append(button) self.options.append(button)
button = tk.Radiobutton(frame, text="titled", value=4, variable=self.radiovar) button = ttk.Radiobutton(frame, text="titled", value=4, variable=self.radiovar)
button.grid(row=0, column=3, sticky="ew") button.grid(row=0, column=3, sticky="ew")
self.options.append(button) self.options.append(button)
def draw_additional_options(self): def draw_additional_options(self):
checkbutton = tk.Checkbutton( checkbutton = ttk.Checkbutton(
self, text="Show grid", variable=self.show_grid_var self, text="Show grid", variable=self.show_grid_var
) )
checkbutton.grid(row=4, column=0, sticky="ew", padx=5) checkbutton.grid(row=4, column=0, sticky="ew", padx=5)
checkbutton = tk.Checkbutton( checkbutton = ttk.Checkbutton(
self, self,
text="Adjust canvas size to image dimensions", text="Adjust canvas size to image dimensions",
variable=self.adjust_to_dim_var, variable=self.adjust_to_dim_var,
@ -118,15 +119,15 @@ class CanvasBackgroundDialog(Dialog):
self.adjust_to_dim_var.set(0) self.adjust_to_dim_var.set(0)
def draw_buttons(self): def draw_buttons(self):
frame = tk.Frame(self) frame = ttk.Frame(self)
frame.grid(row=6, column=0, pady=5, sticky="ew") frame.grid(row=6, column=0, pady=5, sticky="ew")
frame.columnconfigure(0, weight=1) frame.columnconfigure(0, weight=1)
frame.columnconfigure(1, weight=1) frame.columnconfigure(1, weight=1)
button = tk.Button(frame, text="Apply", command=self.click_apply) button = ttk.Button(frame, text="Apply", command=self.click_apply)
button.grid(row=0, column=0, sticky="ew") button.grid(row=0, column=0, sticky="ew")
button = tk.Button(frame, text="Cancel", command=self.destroy) button = ttk.Button(frame, text="Cancel", command=self.destroy)
button.grid(row=0, column=1, sticky="ew") button.grid(row=0, column=1, sticky="ew")
def click_open_image(self): def click_open_image(self):
@ -144,7 +145,7 @@ class CanvasBackgroundDialog(Dialog):
img = Image.open(filename) img = Image.open(filename)
img = img.resize((width, height), Image.ANTIALIAS) img = img.resize((width, height), Image.ANTIALIAS)
tk_img = ImageTk.PhotoImage(img) tk_img = ImageTk.PhotoImage(img)
self.image_label.config(image=tk_img, width=width, height=height) self.image_label.config(image=tk_img, width=width)
self.image_label.image = tk_img self.image_label.image = tk_img
def click_clear(self): def click_clear(self):
@ -156,7 +157,7 @@ class CanvasBackgroundDialog(Dialog):
# delete entry # delete entry
self.file_name.set("") self.file_name.set("")
# delete display image # delete display image
self.image_label.config(image="", width=32, height=8) self.image_label.config(image="", width=32)
def click_adjust_canvas(self): def click_adjust_canvas(self):
# deselect all radio buttons and grey them out # deselect all radio buttons and grey them out

View file

@ -2,7 +2,7 @@
size and scale size and scale
""" """
import tkinter as tk import tkinter as tk
from tkinter import font from tkinter import font, ttk
from coretk.dialogs.canvasbackground import ScaleOption from coretk.dialogs.canvasbackground import ScaleOption
from coretk.dialogs.dialog import Dialog from coretk.dialogs.dialog import Dialog
@ -49,120 +49,120 @@ class SizeAndScaleDialog(Dialog):
self.draw_buttons() self.draw_buttons()
def draw_size(self): def draw_size(self):
label = tk.Label(self, text="Size", font=self.section_font) label = ttk.Label(self, text="Size", font=self.section_font)
label.grid(sticky="w") label.grid(sticky="w")
# draw size row 1 # draw size row 1
frame = tk.Frame(self) frame = ttk.Frame(self)
frame.grid(sticky="ew", pady=3) frame.grid(sticky="ew", pady=3)
frame.columnconfigure(1, weight=1) frame.columnconfigure(1, weight=1)
frame.columnconfigure(3, weight=1) frame.columnconfigure(3, weight=1)
label = tk.Label(frame, text="Width") label = ttk.Label(frame, text="Width")
label.grid(row=0, column=0, sticky="w") label.grid(row=0, column=0, sticky="w")
entry = tk.Entry(frame, textvariable=self.pixel_width) entry = ttk.Entry(frame, textvariable=self.pixel_width)
entry.grid(row=0, column=1, sticky="ew") entry.grid(row=0, column=1, sticky="ew")
label = tk.Label(frame, text="x Height") label = ttk.Label(frame, text="x Height")
label.grid(row=0, column=2, sticky="w") label.grid(row=0, column=2, sticky="w")
entry = tk.Entry(frame, textvariable=self.pixel_height) entry = ttk.Entry(frame, textvariable=self.pixel_height)
entry.grid(row=0, column=3, sticky="ew") entry.grid(row=0, column=3, sticky="ew")
label = tk.Label(frame, text="Pixels") label = ttk.Label(frame, text="Pixels")
label.grid(row=0, column=4, sticky="w") label.grid(row=0, column=4, sticky="w")
# draw size row 2 # draw size row 2
frame = tk.Frame(self) frame = ttk.Frame(self)
frame.grid(sticky="ew", pady=3) frame.grid(sticky="ew", pady=3)
frame.columnconfigure(1, weight=1) frame.columnconfigure(1, weight=1)
frame.columnconfigure(3, weight=1) frame.columnconfigure(3, weight=1)
label = tk.Label(frame, text="Width") label = ttk.Label(frame, text="Width")
label.grid(row=0, column=0, sticky="w") label.grid(row=0, column=0, sticky="w")
entry = tk.Entry(frame, textvariable=self.meters_width) entry = ttk.Entry(frame, textvariable=self.meters_width)
entry.grid(row=0, column=1, sticky="ew") entry.grid(row=0, column=1, sticky="ew")
label = tk.Label(frame, text="x Height") label = ttk.Label(frame, text="x Height")
label.grid(row=0, column=2, sticky="w") label.grid(row=0, column=2, sticky="w")
entry = tk.Entry(frame, textvariable=self.meters_height) entry = ttk.Entry(frame, textvariable=self.meters_height)
entry.grid(row=0, column=3, sticky="ew") entry.grid(row=0, column=3, sticky="ew")
label = tk.Label(frame, text="Meters") label = ttk.Label(frame, text="Meters")
label.grid(row=0, column=4, sticky="w") label.grid(row=0, column=4, sticky="w")
def draw_scale(self): def draw_scale(self):
label = tk.Label(self, text="Scale", font=self.section_font) label = ttk.Label(self, text="Scale", font=self.section_font)
label.grid(sticky="w") label.grid(sticky="w")
frame = tk.Frame(self) frame = ttk.Frame(self)
frame.grid(sticky="ew") frame.grid(sticky="ew")
frame.columnconfigure(1, weight=1) frame.columnconfigure(1, weight=1)
label = tk.Label(frame, text="100 Pixels =") label = ttk.Label(frame, text="100 Pixels =")
label.grid(row=0, column=0, sticky="w") label.grid(row=0, column=0, sticky="w")
entry = tk.Entry(frame, textvariable=self.scale) entry = ttk.Entry(frame, textvariable=self.scale)
entry.grid(row=0, column=1, sticky="ew") entry.grid(row=0, column=1, sticky="ew")
label = tk.Label(frame, text="Meters") label = ttk.Label(frame, text="Meters")
label.grid(row=0, column=2, sticky="w") label.grid(row=0, column=2, sticky="w")
def draw_reference_point(self): def draw_reference_point(self):
label = tk.Label(self, text="Reference point", font=self.section_font) label = ttk.Label(self, text="Reference point", font=self.section_font)
label.grid(sticky="w") label.grid(sticky="w")
label = tk.Label( label = ttk.Label(
self, text="Default is (0, 0), the upper left corner of the canvas" self, text="Default is (0, 0), the upper left corner of the canvas"
) )
label.grid(sticky="w") label.grid(sticky="w")
frame = tk.Frame(self) frame = ttk.Frame(self)
frame.grid(sticky="ew", pady=3) frame.grid(sticky="ew", pady=3)
frame.columnconfigure(1, weight=1) frame.columnconfigure(1, weight=1)
frame.columnconfigure(3, weight=1) frame.columnconfigure(3, weight=1)
label = tk.Label(frame, text="X") label = ttk.Label(frame, text="X")
label.grid(row=0, column=0, sticky="w") label.grid(row=0, column=0, sticky="w")
x_var = tk.StringVar(value=0) x_var = tk.StringVar(value=0)
entry = tk.Entry(frame, textvariable=x_var) entry = ttk.Entry(frame, textvariable=x_var)
entry.grid(row=0, column=1, sticky="ew") entry.grid(row=0, column=1, sticky="ew")
label = tk.Label(frame, text="Y") label = ttk.Label(frame, text="Y")
label.grid(row=0, column=2, sticky="w") label.grid(row=0, column=2, sticky="w")
y_var = tk.StringVar(value=0) y_var = tk.StringVar(value=0)
entry = tk.Entry(frame, textvariable=y_var) entry = ttk.Entry(frame, textvariable=y_var)
entry.grid(row=0, column=3, sticky="ew") entry.grid(row=0, column=3, sticky="ew")
label = tk.Label(self, text="Translates To") label = ttk.Label(self, text="Translates To")
label.grid(sticky="w") label.grid(sticky="w")
frame = tk.Frame(self) frame = ttk.Frame(self)
frame.grid(sticky="ew", pady=3) frame.grid(sticky="ew", pady=3)
frame.columnconfigure(1, weight=1) frame.columnconfigure(1, weight=1)
frame.columnconfigure(3, weight=1) frame.columnconfigure(3, weight=1)
frame.columnconfigure(5, weight=1) frame.columnconfigure(5, weight=1)
label = tk.Label(frame, text="Lat") label = ttk.Label(frame, text="Lat")
label.grid(row=0, column=0, sticky="w") label.grid(row=0, column=0, sticky="w")
entry = tk.Entry(frame, textvariable=self.lat) entry = ttk.Entry(frame, textvariable=self.lat)
entry.grid(row=0, column=1, sticky="ew") entry.grid(row=0, column=1, sticky="ew")
label = tk.Label(frame, text="Lon") label = ttk.Label(frame, text="Lon")
label.grid(row=0, column=2, sticky="w") label.grid(row=0, column=2, sticky="w")
entry = tk.Entry(frame, textvariable=self.lon) entry = ttk.Entry(frame, textvariable=self.lon)
entry.grid(row=0, column=3, sticky="ew") entry.grid(row=0, column=3, sticky="ew")
label = tk.Label(frame, text="Alt") label = ttk.Label(frame, text="Alt")
label.grid(row=0, column=4, sticky="w") label.grid(row=0, column=4, sticky="w")
entry = tk.Entry(frame, textvariable=self.alt) entry = ttk.Entry(frame, textvariable=self.alt)
entry.grid(row=0, column=5, sticky="ew") entry.grid(row=0, column=5, sticky="ew")
def draw_save_as_default(self): def draw_save_as_default(self):
button = tk.Checkbutton( button = ttk.Checkbutton(
self, text="Save as default?", variable=self.save_default self, text="Save as default?", variable=self.save_default
) )
button.grid(sticky="w", pady=3) button.grid(sticky="w", pady=3)
def draw_buttons(self): def draw_buttons(self):
frame = tk.Frame(self) frame = ttk.Frame(self)
frame.columnconfigure(0, weight=1) frame.columnconfigure(0, weight=1)
frame.columnconfigure(1, weight=1) frame.columnconfigure(1, weight=1)
frame.grid(sticky="ew") frame.grid(sticky="ew")
button = tk.Button(frame, text="Apply", command=self.click_apply) button = ttk.Button(frame, text="Apply", command=self.click_apply)
button.grid(row=0, column=0, pady=5, sticky="ew") button.grid(row=0, column=0, pady=5, sticky="ew")
button = tk.Button(frame, text="Cancel", command=self.destroy) button = ttk.Button(frame, text="Cancel", command=self.destroy)
button.grid(row=0, column=1, pady=5, sticky="ew") button.grid(row=0, column=1, pady=5, sticky="ew")
def redraw_grid(self): def redraw_grid(self):

View file

@ -1,8 +1,8 @@
import logging import logging
import tkinter as tk import tkinter as tk
from pathlib import Path from pathlib import Path
from tkinter import ttk
from coretk import appdirs
from coretk.coreclient import CustomNode from coretk.coreclient import CustomNode
from coretk.dialogs.dialog import Dialog from coretk.dialogs.dialog import Dialog
from coretk.dialogs.icondialog import IconDialog from coretk.dialogs.icondialog import IconDialog
@ -22,7 +22,7 @@ class ServicesSelectDialog(Dialog):
self.columnconfigure(0, weight=1) self.columnconfigure(0, weight=1)
self.rowconfigure(0, weight=1) self.rowconfigure(0, weight=1)
frame = tk.Frame(self) frame = ttk.Frame(self)
frame.grid(stick="nsew") frame.grid(stick="nsew")
frame.rowconfigure(0, weight=1) frame.rowconfigure(0, weight=1)
for i in range(3): for i in range(3):
@ -44,13 +44,13 @@ class ServicesSelectDialog(Dialog):
for service in sorted(self.current_services): for service in sorted(self.current_services):
self.current.listbox.insert(tk.END, service) self.current.listbox.insert(tk.END, service)
frame = tk.Frame(self) frame = ttk.Frame(self)
frame.grid(stick="ew") frame.grid(stick="ew")
for i in range(2): for i in range(2):
frame.columnconfigure(i, weight=1) frame.columnconfigure(i, weight=1)
button = tk.Button(frame, text="Save", command=self.destroy) button = ttk.Button(frame, text="Save", command=self.destroy)
button.grid(row=0, column=0, sticky="ew") button.grid(row=0, column=0, sticky="ew")
button = tk.Button(frame, text="Cancel", command=self.click_cancel) button = ttk.Button(frame, text="Cancel", command=self.click_cancel)
button.grid(row=0, column=1, sticky="ew") button.grid(row=0, column=1, sticky="ew")
# trigger group change # trigger group change
@ -103,7 +103,7 @@ class CustomNodesDialog(Dialog):
self.draw_buttons() self.draw_buttons()
def draw_node_config(self): def draw_node_config(self):
frame = tk.Frame(self) frame = ttk.Frame(self)
frame.grid(sticky="nsew") frame.grid(sticky="nsew")
frame.columnconfigure(0, weight=1) frame.columnconfigure(0, weight=1)
frame.rowconfigure(0, weight=1) frame.rowconfigure(0, weight=1)
@ -114,45 +114,45 @@ class CustomNodesDialog(Dialog):
for name in sorted(self.app.core.custom_nodes): for name in sorted(self.app.core.custom_nodes):
self.nodes_list.listbox.insert(tk.END, name) self.nodes_list.listbox.insert(tk.END, name)
frame = tk.Frame(frame) frame = ttk.Frame(frame)
frame.grid(row=0, column=2, sticky="nsew") frame.grid(row=0, column=2, sticky="nsew")
frame.columnconfigure(0, weight=1) frame.columnconfigure(0, weight=1)
entry = tk.Entry(frame, textvariable=self.name) entry = ttk.Entry(frame, textvariable=self.name)
entry.grid(sticky="ew") entry.grid(sticky="ew")
self.image_button = tk.Button(frame, text="Icon", command=self.click_icon) self.image_button = ttk.Button(frame, text="Icon", command=self.click_icon)
self.image_button.grid(sticky="ew") self.image_button.grid(sticky="ew")
button = tk.Button(frame, text="Services", command=self.click_services) button = ttk.Button(frame, text="Services", command=self.click_services)
button.grid(sticky="ew") button.grid(sticky="ew")
def draw_node_buttons(self): def draw_node_buttons(self):
frame = tk.Frame(self) frame = ttk.Frame(self)
frame.grid(pady=2, sticky="ew") frame.grid(pady=2, sticky="ew")
for i in range(3): for i in range(3):
frame.columnconfigure(i, weight=1) frame.columnconfigure(i, weight=1)
button = tk.Button(frame, text="Create", command=self.click_create) button = ttk.Button(frame, text="Create", command=self.click_create)
button.grid(row=0, column=0, sticky="ew") button.grid(row=0, column=0, sticky="ew")
self.edit_button = tk.Button( self.edit_button = ttk.Button(
frame, text="Edit", state=tk.DISABLED, command=self.click_edit frame, text="Edit", state=tk.DISABLED, command=self.click_edit
) )
self.edit_button.grid(row=0, column=1, sticky="ew") self.edit_button.grid(row=0, column=1, sticky="ew")
self.delete_button = tk.Button( self.delete_button = ttk.Button(
frame, text="Delete", state=tk.DISABLED, command=self.click_delete frame, text="Delete", state=tk.DISABLED, command=self.click_delete
) )
self.delete_button.grid(row=0, column=2, sticky="ew") self.delete_button.grid(row=0, column=2, sticky="ew")
def draw_buttons(self): def draw_buttons(self):
frame = tk.Frame(self) frame = ttk.Frame(self)
frame.grid(sticky="ew") frame.grid(sticky="ew")
for i in range(2): for i in range(2):
frame.columnconfigure(i, weight=1) frame.columnconfigure(i, weight=1)
button = tk.Button(frame, text="Save", command=self.click_save) button = ttk.Button(frame, text="Save", command=self.click_save)
button.grid(row=0, column=0, sticky="ew") button.grid(row=0, column=0, sticky="ew")
button = tk.Button(frame, text="Cancel", command=self.destroy) button = ttk.Button(frame, text="Cancel", command=self.destroy)
button.grid(row=0, column=1, sticky="ew") button.grid(row=0, column=1, sticky="ew")
def reset_values(self): def reset_values(self):
@ -189,7 +189,8 @@ class CustomNodesDialog(Dialog):
} }
) )
logging.info("saving custom nodes: %s", self.app.config["nodes"]) logging.info("saving custom nodes: %s", self.app.config["nodes"])
appdirs.save_config(self.app.config) self.app.save_config()
self.destroy()
def click_create(self): def click_create(self):
name = self.name.get() name = self.name.get()

View file

@ -58,18 +58,18 @@ class EmaneConfiguration(Dialog):
print("not implemented") print("not implemented")
def node_name_and_image(self): def node_name_and_image(self):
f = tk.Frame(self, bg="#d9d9d9") f = ttk.Frame(self)
lbl = tk.Label(f, text="Node name:", bg="#d9d9d9") lbl = ttk.Label(f, text="Node name:")
lbl.grid(row=0, column=0, padx=2, pady=2) lbl.grid(row=0, column=0, padx=2, pady=2)
e = tk.Entry(f, textvariable=self.create_text_variable(""), bg="white") e = ttk.Entry(f, textvariable=self.create_text_variable(""))
e.grid(row=0, column=1, padx=2, pady=2) e.grid(row=0, column=1, padx=2, pady=2)
cbb = ttk.Combobox(f, values=["(none)", "core1", "core2"], state="readonly") cbb = ttk.Combobox(f, values=["(none)", "core1", "core2"], state="readonly")
cbb.current(0) cbb.current(0)
cbb.grid(row=0, column=2, padx=2, pady=2) cbb.grid(row=0, column=2, padx=2, pady=2)
b = tk.Button(f, image=self.canvas_node.image) b = ttk.Button(f, image=self.canvas_node.image)
b.grid(row=0, column=3, padx=2, pady=2) b.grid(row=0, column=3, padx=2, pady=2)
f.grid(row=0, column=0, sticky="nsew") f.grid(row=0, column=0, sticky="nsew")
@ -96,13 +96,13 @@ class EmaneConfiguration(Dialog):
self.emane_config_frame.draw_config() self.emane_config_frame.draw_config()
self.emane_config_frame.grid(sticky="nsew") self.emane_config_frame.grid(sticky="nsew")
frame = tk.Frame(self.emane_dialog) frame = ttk.Frame(self.emane_dialog)
frame.grid(sticky="ew") frame.grid(sticky="ew")
for i in range(2): for i in range(2):
frame.columnconfigure(i, weight=1) frame.columnconfigure(i, weight=1)
b1 = tk.Button(frame, text="Appy", command=self.save_emane_option) b1 = ttk.Button(frame, text="Appy", command=self.save_emane_option)
b1.grid(row=0, column=0, sticky="ew") b1.grid(row=0, column=0, sticky="ew")
b2 = tk.Button(frame, text="Cancel", command=self.emane_dialog.destroy) b2 = ttk.Button(frame, text="Cancel", command=self.emane_dialog.destroy)
b2.grid(row=0, column=1, sticky="ew") b2.grid(row=0, column=1, sticky="ew")
self.emane_dialog.show() self.emane_dialog.show()
@ -170,35 +170,33 @@ class EmaneConfiguration(Dialog):
self.model_config_frame.grid(sticky="nsew") self.model_config_frame.grid(sticky="nsew")
self.model_config_frame.draw_config() self.model_config_frame.draw_config()
frame = tk.Frame(self.emane_model_dialog) frame = ttk.Frame(self.emane_model_dialog)
frame.grid(sticky="ew") frame.grid(sticky="ew")
for i in range(2): for i in range(2):
frame.columnconfigure(i, weight=1) frame.columnconfigure(i, weight=1)
b1 = tk.Button(frame, text="Apply", command=self.save_emane_model_options) b1 = ttk.Button(frame, text="Apply", command=self.save_emane_model_options)
b1.grid(row=0, column=0, sticky="ew") b1.grid(row=0, column=0, sticky="ew")
b2 = tk.Button(frame, text="Cancel", command=self.emane_model_dialog.destroy) b2 = ttk.Button(frame, text="Cancel", command=self.emane_model_dialog.destroy)
b2.grid(row=0, column=1, sticky="ew") b2.grid(row=0, column=1, sticky="ew")
self.emane_model_dialog.show() self.emane_model_dialog.show()
def draw_option_buttons(self, parent): def draw_option_buttons(self, parent):
f = tk.Frame(parent, bg="#d9d9d9") f = ttk.Frame(parent)
f.columnconfigure(0, weight=1) f.columnconfigure(0, weight=1)
f.columnconfigure(1, weight=1) f.columnconfigure(1, weight=1)
b = tk.Button( b = ttk.Button(
f, f,
text=self.emane_models[0] + " options", text=self.emane_models[0] + " options",
image=Images.get(ImageEnum.EDITNODE), image=Images.get(ImageEnum.EDITNODE),
compound=tk.RIGHT, compound=tk.RIGHT,
bg="#d9d9d9",
command=self.draw_model_options, command=self.draw_model_options,
) )
b.grid(row=0, column=0, padx=10, pady=2, sticky="nsew") b.grid(row=0, column=0, padx=10, pady=2, sticky="nsew")
b = tk.Button( b = ttk.Button(
f, f,
text="EMANE options", text="EMANE options",
image=Images.get(ImageEnum.EDITNODE), image=Images.get(ImageEnum.EDITNODE),
compound=tk.RIGHT, compound=tk.RIGHT,
bg="#d9d9d9",
command=self.draw_emane_options, command=self.draw_emane_options,
) )
b.grid(row=0, column=1, padx=10, pady=2, sticky="nsew") b.grid(row=0, column=1, padx=10, pady=2, sticky="nsew")
@ -233,21 +231,14 @@ class EmaneConfiguration(Dialog):
self.emane_models = [x.split("_")[1] for x in response.models] self.emane_models = [x.split("_")[1] for x in response.models]
# create combo box and its binding # create combo box and its binding
f = tk.Frame( f = ttk.Frame(parent)
parent,
bg="#d9d9d9",
highlightbackground="#b3b3b3",
highlightcolor="#b3b3b3",
highlightthickness=0.5,
bd=0,
)
self.emane_model_combobox = ttk.Combobox( self.emane_model_combobox = ttk.Combobox(
f, values=self.emane_models, state="readonly" f, values=self.emane_models, state="readonly"
) )
self.emane_model_combobox.grid() self.emane_model_combobox.grid()
self.emane_model_combobox.current(0) self.emane_model_combobox.current(0)
self.emane_model_combobox.bind("<<ComboboxSelected>>", self.combobox_select) self.emane_model_combobox.bind("<<ComboboxSelected>>", self.combobox_select)
f.grid(row=3, column=0, sticky=tk.W + tk.E) f.grid(row=3, column=0, sticky="ew")
def draw_text_label_and_entry(self, parent, label_text, entry_text): def draw_text_label_and_entry(self, parent, label_text, entry_text):
""" """
@ -257,10 +248,10 @@ class EmaneConfiguration(Dialog):
""" """
var = tk.StringVar() var = tk.StringVar()
var.set(entry_text) var.set(entry_text)
f = tk.Frame(parent) f = ttk.Frame(parent)
lbl = tk.Label(f, text=label_text) lbl = ttk.Label(f, text=label_text)
lbl.grid(row=0, column=0) lbl.grid(row=0, column=0)
e = tk.Entry(f, textvariable=var, bg="white") e = ttk.Entry(f, textvariable=var)
e.grid(row=0, column=1) e.grid(row=0, column=1)
f.grid(stick=tk.W, padx=2, pady=2) f.grid(stick=tk.W, padx=2, pady=2)
@ -271,44 +262,33 @@ class EmaneConfiguration(Dialog):
:return: nothing :return: nothing
""" """
# draw label # draw label
lbl = tk.Label(self, text="Emane") lbl = ttk.Label(self, text="Emane")
lbl.grid(row=1, column=0) lbl.grid(row=1, column=0)
# main frame that has emane wiki, a short description, emane models and the configure buttons # main frame that has emane wiki, a short description, emane models and the configure buttons
f = tk.Frame( f = ttk.Frame(self)
self,
bg="#d9d9d9",
highlightbackground="#b3b3b3",
highlightcolor="#b3b3b3",
highlightthickness=0.5,
bd=0,
relief=tk.RAISED,
)
f.columnconfigure(0, weight=1) f.columnconfigure(0, weight=1)
b = tk.Button( b = ttk.Button(
f, f,
image=Images.get(ImageEnum.EDITNODE), image=Images.get(ImageEnum.EDITNODE),
text="EMANE Wiki", text="EMANE Wiki",
compound=tk.RIGHT, compound=tk.RIGHT,
relief=tk.RAISED,
bg="#d9d9d9",
command=lambda: webbrowser.open_new( command=lambda: webbrowser.open_new(
"https://github.com/adjacentlink/emane/wiki" "https://github.com/adjacentlink/emane/wiki"
), ),
) )
b.grid(row=0, column=0, sticky=tk.W) b.grid(row=0, column=0, sticky="w")
lbl = tk.Label( lbl = ttk.Label(
f, f,
text="The EMANE emulation system provides more complex wireless radio emulation " text="The EMANE emulation system provides more complex wireless radio emulation "
"\nusing pluggable MAC and PHY modules. Refer to the wiki for configuration option details", "\nusing pluggable MAC and PHY modules. Refer to the wiki for configuration option details",
bg="#d9d9d9",
) )
lbl.grid(row=1, column=0, sticky="nsew") lbl.grid(row=1, column=0, sticky="nsew")
lbl = tk.Label(f, text="EMANE Models", bg="#d9d9d9") lbl = ttk.Label(f, text="EMANE Models")
lbl.grid(row=2, column=0, sticky=tk.W) lbl.grid(row=2, column=0, sticky="w")
self.draw_emane_models(f) self.draw_emane_models(f)
self.draw_option_buttons(f) self.draw_option_buttons(f)
@ -325,12 +305,12 @@ class EmaneConfiguration(Dialog):
:return: :return:
""" """
f = tk.Frame(self, bg="#d9d9d9") f = ttk.Frame(self)
f.columnconfigure(0, weight=1) f.columnconfigure(0, weight=1)
f.columnconfigure(1, weight=1) f.columnconfigure(1, weight=1)
b = tk.Button(f, text="Link to all routers", bg="#d9d9d9") b = ttk.Button(f, text="Link to all routers")
b.grid(row=0, column=0, padx=10, pady=2, sticky="nsew") b.grid(row=0, column=0, padx=10, pady=2, sticky="nsew")
b = tk.Button(f, text="Choose WLAN members", bg="#d9d9d9") b = ttk.Button(f, text="Choose WLAN members")
b.grid(row=0, column=1, padx=10, pady=2, sticky="nsew") b.grid(row=0, column=1, padx=10, pady=2, sticky="nsew")
f.grid(row=5, column=0, sticky="nsew") f.grid(row=5, column=0, sticky="nsew")
@ -340,12 +320,12 @@ class EmaneConfiguration(Dialog):
self.destroy() self.destroy()
def draw_apply_and_cancel(self): def draw_apply_and_cancel(self):
f = tk.Frame(self, bg="#d9d9d9") f = ttk.Frame(self)
f.columnconfigure(0, weight=1) f.columnconfigure(0, weight=1)
f.columnconfigure(1, weight=1) f.columnconfigure(1, weight=1)
b = tk.Button(f, text="Apply", bg="#d9d9d9", command=self.apply) b = ttk.Button(f, text="Apply", command=self.apply)
b.grid(row=0, column=0, padx=10, pady=2, sticky="nsew") b.grid(row=0, column=0, padx=10, pady=2, sticky="nsew")
b = tk.Button(f, text="Cancel", bg="#d9d9d9", command=self.destroy) b = ttk.Button(f, text="Cancel", command=self.destroy)
b.grid(row=0, column=1, padx=10, pady=2, sticky="nsew") b.grid(row=0, column=1, padx=10, pady=2, sticky="nsew")
f.grid(sticky="nsew") f.grid(sticky="nsew")

View file

@ -19,14 +19,14 @@ class HookDialog(Dialog):
self.rowconfigure(1, weight=1) self.rowconfigure(1, weight=1)
# name and states # name and states
frame = tk.Frame(self) frame = ttk.Frame(self)
frame.grid(row=0, sticky="ew", pady=2) frame.grid(row=0, sticky="ew", pady=2)
frame.columnconfigure(0, weight=2) frame.columnconfigure(0, weight=2)
frame.columnconfigure(1, weight=7) frame.columnconfigure(1, weight=7)
frame.columnconfigure(2, weight=1) frame.columnconfigure(2, weight=1)
label = tk.Label(frame, text="Name") label = ttk.Label(frame, text="Name")
label.grid(row=0, column=0, sticky="ew") label.grid(row=0, column=0, sticky="ew")
entry = tk.Entry(frame, textvariable=self.name) entry = ttk.Entry(frame, textvariable=self.name)
entry.grid(row=0, column=1, sticky="ew") entry.grid(row=0, column=1, sticky="ew")
values = tuple(x for x in core_pb2.SessionState.Enum.keys() if x != "NONE") values = tuple(x for x in core_pb2.SessionState.Enum.keys() if x != "NONE")
initial_state = core_pb2.SessionState.Enum.Name(core_pb2.SessionState.RUNTIME) initial_state = core_pb2.SessionState.Enum.Name(core_pb2.SessionState.RUNTIME)
@ -39,7 +39,7 @@ class HookDialog(Dialog):
combobox.bind("<<ComboboxSelected>>", self.state_change) combobox.bind("<<ComboboxSelected>>", self.state_change)
# data # data
frame = tk.Frame(self) frame = ttk.Frame(self)
frame.columnconfigure(0, weight=1) frame.columnconfigure(0, weight=1)
frame.rowconfigure(0, weight=1) frame.rowconfigure(0, weight=1)
frame.grid(row=1, sticky="nsew", pady=2) frame.grid(row=1, sticky="nsew", pady=2)
@ -53,19 +53,19 @@ class HookDialog(Dialog):
), ),
) )
self.data.grid(row=0, column=0, sticky="nsew") self.data.grid(row=0, column=0, sticky="nsew")
scrollbar = tk.Scrollbar(frame) scrollbar = ttk.Scrollbar(frame)
scrollbar.grid(row=0, column=1, sticky="ns") scrollbar.grid(row=0, column=1, sticky="ns")
self.data.config(yscrollcommand=scrollbar.set) self.data.config(yscrollcommand=scrollbar.set)
scrollbar.config(command=self.data.yview) scrollbar.config(command=self.data.yview)
# button row # button row
frame = tk.Frame(self) frame = ttk.Frame(self)
frame.grid(row=2, sticky="ew", pady=2) frame.grid(row=2, sticky="ew", pady=2)
for i in range(2): for i in range(2):
frame.columnconfigure(i, weight=1) frame.columnconfigure(i, weight=1)
button = tk.Button(frame, text="Save", command=lambda: self.save()) button = ttk.Button(frame, text="Save", command=lambda: self.save())
button.grid(row=0, column=0, sticky="ew") button.grid(row=0, column=0, sticky="ew")
button = tk.Button(frame, text="Cancel", command=lambda: self.destroy()) button = ttk.Button(frame, text="Cancel", command=lambda: self.destroy())
button.grid(row=0, column=1, sticky="ew") button.grid(row=0, column=1, sticky="ew")
def state_change(self, event): def state_change(self, event):
@ -106,21 +106,21 @@ class HooksDialog(Dialog):
self.listbox.bind("<<ListboxSelect>>", self.select) self.listbox.bind("<<ListboxSelect>>", self.select)
for hook_file in self.app.core.hooks: for hook_file in self.app.core.hooks:
self.listbox.insert(tk.END, hook_file) self.listbox.insert(tk.END, hook_file)
frame = tk.Frame(self) frame = ttk.Frame(self)
frame.grid(row=1, sticky="ew") frame.grid(row=1, sticky="ew")
for i in range(4): for i in range(4):
frame.columnconfigure(i, weight=1) frame.columnconfigure(i, weight=1)
button = tk.Button(frame, text="Create", command=self.click_create) button = ttk.Button(frame, text="Create", command=self.click_create)
button.grid(row=0, column=0, sticky="ew") button.grid(row=0, column=0, sticky="ew")
self.edit_button = tk.Button( self.edit_button = ttk.Button(
frame, text="Edit", state=tk.DISABLED, command=self.click_edit frame, text="Edit", state=tk.DISABLED, command=self.click_edit
) )
self.edit_button.grid(row=0, column=1, sticky="ew") self.edit_button.grid(row=0, column=1, sticky="ew")
self.delete_button = tk.Button( self.delete_button = ttk.Button(
frame, text="Delete", state=tk.DISABLED, command=self.click_delete frame, text="Delete", state=tk.DISABLED, command=self.click_delete
) )
self.delete_button.grid(row=0, column=2, sticky="ew") self.delete_button.grid(row=0, column=2, sticky="ew")
button = tk.Button(frame, text="Cancel", command=lambda: self.destroy()) button = ttk.Button(frame, text="Cancel", command=lambda: self.destroy())
button.grid(row=0, column=3, sticky="ew") button.grid(row=0, column=3, sticky="ew")
def click_create(self): def click_create(self):

View file

@ -1,7 +1,7 @@
import tkinter as tk import tkinter as tk
from tkinter import filedialog from tkinter import filedialog, ttk
from coretk.appdirs import ICONS_PATH from coretk.appconfig import ICONS_PATH
from coretk.dialogs.dialog import Dialog from coretk.dialogs.dialog import Dialog
from coretk.images import Images from coretk.images import Images
@ -18,30 +18,30 @@ class IconDialog(Dialog):
self.columnconfigure(0, weight=1) self.columnconfigure(0, weight=1)
# row one # row one
frame = tk.Frame(self) frame = ttk.Frame(self)
frame.grid(row=0, column=0, pady=2, sticky="ew") frame.grid(row=0, column=0, pady=2, sticky="ew")
frame.columnconfigure(0, weight=1) frame.columnconfigure(0, weight=1)
frame.columnconfigure(1, weight=3) frame.columnconfigure(1, weight=3)
label = tk.Label(frame, text="Image") label = ttk.Label(frame, text="Image")
label.grid(row=0, column=0, sticky="ew") label.grid(row=0, column=0, sticky="ew")
entry = tk.Entry(frame, textvariable=self.file_path) entry = ttk.Entry(frame, textvariable=self.file_path)
entry.grid(row=0, column=1, sticky="ew") entry.grid(row=0, column=1, sticky="ew")
button = tk.Button(frame, text="...", command=self.click_file) button = ttk.Button(frame, text="...", command=self.click_file)
button.grid(row=0, column=2) button.grid(row=0, column=2)
# row two # row two
self.image_label = tk.Label(self, image=self.image) self.image_label = ttk.Label(self, image=self.image, anchor=tk.CENTER)
self.image_label.grid(row=1, column=0, pady=2, sticky="ew") self.image_label.grid(row=1, column=0, pady=2, sticky="ew")
# row three # row three
frame = tk.Frame(self) frame = ttk.Frame(self)
frame.grid(row=2, column=0, sticky="ew") frame.grid(row=2, column=0, sticky="ew")
frame.columnconfigure(0, weight=1) frame.columnconfigure(0, weight=1)
frame.columnconfigure(1, weight=1) frame.columnconfigure(1, weight=1)
button = tk.Button(frame, text="Apply", command=self.destroy) button = ttk.Button(frame, text="Apply", command=self.destroy)
button.grid(row=0, column=0, sticky="ew") button.grid(row=0, column=0, sticky="ew")
button = tk.Button(frame, text="Cancel", command=self.click_cancel) button = ttk.Button(frame, text="Cancel", command=self.click_cancel)
button.grid(row=0, column=1, sticky="ew") button.grid(row=0, column=1, sticky="ew")
def click_file(self): def click_file(self):

View file

@ -0,0 +1,149 @@
import tkinter as tk
from tkinter import ttk
from coretk.coreclient import Observer
from coretk.dialogs.dialog import Dialog
class ObserverDialog(Dialog):
def __init__(self, master, app):
super().__init__(master, app, "Observer Widgets", modal=True)
self.observers = None
self.save_button = None
self.delete_button = None
self.selected = None
self.selected_index = None
self.name = tk.StringVar()
self.cmd = tk.StringVar()
self.draw()
def draw(self):
self.columnconfigure(0, weight=1)
self.rowconfigure(0, weight=1)
self.draw_listbox()
self.draw_form_fields()
self.draw_config_buttons()
self.draw_apply_buttons()
def draw_listbox(self):
frame = ttk.Frame(self)
frame.grid(sticky="nsew")
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
)
self.observers.grid(row=0, column=0, sticky="nsew")
self.observers.bind("<<ListboxSelect>>", 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)
frame.grid(sticky="ew")
frame.columnconfigure(1, weight=1)
label = ttk.Label(frame, text="Name")
label.grid(row=0, column=0, sticky="w")
entry = ttk.Entry(frame, textvariable=self.name)
entry.grid(row=0, column=1, sticky="ew")
label = ttk.Label(frame, text="Command")
label.grid(row=1, column=0, sticky="w")
entry = ttk.Entry(frame, textvariable=self.cmd)
entry.grid(row=1, column=1, sticky="ew")
def draw_config_buttons(self):
frame = ttk.Frame(self)
frame.grid(pady=2, sticky="ew")
for i in range(3):
frame.columnconfigure(i, weight=1)
button = ttk.Button(frame, text="Create", command=self.click_create)
button.grid(row=0, column=0, sticky="ew")
self.save_button = ttk.Button(
frame, text="Save", state=tk.DISABLED, command=self.click_save
)
self.save_button.grid(row=0, column=1, sticky="ew")
self.delete_button = ttk.Button(
frame, text="Delete", state=tk.DISABLED, command=self.click_delete
)
self.delete_button.grid(row=0, column=2, sticky="ew")
def draw_apply_buttons(self):
frame = ttk.Frame(self)
frame.grid(sticky="ew")
for i in range(2):
frame.columnconfigure(i, weight=1)
button = ttk.Button(frame, text="Save", command=self.click_save_config)
button.grid(row=0, column=0, sticky="ew")
button = ttk.Button(frame, text="Cancel", command=self.destroy)
button.grid(row=0, column=1, sticky="ew")
def click_save_config(self):
observers = []
for name in sorted(self.app.core.custom_observers):
observer = self.app.core.custom_observers[name]
observers.append({"name": observer.name, "cmd": observer.cmd})
self.app.config["observers"] = observers
self.app.save_config()
self.destroy()
def click_create(self):
name = self.name.get()
if name not in self.app.core.custom_observers:
cmd = self.cmd.get()
observer = Observer(name, cmd)
self.app.core.custom_observers[name] = observer
self.observers.insert(tk.END, name)
def click_save(self):
name = self.name.get()
if self.selected:
previous_name = self.selected
self.selected = name
observer = self.app.core.custom_observers.pop(previous_name)
observer.name = name
observer.cmd = self.cmd.get()
self.app.core.custom_observers[name] = observer
self.observers.delete(self.selected_index)
self.observers.insert(self.selected_index, name)
self.observers.selection_set(self.selected_index)
def click_delete(self):
if self.selected:
self.observers.delete(self.selected_index)
del self.app.core.custom_observers[self.selected]
self.selected = None
self.selected_index = None
self.name.set("")
self.cmd.set("")
self.observers.selection_clear(0, tk.END)
self.save_button.config(state=tk.DISABLED)
self.delete_button.config(state=tk.DISABLED)
def handle_observer_change(self, event):
selection = self.observers.curselection()
if selection:
self.selected_index = selection[0]
self.selected = self.observers.get(self.selected_index)
observer = self.app.core.custom_observers[self.selected]
self.name.set(observer.name)
self.cmd.set(observer.cmd)
self.save_button.config(state=tk.NORMAL)
self.delete_button.config(state=tk.NORMAL)
else:
self.selected_index = None
self.selected = None
self.save_button.config(state=tk.DISABLED)
self.delete_button.config(state=tk.DISABLED)

View file

@ -1,148 +0,0 @@
import tkinter as tk
from coretk.dialogs.dialog import Dialog
class Widget:
def __init__(self, name, command):
self.name = name
self.command = command
class ObserverWidgetsDialog(Dialog):
def __init__(self, master, app):
super().__init__(master, app, "Observer Widgets", modal=True)
self.config_widgets = {}
self.widgets = None
self.save_button = None
self.delete_button = None
self.selected = None
self.selected_index = None
self.name = tk.StringVar()
self.command = tk.StringVar()
self.draw()
def draw(self):
self.columnconfigure(0, weight=1)
self.rowconfigure(0, weight=1)
self.draw_widgets()
self.draw_widget_fields()
self.draw_widget_buttons()
self.draw_apply_buttons()
def draw_widgets(self):
frame = tk.Frame(self)
frame.grid(sticky="nsew")
frame.columnconfigure(0, weight=1)
frame.rowconfigure(0, weight=1)
scrollbar = tk.Scrollbar(frame, orient=tk.VERTICAL)
scrollbar.grid(row=0, column=1, sticky="ns")
self.widgets = tk.Listbox(
frame, selectmode=tk.SINGLE, yscrollcommand=scrollbar.set
)
self.widgets.grid(row=0, column=0, sticky="nsew")
self.widgets.bind("<<ListboxSelect>>", self.handle_widget_change)
scrollbar.config(command=self.widgets.yview)
def draw_widget_fields(self):
frame = tk.Frame(self)
frame.grid(sticky="ew")
frame.columnconfigure(1, weight=1)
label = tk.Label(frame, text="Name")
label.grid(row=0, column=0, sticky="w")
entry = tk.Entry(frame, textvariable=self.name)
entry.grid(row=0, column=1, sticky="ew")
label = tk.Label(frame, text="Command")
label.grid(row=1, column=0, sticky="w")
entry = tk.Entry(frame, textvariable=self.command)
entry.grid(row=1, column=1, sticky="ew")
def draw_widget_buttons(self):
frame = tk.Frame(self)
frame.grid(pady=2, sticky="ew")
for i in range(3):
frame.columnconfigure(i, weight=1)
button = tk.Button(frame, text="Create", command=self.click_create)
button.grid(row=0, column=0, sticky="ew")
self.save_button = tk.Button(
frame, text="Save", state=tk.DISABLED, command=self.click_save
)
self.save_button.grid(row=0, column=1, sticky="ew")
self.delete_button = tk.Button(
frame, text="Delete", state=tk.DISABLED, command=self.click_delete
)
self.delete_button.grid(row=0, column=2, sticky="ew")
def draw_apply_buttons(self):
frame = tk.Frame(self)
frame.grid(sticky="ew")
for i in range(2):
frame.columnconfigure(i, weight=1)
button = tk.Button(
frame, text="Save Configuration", command=self.click_save_configuration
)
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_save_configuration(self):
pass
def click_create(self):
name = self.name.get()
if name not in self.config_widgets:
command = self.command.get()
widget = Widget(name, command)
self.config_widgets[name] = widget
self.widgets.insert(tk.END, name)
def click_save(self):
name = self.name.get()
if self.selected:
previous_name = self.selected
self.selected = name
widget = self.config_widgets.pop(previous_name)
widget.name = name
widget.command = self.command.get()
self.config_widgets[name] = widget
self.widgets.delete(self.selected_index)
self.widgets.insert(self.selected_index, name)
self.widgets.selection_set(self.selected_index)
def click_delete(self):
if self.selected:
self.widgets.delete(self.selected_index)
del self.config_widgets[self.selected]
self.selected = None
self.selected_index = None
self.name.set("")
self.command.set("")
self.widgets.selection_clear(0, tk.END)
self.save_button.config(state=tk.DISABLED)
self.delete_button.config(state=tk.DISABLED)
def handle_widget_change(self, event):
selection = self.widgets.curselection()
if selection:
self.selected_index = selection[0]
self.selected = self.widgets.get(self.selected_index)
widget = self.config_widgets[self.selected]
self.name.set(widget.name)
self.command.set(widget.command)
self.save_button.config(state=tk.NORMAL)
self.delete_button.config(state=tk.NORMAL)
else:
self.selected_index = None
self.selected = None
self.save_button.config(state=tk.DISABLED)
self.delete_button.config(state=tk.DISABLED)

View file

@ -0,0 +1,67 @@
import tkinter as tk
from tkinter import ttk
from coretk import appconfig
from coretk.dialogs.dialog import Dialog
class PreferencesDialog(Dialog):
def __init__(self, master, app):
super().__init__(master, app, "Preferences", modal=True)
preferences = self.app.config["preferences"]
self.editor = tk.StringVar(value=preferences["editor"])
self.terminal = tk.StringVar(value=preferences["terminal"])
self.gui3d = tk.StringVar(value=preferences["gui3d"])
self.draw()
def draw(self):
self.columnconfigure(0, weight=1)
self.draw_programs()
self.draw_buttons()
def draw_programs(self):
frame = ttk.LabelFrame(self, text="Programs")
frame.grid(sticky="ew", pady=2)
frame.columnconfigure(1, weight=1)
label = ttk.Label(frame, text="Editor")
label.grid(row=0, column=0, pady=2, padx=2, sticky="w")
combobox = ttk.Combobox(
frame, textvariable=self.editor, values=appconfig.EDITORS, state="readonly"
)
combobox.grid(row=0, column=1, sticky="ew")
label = ttk.Label(frame, text="Terminal")
label.grid(row=1, column=0, pady=2, padx=2, sticky="w")
combobox = ttk.Combobox(
frame,
textvariable=self.terminal,
values=appconfig.TERMINALS,
state="readonly",
)
combobox.grid(row=1, column=1, sticky="ew")
label = ttk.Label(frame, text="3D GUI")
label.grid(row=2, column=0, pady=2, padx=2, sticky="w")
entry = ttk.Entry(frame, textvariable=self.gui3d)
entry.grid(row=2, column=1, sticky="ew")
def draw_buttons(self):
frame = ttk.Frame(self)
frame.grid(sticky="ew")
for i in range(2):
frame.columnconfigure(i, weight=1)
button = ttk.Button(frame, text="Save", command=self.click_save)
button.grid(row=0, column=0, sticky="ew")
button = ttk.Button(frame, text="Cancel", command=self.destroy)
button.grid(row=0, column=1, sticky="ew")
def click_save(self):
preferences = self.app.config["preferences"]
preferences["terminal"] = self.terminal.get()
preferences["editor"] = self.editor.get()
preferences["gui3d"] = self.gui3d.get()
self.app.save_config()
self.destroy()

View file

@ -1,6 +1,6 @@
import tkinter as tk import tkinter as tk
from tkinter import ttk
from coretk import appdirs
from coretk.coreclient import CoreServer from coretk.coreclient import CoreServer
from coretk.dialogs.dialog import Dialog from coretk.dialogs.dialog import Dialog
@ -31,12 +31,12 @@ class ServersDialog(Dialog):
self.draw_apply_buttons() self.draw_apply_buttons()
def draw_servers(self): def draw_servers(self):
frame = tk.Frame(self) frame = ttk.Frame(self)
frame.grid(pady=2, sticky="nsew") frame.grid(pady=2, sticky="nsew")
frame.columnconfigure(0, weight=1) frame.columnconfigure(0, weight=1)
frame.rowconfigure(0, weight=1) frame.rowconfigure(0, weight=1)
scrollbar = tk.Scrollbar(frame, orient=tk.VERTICAL) scrollbar = ttk.Scrollbar(frame, orient=tk.VERTICAL)
scrollbar.grid(row=0, column=1, sticky="ns") scrollbar.grid(row=0, column=1, sticky="ns")
self.servers = tk.Listbox( self.servers = tk.Listbox(
@ -51,61 +51,61 @@ class ServersDialog(Dialog):
scrollbar.config(command=self.servers.yview) scrollbar.config(command=self.servers.yview)
def draw_server_configuration(self): def draw_server_configuration(self):
label = tk.Label(self, text="Server Configuration") label = ttk.Label(self, text="Server Configuration")
label.grid(pady=2, sticky="ew") label.grid(pady=2, sticky="ew")
frame = tk.Frame(self) frame = ttk.Frame(self)
frame.grid(pady=2, sticky="ew") frame.grid(pady=2, sticky="ew")
frame.columnconfigure(1, weight=1) frame.columnconfigure(1, weight=1)
frame.columnconfigure(3, weight=1) frame.columnconfigure(3, weight=1)
frame.columnconfigure(5, weight=1) frame.columnconfigure(5, weight=1)
label = tk.Label(frame, text="Name") label = ttk.Label(frame, text="Name")
label.grid(row=0, column=0, sticky="w") label.grid(row=0, column=0, sticky="w")
entry = tk.Entry(frame, textvariable=self.name) entry = ttk.Entry(frame, textvariable=self.name)
entry.grid(row=0, column=1, sticky="ew") entry.grid(row=0, column=1, sticky="ew")
label = tk.Label(frame, text="Address") label = ttk.Label(frame, text="Address")
label.grid(row=0, column=2, sticky="w") label.grid(row=0, column=2, sticky="w")
entry = tk.Entry(frame, textvariable=self.address) entry = ttk.Entry(frame, textvariable=self.address)
entry.grid(row=0, column=3, sticky="ew") entry.grid(row=0, column=3, sticky="ew")
label = tk.Label(frame, text="Port") label = ttk.Label(frame, text="Port")
label.grid(row=0, column=4, sticky="w") label.grid(row=0, column=4, sticky="w")
entry = tk.Entry(frame, textvariable=self.port) entry = ttk.Entry(frame, textvariable=self.port)
entry.grid(row=0, column=5, sticky="ew") entry.grid(row=0, column=5, sticky="ew")
def draw_servers_buttons(self): def draw_servers_buttons(self):
frame = tk.Frame(self) frame = ttk.Frame(self)
frame.grid(pady=2, sticky="ew") frame.grid(pady=2, sticky="ew")
for i in range(3): for i in range(3):
frame.columnconfigure(i, weight=1) frame.columnconfigure(i, weight=1)
button = tk.Button(frame, text="Create", command=self.click_create) button = ttk.Button(frame, text="Create", command=self.click_create)
button.grid(row=0, column=0, sticky="ew") button.grid(row=0, column=0, sticky="ew")
self.save_button = tk.Button( self.save_button = ttk.Button(
frame, text="Save", state=tk.DISABLED, command=self.click_save frame, text="Save", state=tk.DISABLED, command=self.click_save
) )
self.save_button.grid(row=0, column=1, sticky="ew") self.save_button.grid(row=0, column=1, sticky="ew")
self.delete_button = tk.Button( self.delete_button = ttk.Button(
frame, text="Delete", state=tk.DISABLED, command=self.click_delete frame, text="Delete", state=tk.DISABLED, command=self.click_delete
) )
self.delete_button.grid(row=0, column=2, sticky="ew") self.delete_button.grid(row=0, column=2, sticky="ew")
def draw_apply_buttons(self): def draw_apply_buttons(self):
frame = tk.Frame(self) frame = ttk.Frame(self)
frame.grid(sticky="ew") frame.grid(sticky="ew")
for i in range(2): for i in range(2):
frame.columnconfigure(i, weight=1) frame.columnconfigure(i, weight=1)
button = tk.Button( button = ttk.Button(
frame, text="Save Configuration", command=self.click_save_configuration frame, text="Save Configuration", command=self.click_save_configuration
) )
button.grid(row=0, column=0, sticky="ew") button.grid(row=0, column=0, sticky="ew")
button = tk.Button(frame, text="Cancel", command=self.destroy) button = ttk.Button(frame, text="Cancel", command=self.destroy)
button.grid(row=0, column=1, sticky="ew") button.grid(row=0, column=1, sticky="ew")
def click_save_configuration(self): def click_save_configuration(self):
@ -116,7 +116,8 @@ class ServersDialog(Dialog):
{"name": server.name, "address": server.address, "port": server.port} {"name": server.name, "address": server.address, "port": server.port}
) )
self.app.config["servers"] = servers self.app.config["servers"] = servers
appdirs.save_config(self.app.config) self.app.save_config()
self.destroy()
def click_create(self): def click_create(self):
name = self.name.get() name = self.name.get()

View file

@ -1,5 +1,5 @@
import logging import logging
import tkinter as tk from tkinter import ttk
from coretk.dialogs.dialog import Dialog from coretk.dialogs.dialog import Dialog
from coretk.widgets import ConfigFrame from coretk.widgets import ConfigFrame
@ -26,13 +26,13 @@ class SessionOptionsDialog(Dialog):
self.config_frame.draw_config() self.config_frame.draw_config()
self.config_frame.grid(sticky="nsew") self.config_frame.grid(sticky="nsew")
frame = tk.Frame(self) frame = ttk.Frame(self)
frame.grid(sticky="ew") frame.grid(sticky="ew")
for i in range(2): for i in range(2):
frame.columnconfigure(i, weight=1) frame.columnconfigure(i, weight=1)
button = tk.Button(frame, text="Save", command=self.save) button = ttk.Button(frame, text="Save", command=self.save)
button.grid(row=0, column=0, pady=PAD_Y, padx=PAD_X, sticky="ew") button.grid(row=0, column=0, pady=PAD_Y, padx=PAD_X, sticky="ew")
button = tk.Button(frame, text="Cancel", command=self.destroy) button = ttk.Button(frame, text="Cancel", command=self.destroy)
button.grid(row=0, column=1, pady=PAD_Y, padx=PAD_X, sticky="ew") button.grid(row=0, column=1, pady=PAD_Y, padx=PAD_X, sticky="ew")
def save(self): def save(self):

View file

@ -1,6 +1,6 @@
import logging import logging
import tkinter as tk import tkinter as tk
from tkinter.ttk import Scrollbar, Treeview from tkinter import ttk
from core.api.grpc import core_pb2 from core.api.grpc import core_pb2
from coretk.dialogs.dialog import Dialog from coretk.dialogs.dialog import Dialog
@ -9,12 +9,6 @@ from coretk.images import ImageEnum, Images
class SessionsDialog(Dialog): class SessionsDialog(Dialog):
def __init__(self, master, app): def __init__(self, master, app):
"""
create session table instance
:param coretk.coreclient.CoreClient grpc: coregrpc
:param root.master master:
"""
super().__init__(master, app, "Sessions", modal=True) super().__init__(master, app, "Sessions", modal=True)
self.selected = False self.selected = False
self.selected_id = None self.selected_id = None
@ -32,7 +26,7 @@ class SessionsDialog(Dialog):
write a short description write a short description
:return: nothing :return: nothing
""" """
label = tk.Label( label = ttk.Label(
self, self,
text="Below is a list of active CORE sessions. Double-click to \n" text="Below is a list of active CORE sessions. Double-click to \n"
"connect to an existing session. Usually, only sessions in \n" "connect to an existing session. Usually, only sessions in \n"
@ -42,7 +36,9 @@ class SessionsDialog(Dialog):
label.grid(row=0, sticky="ew", pady=5) label.grid(row=0, sticky="ew", pady=5)
def draw_tree(self): def draw_tree(self):
self.tree = Treeview(self, columns=("id", "state", "nodes"), show="headings") self.tree = ttk.Treeview(
self, columns=("id", "state", "nodes"), show="headings"
)
self.tree.grid(row=1, sticky="nsew") self.tree.grid(row=1, sticky="nsew")
self.tree.column("id", stretch=tk.YES) self.tree.column("id", stretch=tk.YES)
self.tree.heading("id", text="ID") self.tree.heading("id", text="ID")
@ -64,20 +60,20 @@ class SessionsDialog(Dialog):
self.tree.bind("<Double-1>", self.on_selected) self.tree.bind("<Double-1>", self.on_selected)
self.tree.bind("<<TreeviewSelect>>", self.click_select) self.tree.bind("<<TreeviewSelect>>", self.click_select)
yscrollbar = Scrollbar(self, orient="vertical", command=self.tree.yview) yscrollbar = ttk.Scrollbar(self, orient="vertical", command=self.tree.yview)
yscrollbar.grid(row=1, column=1, sticky="ns") yscrollbar.grid(row=1, column=1, sticky="ns")
self.tree.configure(yscrollcommand=yscrollbar.set) self.tree.configure(yscrollcommand=yscrollbar.set)
xscrollbar = Scrollbar(self, orient="horizontal", command=self.tree.xview) xscrollbar = ttk.Scrollbar(self, orient="horizontal", command=self.tree.xview)
xscrollbar.grid(row=2, sticky="ew", pady=5) xscrollbar.grid(row=2, sticky="ew", pady=5)
self.tree.configure(xscrollcommand=xscrollbar.set) self.tree.configure(xscrollcommand=xscrollbar.set)
def draw_buttons(self): def draw_buttons(self):
frame = tk.Frame(self) frame = ttk.Frame(self)
for i in range(4): for i in range(4):
frame.columnconfigure(i, weight=1) frame.columnconfigure(i, weight=1)
frame.grid(row=3, sticky="ew") frame.grid(row=3, sticky="ew")
b = tk.Button( b = ttk.Button(
frame, frame,
image=Images.get(ImageEnum.DOCUMENTNEW), image=Images.get(ImageEnum.DOCUMENTNEW),
text="New", text="New",
@ -85,7 +81,7 @@ class SessionsDialog(Dialog):
command=self.click_new, command=self.click_new,
) )
b.grid(row=0, padx=2, sticky="ew") b.grid(row=0, padx=2, sticky="ew")
b = tk.Button( b = ttk.Button(
frame, frame,
image=Images.get(ImageEnum.FILEOPEN), image=Images.get(ImageEnum.FILEOPEN),
text="Connect", text="Connect",
@ -93,7 +89,7 @@ class SessionsDialog(Dialog):
command=self.click_connect, command=self.click_connect,
) )
b.grid(row=0, column=1, padx=2, sticky="ew") b.grid(row=0, column=1, padx=2, sticky="ew")
b = tk.Button( b = ttk.Button(
frame, frame,
image=Images.get(ImageEnum.EDITDELETE), image=Images.get(ImageEnum.EDITDELETE),
text="Shutdown", text="Shutdown",
@ -101,7 +97,7 @@ class SessionsDialog(Dialog):
command=self.click_shutdown, command=self.click_shutdown,
) )
b.grid(row=0, column=2, padx=2, sticky="ew") b.grid(row=0, column=2, padx=2, sticky="ew")
b = tk.Button(frame, text="Cancel", command=self.click_new) b = ttk.Button(frame, text="Cancel", command=self.click_new)
b.grid(row=0, column=3, padx=2, sticky="ew") b.grid(row=0, column=3, padx=2, sticky="ew")
def click_new(self): def click_new(self):

View file

@ -150,7 +150,7 @@ class CanvasGraph(tk.Canvas):
node.type, node.model node.type, node.model
) )
n = CanvasNode( n = CanvasNode(
node.position.x, node.position.y, image, name, self, node.id node.position.x, node.position.y, image, name, self.master, node.id
) )
self.nodes[n.id] = n self.nodes[n.id] = n
core_id_to_canvas_id[node.id] = n.id core_id_to_canvas_id[node.id] = n.id
@ -419,14 +419,7 @@ class CanvasGraph(tk.Canvas):
plot_id = self.find_all()[0] plot_id = self.find_all()[0]
logging.info("add node event: %s - %s", plot_id, self.selected) logging.info("add node event: %s - %s", plot_id, self.selected)
if self.selected == plot_id: if self.selected == plot_id:
node = CanvasNode( node = CanvasNode(x, y, image, node_name, self.master, self.core.peek_id())
x=x,
y=y,
image=image,
node_type=node_name,
canvas=self,
core_id=self.core.peek_id(),
)
self.nodes[node.id] = node self.nodes[node.id] = node
self.core.add_graph_node(self.core.session_id, node.id, x, y, node_name) self.core.add_graph_node(self.core.session_id, node.id, x, y, node_name)
return node return node
@ -491,10 +484,11 @@ class CanvasEdge:
class CanvasNode: class CanvasNode:
def __init__(self, x, y, image, node_type, canvas, core_id): def __init__(self, x, y, image, node_type, app, core_id):
self.image = image self.image = image
self.node_type = node_type self.node_type = node_type
self.canvas = canvas self.app = app
self.canvas = app.canvas
self.id = self.canvas.create_image( self.id = self.canvas.create_image(
x, y, anchor=tk.CENTER, image=self.image, tags="node" x, y, anchor=tk.CENTER, image=self.image, tags="node"
) )
@ -506,19 +500,30 @@ class CanvasNode:
x, y + 20, text=self.name, tags="nodename" x, y + 20, text=self.name, tags="nodename"
) )
self.antenna_draw = WlanAntennaManager(self.canvas, self.id) self.antenna_draw = WlanAntennaManager(self.canvas, self.id)
self.tooltip = CanvasTooltip(self.canvas)
self.canvas.tag_bind(self.id, "<ButtonPress-1>", self.click_press) self.canvas.tag_bind(self.id, "<ButtonPress-1>", self.click_press)
self.canvas.tag_bind(self.id, "<ButtonRelease-1>", self.click_release) self.canvas.tag_bind(self.id, "<ButtonRelease-1>", self.click_release)
self.canvas.tag_bind(self.id, "<B1-Motion>", self.motion) self.canvas.tag_bind(self.id, "<B1-Motion>", self.motion)
self.canvas.tag_bind(self.id, "<Button-3>", self.context) self.canvas.tag_bind(self.id, "<Button-3>", self.context)
self.canvas.tag_bind(self.id, "<Double-Button-1>", self.double_click) self.canvas.tag_bind(self.id, "<Double-Button-1>", self.double_click)
self.canvas.tag_bind(self.id, "<Control-1>", self.select_multiple) self.canvas.tag_bind(self.id, "<Control-1>", self.select_multiple)
self.tooltip = CanvasTooltip(self.canvas, self.id, text=self.name) self.canvas.tag_bind(self.id, "<Enter>", self.on_enter)
self.canvas.tag_bind(self.id, "<Leave>", self.on_leave)
self.edges = set() self.edges = set()
self.wlans = [] self.wlans = []
self.moving = None self.moving = None
def on_enter(self, event):
if self.app.core.is_runtime() and self.app.core.observer:
self.tooltip.text.set("waiting...")
self.tooltip.on_enter(event)
output = self.app.core.run(self.core_id)
self.tooltip.text.set(output)
def on_leave(self, event):
self.tooltip.on_leave(event)
def click(self, event): def click(self, event):
print("click") print("click")

View file

@ -4,7 +4,7 @@ from enum import Enum
from PIL import Image, ImageTk from PIL import Image, ImageTk
from core.api.grpc import core_pb2 from core.api.grpc import core_pb2
from coretk.appdirs import LOCAL_ICONS_PATH from coretk.appconfig import LOCAL_ICONS_PATH
class Images: class Images:

View file

@ -7,11 +7,12 @@ import webbrowser
from tkinter import filedialog, messagebox from tkinter import filedialog, messagebox
from core.api.grpc import core_pb2 from core.api.grpc import core_pb2
from coretk.appdirs import XML_PATH from coretk.appconfig import XML_PATH
from coretk.dialogs.canvasbackground import CanvasBackgroundDialog from coretk.dialogs.canvasbackground import CanvasBackgroundDialog
from coretk.dialogs.canvassizeandscale import SizeAndScaleDialog from coretk.dialogs.canvassizeandscale import SizeAndScaleDialog
from coretk.dialogs.hooks import HooksDialog from coretk.dialogs.hooks import HooksDialog
from coretk.dialogs.observerwidgets import ObserverWidgetsDialog from coretk.dialogs.observers import ObserverDialog
from coretk.dialogs.preferences import PreferencesDialog
from coretk.dialogs.servers import ServersDialog from coretk.dialogs.servers import ServersDialog
from coretk.dialogs.sessionoptions import SessionOptionsDialog from coretk.dialogs.sessionoptions import SessionOptionsDialog
from coretk.dialogs.sessions import SessionsDialog from coretk.dialogs.sessions import SessionsDialog
@ -83,6 +84,10 @@ class MenuAction:
self.prompt_save_running_session() self.prompt_save_running_session()
self.app.core.open_xml(file_path) self.app.core.open_xml(file_path)
def gui_preferences(self):
dialog = PreferencesDialog(self.app, self.app)
dialog.show()
def canvas_size_and_scale(self): def canvas_size_and_scale(self):
dialog = SizeAndScaleDialog(self.app, self.app) dialog = SizeAndScaleDialog(self.app, self.app)
dialog.show() dialog.show()
@ -118,5 +123,5 @@ class MenuAction:
dialog.show() dialog.show()
def edit_observer_widgets(self): def edit_observer_widgets(self):
dialog = ObserverWidgetsDialog(self.app, self.app) dialog = ObserverDialog(self.app, self.app)
dialog.show() dialog.show()

View file

@ -1,6 +1,8 @@
import tkinter as tk import tkinter as tk
from functools import partial
import coretk.menuaction as action import coretk.menuaction as action
from coretk.coreclient import OBSERVERS
class Menubar(tk.Menu): class Menubar(tk.Menu):
@ -92,7 +94,9 @@ class Menubar(tk.Menu):
menu.add_separator() menu.add_separator()
menu.add_command(label="Find...", accelerator="Ctrl+F", state=tk.DISABLED) menu.add_command(label="Find...", accelerator="Ctrl+F", state=tk.DISABLED)
menu.add_command(label="Clear marker", state=tk.DISABLED) menu.add_command(label="Clear marker", state=tk.DISABLED)
menu.add_command(label="Preferences...", state=tk.DISABLED) menu.add_command(
label="Preferences...", command=self.menuaction.gui_preferences
)
self.add_cascade(label="Edit", menu=menu) self.add_cascade(label="Edit", menu=menu)
def draw_canvas_menu(self): def draw_canvas_menu(self):
@ -364,23 +368,35 @@ class Menubar(tk.Menu):
:param tkinter.Menu widget_menu: widget_menu :param tkinter.Menu widget_menu: widget_menu
:return: nothing :return: nothing
""" """
var = tk.StringVar(value="none")
menu = tk.Menu(widget_menu) menu = tk.Menu(widget_menu)
menu.add_command(label="None", state=tk.DISABLED) menu.var = var
menu.add_command(label="processes", state=tk.DISABLED) menu.add_command(
menu.add_command(label="ifconfig", state=tk.DISABLED) label="Edit Observers", command=self.menuaction.edit_observer_widgets
menu.add_command(label="IPv4 routes", state=tk.DISABLED) )
menu.add_command(label="IPv6 routes", state=tk.DISABLED) menu.add_separator()
menu.add_command(label="OSPFv2 neighbors", state=tk.DISABLED) menu.add_radiobutton(
menu.add_command(label="OSPFv3 neighbors", state=tk.DISABLED) label="None",
menu.add_command(label="Listening sockets", state=tk.DISABLED) variable=var,
menu.add_command(label="IPv4 MFC entries", state=tk.DISABLED) value="none",
menu.add_command(label="IPv6 MFC entries", state=tk.DISABLED) command=lambda: self.app.core.set_observer(None),
menu.add_command(label="firewall rules", state=tk.DISABLED) )
menu.add_command(label="IPsec policies", state=tk.DISABLED) for name in sorted(OBSERVERS):
menu.add_command(label="docker logs", state=tk.DISABLED) cmd = OBSERVERS[name]
menu.add_command(label="OSPFv3 MDR level", state=tk.DISABLED) menu.add_radiobutton(
menu.add_command(label="PIM neighbors", state=tk.DISABLED) label=name,
menu.add_command(label="Edit...", command=self.menuaction.edit_observer_widgets) variable=var,
value=name,
command=partial(self.app.core.set_observer, cmd),
)
for name in sorted(self.app.core.custom_observers):
observer = self.app.core.custom_observers[name]
menu.add_radiobutton(
label=name,
variable=var,
value=name,
command=partial(self.app.core.set_observer, observer.cmd),
)
widget_menu.add_cascade(label="Observer Widgets", menu=menu) widget_menu.add_cascade(label="Observer Widgets", menu=menu)
def create_adjacency_menu(self, widget_menu): def create_adjacency_menu(self, widget_menu):

View file

@ -26,7 +26,7 @@ class FrameScroll(tk.LabelFrame):
self.canvas.grid(row=0, sticky="nsew", padx=2, pady=2) self.canvas.grid(row=0, sticky="nsew", padx=2, pady=2)
self.canvas.columnconfigure(0, weight=1) self.canvas.columnconfigure(0, weight=1)
self.canvas.rowconfigure(0, weight=1) self.canvas.rowconfigure(0, weight=1)
self.scrollbar = tk.Scrollbar( self.scrollbar = ttk.Scrollbar(
self, orient="vertical", command=self.canvas.yview self, orient="vertical", command=self.canvas.yview
) )
self.scrollbar.grid(row=0, column=1, sticky="ns") self.scrollbar.grid(row=0, column=1, sticky="ns")
@ -70,11 +70,11 @@ class ConfigFrame(FrameScroll):
for group_name in sorted(group_mapping): for group_name in sorted(group_mapping):
group = group_mapping[group_name] group = group_mapping[group_name]
frame = tk.Frame(self.frame) frame = ttk.Frame(self.frame)
frame.columnconfigure(1, weight=1) frame.columnconfigure(1, weight=1)
self.frame.add(frame, text=group_name) self.frame.add(frame, text=group_name)
for index, option in enumerate(sorted(group, key=lambda x: x.name)): for index, option in enumerate(sorted(group, key=lambda x: x.name)):
label = tk.Label(frame, text=option.label) label = ttk.Label(frame, text=option.label)
label.grid(row=index, pady=pady, padx=padx, sticky="w") label.grid(row=index, pady=pady, padx=padx, sticky="w")
value = tk.StringVar() value = tk.StringVar()
if option.type == core_pb2.ConfigOptionType.BOOL: if option.type == core_pb2.ConfigOptionType.BOOL:
@ -96,15 +96,15 @@ class ConfigFrame(FrameScroll):
combobox.grid(row=index, column=1, sticky="ew", pady=pady) combobox.grid(row=index, column=1, sticky="ew", pady=pady)
elif option.type == core_pb2.ConfigOptionType.STRING: elif option.type == core_pb2.ConfigOptionType.STRING:
value.set(option.value) value.set(option.value)
entry = tk.Entry(frame, textvariable=value) entry = ttk.Entry(frame, textvariable=value)
entry.grid(row=index, column=1, sticky="ew", pady=pady) entry.grid(row=index, column=1, sticky="ew", pady=pady)
elif option.type in INT_TYPES: elif option.type in INT_TYPES:
value.set(option.value) value.set(option.value)
entry = tk.Entry(frame, textvariable=value) entry = ttk.Entry(frame, textvariable=value)
entry.grid(row=index, column=1, sticky="ew", pady=pady) entry.grid(row=index, column=1, sticky="ew", pady=pady)
elif option.type == core_pb2.ConfigOptionType.FLOAT: elif option.type == core_pb2.ConfigOptionType.FLOAT:
value.set(option.value) value.set(option.value)
entry = tk.Entry(frame, textvariable=value) entry = ttk.Entry(frame, textvariable=value)
entry.grid(row=index, column=1, sticky="ew", pady=pady) entry.grid(row=index, column=1, sticky="ew", pady=pady)
else: else:
logging.error("unhandled config option type: %s", option.type) logging.error("unhandled config option type: %s", option.type)
@ -131,7 +131,7 @@ class ListboxScroll(tk.LabelFrame):
super().__init__(master, cnf, **kw) super().__init__(master, cnf, **kw)
self.columnconfigure(0, weight=1) self.columnconfigure(0, weight=1)
self.rowconfigure(0, weight=1) self.rowconfigure(0, weight=1)
self.scrollbar = tk.Scrollbar(self, orient=tk.VERTICAL) self.scrollbar = ttk.Scrollbar(self, orient=tk.VERTICAL)
self.scrollbar.grid(row=0, column=1, sticky="ns") self.scrollbar.grid(row=0, column=1, sticky="ns")
self.listbox = tk.Listbox( self.listbox = tk.Listbox(
self, selectmode=tk.SINGLE, yscrollcommand=self.scrollbar.set self, selectmode=tk.SINGLE, yscrollcommand=self.scrollbar.set
@ -149,5 +149,5 @@ class CheckboxList(FrameScroll):
def add(self, name, checked): def add(self, name, checked):
var = tk.BooleanVar(value=checked) var = tk.BooleanVar(value=checked)
func = partial(self.clicked, name, var) func = partial(self.clicked, name, var)
checkbox = tk.Checkbutton(self.frame, text=name, variable=var, command=func) checkbox = ttk.Checkbutton(self.frame, text=name, variable=var, command=func)
checkbox.grid(sticky="w") checkbox.grid(sticky="w")

View file

@ -184,9 +184,9 @@ class CoreGrpcServer(core_pb2_grpc.CoreApiServicer):
logging.debug("stop session: %s", request) logging.debug("stop session: %s", request)
session = self.get_session(request.session_id, context) session = self.get_session(request.session_id, context)
session.data_collect() session.data_collect()
session.set_state(EventTypes.DATACOLLECT_STATE) session.set_state(EventTypes.DATACOLLECT_STATE, send_event=True)
session.clear() session.clear()
session.set_state(EventTypes.SHUTDOWN_STATE) session.set_state(EventTypes.SHUTDOWN_STATE, send_event=True)
return core_pb2.StopSessionResponse(result=True) return core_pb2.StopSessionResponse(result=True)
def CreateSession(self, request, context): def CreateSession(self, request, context):