fix merge conflicts, continued work on node service configuration

This commit is contained in:
Huy Pham 2019-11-13 09:30:49 -08:00
commit c652ad2321
19 changed files with 619 additions and 437 deletions

View file

@ -1,5 +1,6 @@
import logging import logging
import tkinter as tk import tkinter as tk
from tkinter import ttk
from coretk import appconfig from coretk import appconfig
from coretk.coreclient import CoreClient from coretk.coreclient import CoreClient
@ -36,7 +37,7 @@ class Application(tk.Frame):
self.master.title("CORE") self.master.title("CORE")
self.master.geometry("1000x800") self.master.geometry("1000x800")
self.master.protocol("WM_DELETE_WINDOW", self.on_closing) self.master.protocol("WM_DELETE_WINDOW", self.on_closing)
image = Images.get(ImageEnum.CORE) image = Images.get(ImageEnum.CORE, 16)
self.master.tk.call("wm", "iconphoto", self.master._w, image) self.master.tk.call("wm", "iconphoto", self.master._w, image)
self.pack(fill=tk.BOTH, expand=True) self.pack(fill=tk.BOTH, expand=True)
@ -53,17 +54,17 @@ class Application(tk.Frame):
self, self.core, background="#cccccc", scrollregion=(0, 0, 1200, 1000) self, self.core, background="#cccccc", scrollregion=(0, 0, 1200, 1000)
) )
self.canvas.pack(fill=tk.BOTH, expand=True) self.canvas.pack(fill=tk.BOTH, expand=True)
scroll_x = tk.Scrollbar( scroll_x = ttk.Scrollbar(
self.canvas, orient=tk.HORIZONTAL, command=self.canvas.xview self.canvas, orient=tk.HORIZONTAL, command=self.canvas.xview
) )
scroll_x.pack(side=tk.BOTTOM, fill=tk.X) scroll_x.pack(side=tk.BOTTOM, fill=tk.X)
scroll_y = tk.Scrollbar(self.canvas, command=self.canvas.yview) scroll_y = ttk.Scrollbar(self.canvas, command=self.canvas.yview)
scroll_y.pack(side=tk.RIGHT, fill=tk.Y) scroll_y.pack(side=tk.RIGHT, fill=tk.Y)
self.canvas.configure(xscrollcommand=scroll_x.set) self.canvas.configure(xscrollcommand=scroll_x.set)
self.canvas.configure(yscrollcommand=scroll_y.set) self.canvas.configure(yscrollcommand=scroll_y.set)
def draw_status(self): def draw_status(self):
self.statusbar = tk.Frame(self) self.statusbar = ttk.Frame(self)
self.statusbar.pack(side=tk.BOTTOM, fill=tk.X) self.statusbar.pack(side=tk.BOTTOM, fill=tk.X)
def on_closing(self): def on_closing(self):

View file

@ -8,7 +8,7 @@ from core.api.grpc import client, core_pb2
from coretk.coretocanvas import CoreToCanvasMapping from coretk.coretocanvas import CoreToCanvasMapping
from coretk.dialogs.sessions import SessionsDialog from coretk.dialogs.sessions import SessionsDialog
from coretk.emaneodelnodeconfig import EmaneModelNodeConfig from coretk.emaneodelnodeconfig import EmaneModelNodeConfig
from coretk.images import Images from coretk.images import NODE_WIDTH, Images
from coretk.interface import Interface, InterfaceManager from coretk.interface import Interface, InterfaceManager
from coretk.mobilitynodeconfig import MobilityNodeConfig from coretk.mobilitynodeconfig import MobilityNodeConfig
from coretk.servicenodeconfig import ServiceNodeConfig from coretk.servicenodeconfig import ServiceNodeConfig
@ -139,7 +139,7 @@ class CoreClient:
# read custom nodes # read custom nodes
for config in self.app.config.get("nodes", []): for config in self.app.config.get("nodes", []):
image_file = config["image"] image_file = config["image"]
image = Images.get_custom(image_file) image = Images.get_custom(image_file, NODE_WIDTH)
custom_node = CustomNode( custom_node = CustomNode(
config["name"], image, image_file, set(config["services"]) config["name"], image, image_file, set(config["services"])
) )

View file

@ -11,6 +11,8 @@ from PIL import Image, ImageTk
from coretk.appconfig import BACKGROUNDS_PATH from coretk.appconfig import BACKGROUNDS_PATH
from coretk.dialogs.dialog import Dialog from coretk.dialogs.dialog import Dialog
PADX = 5
class ScaleOption(enum.Enum): class ScaleOption(enum.Enum):
NONE = 0 NONE = 0
@ -65,10 +67,10 @@ class CanvasBackgroundDialog(Dialog):
entry = ttk.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", padx=PADX)
button = ttk.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", padx=PADX)
button = ttk.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")
@ -105,7 +107,7 @@ class CanvasBackgroundDialog(Dialog):
checkbutton = ttk.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=PADX)
checkbutton = ttk.Checkbutton( checkbutton = ttk.Checkbutton(
self, self,
@ -113,7 +115,7 @@ class CanvasBackgroundDialog(Dialog):
variable=self.adjust_to_dim_var, variable=self.adjust_to_dim_var,
command=self.click_adjust_canvas, command=self.click_adjust_canvas,
) )
checkbutton.grid(row=5, column=0, sticky="ew", padx=5) checkbutton.grid(row=5, column=0, sticky="ew", padx=PADX)
self.show_grid_var.set(1) self.show_grid_var.set(1)
self.adjust_to_dim_var.set(0) self.adjust_to_dim_var.set(0)
@ -125,7 +127,7 @@ class CanvasBackgroundDialog(Dialog):
frame.columnconfigure(1, weight=1) frame.columnconfigure(1, weight=1)
button = ttk.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", padx=PADX)
button = ttk.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")
@ -206,7 +208,6 @@ class CanvasBackgroundDialog(Dialog):
return return
def upper_left(self, img): def upper_left(self, img):
print("upperleft")
tk_img = ImageTk.PhotoImage(img) tk_img = ImageTk.PhotoImage(img)
# crop image if it is bigger than canvas # crop image if it is bigger than canvas

View file

@ -8,6 +8,9 @@ from coretk.dialogs.canvasbackground import ScaleOption
from coretk.dialogs.dialog import Dialog from coretk.dialogs.dialog import Dialog
DRAW_OBJECT_TAGS = ["edge", "node", "nodename", "linkinfo", "antenna"] DRAW_OBJECT_TAGS = ["edge", "node", "nodename", "linkinfo", "antenna"]
FRAME_BAD = 5
PAD = (0, 0, 5, 0)
PADX = 5
class SizeAndScaleDialog(Dialog): class SizeAndScaleDialog(Dialog):
@ -49,101 +52,105 @@ class SizeAndScaleDialog(Dialog):
self.draw_buttons() self.draw_buttons()
def draw_size(self): def draw_size(self):
label = ttk.Label(self, text="Size", font=self.section_font) label_frame = ttk.Labelframe(self, text="Size", padding=FRAME_BAD)
label.grid(sticky="w") label_frame.grid(sticky="ew")
label_frame.columnconfigure(0, weight=1)
# draw size row 1 # draw size row 1
frame = ttk.Frame(self) frame = ttk.Frame(label_frame)
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 = ttk.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", padx=PADX)
entry = ttk.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", padx=PADX)
label = ttk.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", padx=PADX)
entry = ttk.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", padx=PADX)
label = ttk.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 = ttk.Frame(self) frame = ttk.Frame(label_frame)
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 = ttk.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", padx=PADX)
entry = ttk.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", padx=PADX)
label = ttk.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", padx=PADX)
entry = ttk.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", padx=PADX)
label = ttk.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 = ttk.Label(self, text="Scale", font=self.section_font) label_frame = ttk.Labelframe(self, text="Scale", padding=FRAME_BAD)
label.grid(sticky="w") label_frame.grid(sticky="ew")
label_frame.columnconfigure(0, weight=1)
frame = ttk.Frame(self) frame = ttk.Frame(label_frame)
frame.grid(sticky="ew") frame.grid(sticky="ew")
frame.columnconfigure(1, weight=1) frame.columnconfigure(1, weight=1)
label = ttk.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", padx=PADX)
entry = ttk.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", padx=PADX)
label = ttk.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 = ttk.Label(self, text="Reference point", font=self.section_font) label_frame = ttk.Labelframe(self, text="Reference Point", padding=FRAME_BAD)
label.grid(sticky="w") label_frame.grid(sticky="ew")
label = ttk.Label( label_frame.columnconfigure(0, weight=1)
self, text="Default is (0, 0), the upper left corner of the canvas"
)
label.grid(sticky="w")
frame = ttk.Frame(self) label = ttk.Label(
label_frame, text="Default is (0, 0), the upper left corner of the canvas"
)
label.grid()
frame = ttk.Frame(label_frame)
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 = ttk.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", padx=PADX)
x_var = tk.StringVar(value=0) x_var = tk.StringVar(value=0)
entry = ttk.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", padx=PADX)
label = ttk.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", padx=PADX)
y_var = tk.StringVar(value=0) y_var = tk.StringVar(value=0)
entry = ttk.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", padx=PADX)
label = ttk.Label(self, text="Translates To") label = ttk.Label(label_frame, text="Translates To")
label.grid(sticky="w") label.grid()
frame = ttk.Frame(self) frame = ttk.Frame(label_frame)
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 = ttk.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", padx=PADX)
entry = ttk.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", padx=PADX)
label = ttk.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", padx=PADX)
entry = ttk.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", padx=PADX)
label = ttk.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", padx=PADX)
entry = ttk.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")
@ -160,10 +167,10 @@ class SizeAndScaleDialog(Dialog):
frame.grid(sticky="ew") frame.grid(sticky="ew")
button = ttk.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, sticky="ew", padx=PADX)
button = ttk.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, sticky="ew")
def redraw_grid(self): def redraw_grid(self):
""" """

View file

@ -2,16 +2,18 @@ import tkinter as tk
from coretk.images import ImageEnum, Images from coretk.images import ImageEnum, Images
DIALOG_PAD = 5
class Dialog(tk.Toplevel): class Dialog(tk.Toplevel):
def __init__(self, master, app, title, modal=False): def __init__(self, master, app, title, modal=False):
super().__init__(master, padx=5, pady=5) super().__init__(master, padx=DIALOG_PAD, pady=DIALOG_PAD)
self.withdraw() self.withdraw()
self.app = app self.app = app
self.modal = modal self.modal = modal
self.title(title) self.title(title)
self.protocol("WM_DELETE_WINDOW", self.destroy) self.protocol("WM_DELETE_WINDOW", self.destroy)
image = Images.get(ImageEnum.CORE) image = Images.get(ImageEnum.CORE, 16)
self.tk.call("wm", "iconphoto", self._w, image) self.tk.call("wm", "iconphoto", self._w, image)
def show(self): def show(self):

View file

@ -182,25 +182,31 @@ class EmaneConfiguration(Dialog):
def draw_option_buttons(self, parent): def draw_option_buttons(self, parent):
f = ttk.Frame(parent) f = ttk.Frame(parent)
f.grid(row=4, column=0, sticky="nsew")
f.columnconfigure(0, weight=1) f.columnconfigure(0, weight=1)
f.columnconfigure(1, weight=1) f.columnconfigure(1, weight=1)
image = Images.get(ImageEnum.EDITNODE, 16)
b = ttk.Button( b = ttk.Button(
f, f,
text=self.emane_models[0] + " options", text=self.emane_models[0] + " options",
image=Images.get(ImageEnum.EDITNODE), image=image,
compound=tk.RIGHT, compound=tk.RIGHT,
command=self.draw_model_options, command=self.draw_model_options,
) )
b.image = image
b.grid(row=0, column=0, padx=10, pady=2, sticky="nsew") b.grid(row=0, column=0, padx=10, pady=2, sticky="nsew")
image = Images.get(ImageEnum.EDITNODE, 16)
b = ttk.Button( b = ttk.Button(
f, f,
text="EMANE options", text="EMANE options",
image=Images.get(ImageEnum.EDITNODE), image=image,
compound=tk.RIGHT, compound=tk.RIGHT,
command=self.draw_emane_options, command=self.draw_emane_options,
) )
b.image = image
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=4, column=0, sticky="nsew")
def combobox_select(self, event): def combobox_select(self, event):
""" """
@ -271,7 +277,7 @@ class EmaneConfiguration(Dialog):
b = ttk.Button( b = ttk.Button(
f, f,
image=Images.get(ImageEnum.EDITNODE), image=Images.get(ImageEnum.EDITNODE, 8),
text="EMANE Wiki", text="EMANE Wiki",
compound=tk.RIGHT, compound=tk.RIGHT,
command=lambda: webbrowser.open_new( command=lambda: webbrowser.open_new(

View file

@ -54,7 +54,7 @@ class IconDialog(Dialog):
), ),
) )
if file_path: if file_path:
self.image = Images.create(file_path) self.image = Images.create(file_path, 32, 32)
self.image_label.config(image=self.image) self.image_label.config(image=self.image)
self.file_path.set(file_path) self.file_path.set(file_path)

View file

@ -2,11 +2,10 @@
mobility configuration mobility configuration
""" """
import os
import tkinter as tk import tkinter as tk
from pathlib import Path from tkinter import filedialog, ttk
from tkinter import filedialog
from coretk import appconfig
from coretk.dialogs.dialog import Dialog from coretk.dialogs.dialog import Dialog
@ -40,12 +39,12 @@ class MobilityConfiguration(Dialog):
return var return var
def open_file(self, entry): def open_file(self, entry):
configs_dir = os.path.join(Path.home(), ".core/configs") filename = filedialog.askopenfilename(
if os.path.isdir(configs_dir): initialdir=str(appconfig.MOBILITY_PATH), title="Open"
filename = filedialog.askopenfilename(initialdir=configs_dir, title="Open") )
if filename: if filename:
entry.delete(0, tk.END) entry.delete(0, tk.END)
entry.insert(0, filename) entry.insert(0, filename)
def set_loop_value(self, value): def set_loop_value(self, value):
""" """
@ -58,26 +57,26 @@ class MobilityConfiguration(Dialog):
def create_label_entry_filebrowser( def create_label_entry_filebrowser(
self, parent_frame, text_label, entry_text, filebrowser=False self, parent_frame, text_label, entry_text, filebrowser=False
): ):
f = tk.Frame(parent_frame, bg="#d9d9d9") f = ttk.Frame(parent_frame, bg="#d9d9d9")
lbl = tk.Label(f, text=text_label, bg="#d9d9d9") lbl = ttk.Label(f, text=text_label, bg="#d9d9d9")
lbl.grid(padx=3, pady=3) lbl.grid(padx=3, pady=3)
# f.grid() # f.grid()
e = tk.Entry(f, textvariable=self.create_string_var(entry_text), bg="#ffffff") e = ttk.Entry(f, textvariable=self.create_string_var(entry_text), bg="#ffffff")
e.grid(row=0, column=1, padx=3, pady=3) e.grid(row=0, column=1, padx=3, pady=3)
if filebrowser: if filebrowser:
b = tk.Button(f, text="...", command=lambda: self.open_file(e)) b = ttk.Button(f, text="...", command=lambda: self.open_file(e))
b.grid(row=0, column=2, padx=3, pady=3) b.grid(row=0, column=2, padx=3, pady=3)
f.grid(sticky=tk.E) f.grid(sticky=tk.E)
def mobility_script_parameters(self): def mobility_script_parameters(self):
lbl = tk.Label(self, text="node ns2script") lbl = ttk.Label(self, text="node ns2script")
lbl.grid(sticky=tk.W + tk.E) lbl.grid(sticky="ew")
sb = tk.Scrollbar(self, orient=tk.VERTICAL) sb = ttk.Scrollbar(self, orient=tk.VERTICAL)
sb.grid(row=1, column=1, sticky=tk.N + tk.S + tk.E) sb.grid(row=1, column=1, sticky="ns")
f = tk.Frame(self, bg="#d9d9d9") f = ttk.Frame(self, bg="#d9d9d9")
lbl = tk.Label( lbl = ttk.Label(
f, text="ns-2 Mobility Scripts Parameters", bg="#d9d9d9", relief=tk.RAISED f, text="ns-2 Mobility Scripts Parameters", bg="#d9d9d9", relief=tk.RAISED
) )
lbl.grid(row=0, column=0, sticky=tk.W) lbl.grid(row=0, column=0, sticky=tk.W)
@ -99,21 +98,21 @@ class MobilityConfiguration(Dialog):
f1, "Refresh time (ms)", self.node_config["refresh_ms"] f1, "Refresh time (ms)", self.node_config["refresh_ms"]
) )
# f12 = tk.Frame(f1) # f12 = ttk.Frame(f1)
# #
# lbl = tk.Label(f12, text="Refresh time (ms)") # lbl = ttk.Label(f12, text="Refresh time (ms)")
# lbl.grid() # lbl.grid()
# #
# e = tk.Entry(f12, textvariable=self.create_string_var("50")) # e = ttk.Entry(f12, textvariable=self.create_string_var("50"))
# e.grid(row=0, column=1) # e.grid(row=0, column=1)
# f12.grid() # f12.grid()
f13 = tk.Frame(f1) f13 = ttk.Frame(f1)
lbl = tk.Label(f13, text="loop") lbl = ttk.Label(f13, text="loop")
lbl.grid() lbl.grid()
om = tk.OptionMenu( om = ttk.OptionMenu(
f13, self.create_string_var("On"), "On", "Off", command=self.set_loop_value f13, self.create_string_var("On"), "On", "Off", command=self.set_loop_value
) )
om.grid(row=0, column=1) om.grid(row=0, column=1)
@ -123,24 +122,24 @@ class MobilityConfiguration(Dialog):
self.create_label_entry_filebrowser( self.create_label_entry_filebrowser(
f1, "auto-start seconds (0.0 for runtime)", self.node_config["autostart"] f1, "auto-start seconds (0.0 for runtime)", self.node_config["autostart"]
) )
# f14 = tk.Frame(f1) # f14 = ttk.Frame(f1)
# #
# lbl = tk.Label(f14, text="auto-start seconds (0.0 for runtime)") # lbl = ttk.Label(f14, text="auto-start seconds (0.0 for runtime)")
# lbl.grid() # lbl.grid()
# #
# e = tk.Entry(f14, textvariable=self.create_string_var("")) # e = ttk.Entry(f14, textvariable=self.create_string_var(""))
# e.grid(row=0, column=1) # e.grid(row=0, column=1)
# #
# f14.grid() # f14.grid()
self.create_label_entry_filebrowser( self.create_label_entry_filebrowser(
f1, "node mapping (optional, e.g. 0:1, 1:2, 2:3)", self.node_config["map"] f1, "node mapping (optional, e.g. 0:1, 1:2, 2:3)", self.node_config["map"]
) )
# f15 = tk.Frame(f1) # f15 = ttk.Frame(f1)
# #
# lbl = tk.Label(f15, text="node mapping (optional, e.g. 0:1, 1:2, 2:3)") # lbl = ttk.Label(f15, text="node mapping (optional, e.g. 0:1, 1:2, 2:3)")
# lbl.grid() # lbl.grid()
# #
# e = tk.Entry(f15, textvariable=self.create_string_var("")) # e = ttk.Entry(f15, textvariable=self.create_string_var(""))
# e.grid(row=0, column=1) # e.grid(row=0, column=1)
# #
# f15.grid() # f15.grid()
@ -230,9 +229,9 @@ class MobilityConfiguration(Dialog):
:return: nothing :return: nothing
""" """
f = tk.Frame(self) f = ttk.Frame(self)
b = tk.Button(f, text="Apply", command=self.ns2script_apply) b = ttk.Button(f, text="Apply", command=self.ns2script_apply)
b.grid() b.grid()
b = tk.Button(f, text="Cancel", command=self.destroy) b = ttk.Button(f, text="Cancel", command=self.destroy)
b.grid(row=0, column=1) b.grid(row=0, column=1)
f.grid() f.grid()

View file

@ -1,13 +1,11 @@
import tkinter as tk import tkinter as tk
from tkinter import ttk from tkinter import ttk
from coretk.coreclient import DEFAULT_NODES
from coretk.dialogs.dialog import Dialog from coretk.dialogs.dialog import Dialog
from coretk.dialogs.icondialog import IconDialog from coretk.dialogs.icondialog import IconDialog
from coretk.dialogs.nodeservice import NodeService from coretk.dialogs.nodeservice import NodeService
NETWORKNODETYPES = ["switch", "hub", "wlan", "rj45", "tunnel"]
DEFAULTNODES = ["router", "host", "PC"]
class NodeConfigDialog(Dialog): class NodeConfigDialog(Dialog):
def __init__(self, master, app, canvas_node): def __init__(self, master, app, canvas_node):
@ -34,17 +32,17 @@ class NodeConfigDialog(Dialog):
self.draw_third_row() self.draw_third_row()
def draw_first_row(self): def draw_first_row(self):
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=1) frame.columnconfigure(1, weight=1)
frame.columnconfigure(2, weight=1) frame.columnconfigure(2, weight=1)
entry = tk.Entry(frame, textvariable=self.name) entry = ttk.Entry(frame, textvariable=self.name)
entry.grid(row=0, column=0, padx=2, sticky="ew") entry.grid(row=0, column=0, padx=2, sticky="ew")
combobox = ttk.Combobox( combobox = ttk.Combobox(
frame, textvariable=self.type, values=DEFAULTNODES, state="readonly" frame, textvariable=self.type, values=DEFAULT_NODES, state="readonly"
) )
combobox.grid(row=0, column=1, padx=2, sticky="ew") combobox.grid(row=0, column=1, padx=2, sticky="ew")
@ -57,15 +55,15 @@ class NodeConfigDialog(Dialog):
combobox.grid(row=0, column=2, sticky="ew") combobox.grid(row=0, column=2, sticky="ew")
def draw_second_row(self): def draw_second_row(self):
frame = tk.Frame(self) frame = ttk.Frame(self)
frame.grid(row=1, column=0, pady=2, sticky="ew") frame.grid(row=1, column=0, pady=2, 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="Services", command=self.click_services) button = ttk.Button(frame, text="Services", command=self.click_services)
button.grid(row=0, column=0, padx=2, sticky="ew") button.grid(row=0, column=0, padx=2, sticky="ew")
self.image_button = tk.Button( self.image_button = ttk.Button(
frame, frame,
text="Icon", text="Icon",
image=self.image, image=self.image,
@ -75,15 +73,15 @@ class NodeConfigDialog(Dialog):
self.image_button.grid(row=0, column=1, sticky="ew") self.image_button.grid(row=0, column=1, sticky="ew")
def draw_third_row(self): def draw_third_row(self):
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.config_apply) button = ttk.Button(frame, text="Apply", command=self.config_apply)
button.grid(row=0, column=0, padx=2, sticky="ew") button.grid(row=0, column=0, padx=2, 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_services(self): def click_services(self):

View file

@ -2,7 +2,7 @@
core node services core node services
""" """
import tkinter as tk import tkinter as tk
from tkinter import messagebox from tkinter import messagebox, ttk
from coretk.dialogs.dialog import Dialog from coretk.dialogs.dialog import Dialog
from coretk.dialogs.serviceconfiguration import ServiceConfiguration from coretk.dialogs.serviceconfiguration import ServiceConfiguration
@ -10,20 +10,22 @@ from coretk.widgets import CheckboxList, ListboxScroll
class NodeService(Dialog): class NodeService(Dialog):
def __init__(self, master, app, canvas_node, current_services=set()): def __init__(self, master, app, canvas_node, services=None):
super().__init__(master, app, "Node Services", modal=True) super().__init__(master, app, "Node Services", modal=True)
self.canvas_node = canvas_node self.canvas_node = canvas_node
self.groups = None self.groups = None
self.services = None self.services = None
self.current = None self.current = None
self.current_services = current_services if services is None:
services = set()
self.current_services = services
self.draw() self.draw()
def draw(self): def draw(self):
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):
@ -45,15 +47,15 @@ class NodeService(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(3): for i in range(3):
frame.columnconfigure(i, weight=1) frame.columnconfigure(i, weight=1)
button = tk.Button(frame, text="Configure", command=self.click_configure) button = ttk.Button(frame, text="Configure", command=self.click_configure)
button.grid(row=0, column=0, sticky="ew") button.grid(row=0, column=0, sticky="ew")
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=1, sticky="ew") button.grid(row=0, column=1, 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=2, sticky="ew") button.grid(row=0, column=2, sticky="ew")
# trigger group change # trigger group change

View file

@ -1,5 +1,5 @@
"Service configuration dialog" "Service configuration dialog"
import logging
import tkinter as tk import tkinter as tk
from tkinter import ttk from tkinter import ttk
@ -11,14 +11,12 @@ from coretk.widgets import ListboxScroll
class ServiceConfiguration(Dialog): class ServiceConfiguration(Dialog):
def __init__(self, master, app, service_name, canvas_node): def __init__(self, master, app, service_name, canvas_node):
super().__init__(master, app, service_name + " service", modal=True) super().__init__(master, app, f"{service_name} service", modal=True)
self.app = app self.app = app
self.canvas_node = canvas_node self.canvas_node = canvas_node
self.service_name = service_name self.service_name = service_name
self.radiovar = tk.IntVar() self.radiovar = tk.IntVar()
self.radiovar.set(2) self.radiovar.set(2)
self.documentnew_img = Images.get(ImageEnum.DOCUMENTNEW)
self.editdelete_img = Images.get(ImageEnum.EDITDELETE)
self.metadata = "" self.metadata = ""
self.filenames = [] self.filenames = []
self.dependencies = [] self.dependencies = []
@ -29,6 +27,8 @@ class ServiceConfiguration(Dialog):
self.validation_mode = None self.validation_mode = None
self.validation_time = None self.validation_time = None
self.validation_period = None self.validation_period = None
self.documentnew_img = Images.get(ImageEnum.DOCUMENTNEW, 16)
self.editdelete_img = Images.get(ImageEnum.EDITDELETE, 16)
self.tab_parent = None self.tab_parent = None
self.metadata_entry = None self.metadata_entry = None
@ -60,24 +60,23 @@ class ServiceConfiguration(Dialog):
def draw(self): def draw(self):
# self.columnconfigure(1, weight=1) # self.columnconfigure(1, weight=1)
frame = tk.Frame(self) frame = ttk.Frame(self)
frame1 = tk.Frame(frame) frame1 = ttk.Frame(frame)
label = tk.Label(frame1, text=self.service_name) label = ttk.Label(frame1, text=self.service_name)
label.grid(row=0, column=0, sticky="ew") label.grid(row=0, column=0, sticky="ew")
frame1.grid(row=0, column=0) frame1.grid(row=0, column=0)
frame2 = tk.Frame(frame) frame2 = ttk.Frame(frame)
# frame2.columnconfigure(0, weight=1) # frame2.columnconfigure(0, weight=1)
# frame2.columnconfigure(1, weight=4) # frame2.columnconfigure(1, weight=4)
label = tk.Label(frame2, text="Meta-data") label = ttk.Label(frame2, text="Meta-data")
label.grid(row=0, column=0) label.grid(row=0, column=0)
self.metadata_entry = tk.Entry(
frame2, textvariable=tk.StringVar(value=self.metadata) self.metadata_entry = ttk.Entry(frame2, textvariable=self.metadata)
)
self.metadata_entry.grid(row=0, column=1) self.metadata_entry.grid(row=0, column=1)
frame2.grid(row=1, column=0) frame2.grid(row=1, column=0)
frame.grid(row=0, column=0) frame.grid(row=0, column=0)
frame = tk.Frame(self) frame = ttk.Frame(self)
self.tab_parent = ttk.Notebook(frame) self.tab_parent = ttk.Notebook(frame)
tab1 = ttk.Frame(self.tab_parent) tab1 = ttk.Frame(self.tab_parent)
tab2 = ttk.Frame(self.tab_parent) tab2 = ttk.Frame(self.tab_parent)
@ -96,13 +95,13 @@ class ServiceConfiguration(Dialog):
frame.grid(row=1, column=0, sticky="nsew") frame.grid(row=1, column=0, sticky="nsew")
# tab 1 # tab 1
label = tk.Label( label = ttk.Label(
tab1, text="Config files and scripts that are generated for this service." tab1, text="Config files and scripts that are generated for this service."
) )
label.grid(row=0, column=0, sticky="nsew") label.grid(row=0, column=0, sticky="nsew")
frame = tk.Frame(tab1) frame = ttk.Frame(tab1)
label = tk.Label(frame, text="File name: ") label = ttk.Label(frame, text="File name: ")
label.grid(row=0, column=0) label.grid(row=0, column=0)
self.filename_combobox = ttk.Combobox(frame, values=self.filenames) self.filename_combobox = ttk.Combobox(frame, values=self.filenames)
self.filename_combobox.grid(row=0, column=1) self.filename_combobox.grid(row=0, column=1)
@ -111,48 +110,51 @@ class ServiceConfiguration(Dialog):
self.filename_combobox.bind( self.filename_combobox.bind(
"<<ComboboxSelected>>", self.display_service_file_data "<<ComboboxSelected>>", self.display_service_file_data
) )
button = ttk.Button(frame, image=self.documentnew_img)
button = tk.Button(frame, image=self.documentnew_img)
button.bind("<Button-1>", self.add_filename) button.bind("<Button-1>", self.add_filename)
button.grid(row=0, column=2) button.grid(row=0, column=2)
button = tk.Button(frame, image=self.editdelete_img) button = ttk.Button(frame, image=self.editdelete_img)
button.bind("<Button-1>", self.delete_filename) button.bind("<Button-1>", self.delete_filename)
button.grid(row=0, column=3) button.grid(row=0, column=3)
frame.grid(row=1, column=0, sticky="nsew") frame.grid(row=1, column=0, sticky="nsew")
frame = tk.Frame(tab1) frame = ttk.Frame(tab1)
button = tk.Radiobutton( button = ttk.Radiobutton(
frame, frame,
variable=self.radiovar, variable=self.radiovar,
text="Copy this source file:", text="Copy this source file:",
indicatoron=True,
value=1, value=1,
state="disabled", state="disabled",
) )
button.grid(row=0, column=0) button.grid(row=0, column=0)
entry = tk.Entry(frame, state=tk.DISABLED) entry = ttk.Entry(frame, state=tk.DISABLED)
entry.grid(row=0, column=1) entry.grid(row=0, column=1)
button = tk.Button(frame, image=Images.get(ImageEnum.FILEOPEN)) image = Images.get(ImageEnum.FILEOPEN, 16)
button = ttk.Button(frame, image=image)
button.image = image
button.grid(row=0, column=2) button.grid(row=0, column=2)
frame.grid(row=2, column=0, sticky="nsew") frame.grid(row=2, column=0, sticky="nsew")
frame = tk.Frame(tab1) frame = ttk.Frame(tab1)
button = tk.Radiobutton( button = ttk.Radiobutton(
frame, frame,
variable=self.radiovar, variable=self.radiovar,
text="Use text below for file contents:", text="Use text below for file contents:",
indicatoron=True,
value=2, value=2,
) )
button.grid(row=0, column=0) button.grid(row=0, column=0)
button = tk.Button(frame, image=Images.get(ImageEnum.FILEOPEN)) image = Images.get(ImageEnum.FILEOPEN, 16)
button = ttk.Button(frame, image=image)
button.image = image
button.grid(row=0, column=1) button.grid(row=0, column=1)
button = tk.Button(frame, image=Images.get(ImageEnum.DOCUMENTSAVE)) image = Images.get(ImageEnum.DOCUMENTSAVE, 16)
button = ttk.Button(frame, image=image)
button.image = image
button.grid(row=0, column=2) button.grid(row=0, column=2)
frame.grid(row=3, column=0, sticky="nsew") frame.grid(row=3, column=0, sticky="nsew")
# tab 2 # tab 2
label = tk.Label( label = ttk.Label(
tab2, tab2,
text="Directories required by this service that are unique for each node.", text="Directories required by this service that are unique for each node.",
) )
@ -162,23 +164,24 @@ class ServiceConfiguration(Dialog):
for i in range(3): for i in range(3):
label_frame = None label_frame = None
if i == 0: if i == 0:
label_frame = tk.LabelFrame(tab3, text="Startup commands") label_frame = ttk.LabelFrame(tab3, text="Startup commands")
commands = self.startup_commands commands = self.startup_commands
elif i == 1: elif i == 1:
label_frame = tk.LabelFrame(tab3, text="Shutdown commands") label_frame = ttk.LabelFrame(tab3, text="Shutdown commands")
commands = self.shutdown_commands commands = self.shutdown_commands
elif i == 2: elif i == 2:
label_frame = tk.LabelFrame(tab3, text="Validation commands") label_frame = ttk.LabelFrame(tab3, text="Validation commands")
commands = self.validation_commands commands = self.validation_commands
label_frame.columnconfigure(0, weight=1) label_frame.columnconfigure(0, weight=1)
frame = tk.Frame(label_frame) frame = ttk.Frame(label_frame)
frame.columnconfigure(0, weight=1) frame.columnconfigure(0, weight=1)
entry = tk.Entry(frame, textvariable=tk.StringVar()) entry = ttk.Entry(frame, textvariable=tk.StringVar())
entry.grid(row=0, column=0, stick="nsew") entry.grid(row=0, column=0, stick="nsew")
button = tk.Button(frame, image=self.documentnew_img) button = ttk.Button(frame, image=self.documentnew_img)
button.bind("<Button-1>", self.add_command) button.bind("<Button-1>", self.add_command)
button.grid(row=0, column=1, sticky="nsew") button.grid(row=0, column=1, sticky="nsew")
button = tk.Button(frame, image=self.editdelete_img) button = ttk.Button(frame, image=self.editdelete_img)
button.grid(row=0, column=2, sticky="nsew") button.grid(row=0, column=2, sticky="nsew")
button.bind("<Button-1>", self.delete_command) button.bind("<Button-1>", self.delete_command)
frame.grid(row=0, column=0, sticky="nsew") frame.grid(row=0, column=0, sticky="nsew")
@ -200,9 +203,9 @@ class ServiceConfiguration(Dialog):
for i in range(2): for i in range(2):
label_frame = None label_frame = None
if i == 0: if i == 0:
label_frame = tk.LabelFrame(tab4, text="Executables") label_frame = ttk.LabelFrame(tab4, text="Executables")
elif i == 1: elif i == 1:
label_frame = tk.LabelFrame(tab4, text="Dependencies") label_frame = ttk.LabelFrame(tab4, text="Dependencies")
label_frame.columnconfigure(0, weight=1) label_frame.columnconfigure(0, weight=1)
listbox_scroll = ListboxScroll(label_frame) listbox_scroll = ListboxScroll(label_frame)
listbox_scroll.listbox.config(height=4) listbox_scroll.listbox.config(height=4)
@ -217,18 +220,18 @@ class ServiceConfiguration(Dialog):
listbox_scroll.listbox.insert("end", dependency) listbox_scroll.listbox.insert("end", dependency)
for i in range(3): for i in range(3):
frame = tk.Frame(tab4) frame = ttk.Frame(tab4)
frame.columnconfigure(0, weight=1) frame.columnconfigure(0, weight=1)
if i == 0: if i == 0:
label = tk.Label(frame, text="Validation time:") label = ttk.Label(frame, text="Validation time:")
self.validation_time_entry = tk.Entry( self.validation_time_entry = ttk.Entry(
frame, frame,
state="disabled", state="disabled",
textvariable=tk.StringVar(value=self.validation_time), textvariable=tk.StringVar(value=self.validation_time),
) )
self.validation_time_entry.grid(row=i, column=1) self.validation_time_entry.grid(row=i, column=1)
elif i == 1: elif i == 1:
label = tk.Label(frame, text="Validation mode:") label = ttk.Label(frame, text="Validation mode:")
if self.validation_mode == core_pb2.ServiceValidationMode.BLOCKING: if self.validation_mode == core_pb2.ServiceValidationMode.BLOCKING:
mode = "BLOCKING" mode = "BLOCKING"
elif ( elif (
@ -237,36 +240,36 @@ class ServiceConfiguration(Dialog):
mode = "NON_BLOCKING" mode = "NON_BLOCKING"
elif self.validation_mode == core_pb2.ServiceValidationMode.TIMER: elif self.validation_mode == core_pb2.ServiceValidationMode.TIMER:
mode = "TIMER" mode = "TIMER"
self.validation_mode_entry = tk.Entry( self.validation_mode_entry = ttk.Entry(
frame, state="disabled", textvariable=tk.StringVar(value=mode) frame, state="disabled", textvariable=tk.StringVar(value=mode)
) )
self.validation_mode_entry.grid(row=i, column=1) self.validation_mode_entry.grid(row=i, column=1)
elif i == 2: elif i == 2:
label = tk.Label(frame, text="Validation period:") label = ttk.Label(frame, text="Validation period:")
self.validation_period_entry = tk.Entry( self.validation_period_entry = ttk.Entry(
frame, state="disabled", textvariable=tk.StringVar() frame, state="disabled", textvariable=tk.StringVar()
) )
self.validation_period_entry.grid(row=i, column=1) self.validation_period_entry.grid(row=i, column=1)
label.grid(row=i, column=0) label.grid(row=i, column=0)
frame.grid(row=2 + i, column=0, sticky="nsew") frame.grid(row=2 + i, column=0, sticky="nsew")
button = tk.Button( button = ttk.Button(
self, text="only store values that have changed from their defaults" self, text="only store values that have changed from their defaults"
) )
button.grid(row=2, column=0) button.grid(row=2, column=0)
frame = tk.Frame(self) frame = ttk.Frame(self)
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="nsew") button.grid(row=0, column=0, sticky="nsew")
button = tk.Button( button = ttk.Button(
frame, text="Dafults", command=self.click_defaults, state="disabled" frame, text="Dafults", command=self.click_defaults, state="disabled"
) )
button.grid(row=0, column=1, sticky="nsew") button.grid(row=0, column=1, sticky="nsew")
button = tk.Button( button = ttk.Button(
frame, text="Copy...", command=self.click_copy, state="disabled" frame, text="Copy...", command=self.click_copy, state="disabled"
) )
button.grid(row=0, column=2, sticky="nsew") button.grid(row=0, column=2, sticky="nsew")
button = tk.Button(frame, text="Cancel", command=self.destroy) button = ttk.Button(frame, text="Cancel", command=self.destroy)
button.grid(row=0, column=3, sticky="nsew") button.grid(row=0, column=3, sticky="nsew")
frame.grid(row=3, column=0) frame.grid(row=3, column=0)
@ -330,20 +333,27 @@ class ServiceConfiguration(Dialog):
validate_commands, validate_commands,
shutdown_commands, shutdown_commands,
) )
logging.info(
"%s, %s, %s, %s, %s",
metadata,
filenames,
startup_commands,
shutdown_commands,
validate_commands,
)
# wipe nodes and links when finished by setting to DEFINITION state # wipe nodes and links when finished by setting to DEFINITION state
self.app.core.client.set_session_state( self.app.core.client.set_session_state(
self.app.core.session_id, core_pb2.SessionState.DEFINITION self.app.core.session_id, core_pb2.SessionState.DEFINITION
) )
print(metadata, filenames)
def display_service_file_data(self, event): def display_service_file_data(self, event):
print("not implemented") print("not implemented")
def click_defaults(self): def click_defaults(self):
print("not implemented") logging.info("not implemented")
def click_copy(self): def click_copy(self):
print("not implemented") logging.info("not implemented")
def click_cancel(self): def click_cancel(self):
print("not implemented") logging.info("not implemented")

View file

@ -73,30 +73,36 @@ class SessionsDialog(Dialog):
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")
image = Images.get(ImageEnum.DOCUMENTNEW, 16)
b = ttk.Button( b = ttk.Button(
frame, frame, image=image, text="New", compound=tk.LEFT, command=self.click_new
image=Images.get(ImageEnum.DOCUMENTNEW),
text="New",
compound=tk.LEFT,
command=self.click_new,
) )
b.image = image
b.grid(row=0, padx=2, sticky="ew") b.grid(row=0, padx=2, sticky="ew")
image = Images.get(ImageEnum.FILEOPEN, 16)
b = ttk.Button( b = ttk.Button(
frame, frame,
image=Images.get(ImageEnum.FILEOPEN), image=image,
text="Connect", text="Connect",
compound=tk.LEFT, compound=tk.LEFT,
command=self.click_connect, command=self.click_connect,
) )
b.image = image
b.grid(row=0, column=1, padx=2, sticky="ew") b.grid(row=0, column=1, padx=2, sticky="ew")
image = Images.get(ImageEnum.EDITDELETE, 16)
b = ttk.Button( b = ttk.Button(
frame, frame,
image=Images.get(ImageEnum.EDITDELETE), image=image,
text="Shutdown", text="Shutdown",
compound=tk.LEFT, compound=tk.LEFT,
command=self.click_shutdown, command=self.click_shutdown,
) )
b.image = image
b.grid(row=0, column=2, padx=2, sticky="ew") b.grid(row=0, column=2, padx=2, sticky="ew")
b = ttk.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")

View file

@ -3,6 +3,7 @@ wlan configuration
""" """
import tkinter as tk import tkinter as tk
from tkinter import ttk
from coretk.dialogs.dialog import Dialog from coretk.dialogs.dialog import Dialog
from coretk.dialogs.icondialog import IconDialog from coretk.dialogs.icondialog import IconDialog
@ -10,12 +11,6 @@ from coretk.dialogs.icondialog import IconDialog
class WlanConfigDialog(Dialog): class WlanConfigDialog(Dialog):
def __init__(self, master, app, canvas_node, config): def __init__(self, master, app, canvas_node, config):
"""
create an instance of WlanConfiguration
:param coretk.grpah.CanvasGraph canvas: canvas object
:param coretk.graph.CanvasNode canvas_node: canvas node object
"""
super().__init__( super().__init__(
master, app, f"{canvas_node.name} Wlan Configuration", modal=True master, app, f"{canvas_node.name} Wlan Configuration", modal=True
) )
@ -48,14 +43,14 @@ class WlanConfigDialog(Dialog):
:return: nothing :return: nothing
""" """
frame = tk.Frame(self) frame = ttk.Frame(self)
frame.grid(pady=2, sticky="ew") frame.grid(pady=2, sticky="ew")
frame.columnconfigure(0, weight=1) frame.columnconfigure(0, weight=1)
entry = tk.Entry(frame, textvariable=self.name, bg="white") entry = ttk.Entry(frame, textvariable=self.name)
entry.grid(row=0, column=0, padx=2, sticky="ew") entry.grid(row=0, column=0, padx=2, sticky="ew")
self.image_button = tk.Button(frame, image=self.image, command=self.click_icon) self.image_button = ttk.Button(frame, image=self.image, command=self.click_icon)
self.image_button.grid(row=0, column=1, padx=3) self.image_button.grid(row=0, column=1, padx=3)
def draw_wlan_config(self): def draw_wlan_config(self):
@ -64,15 +59,15 @@ class WlanConfigDialog(Dialog):
:return: nothing :return: nothing
""" """
label = tk.Label(self, text="Wireless") label = ttk.Label(self, text="Wireless")
label.grid(sticky="w", pady=2) label.grid(sticky="w", pady=2)
frame = tk.Frame(self) frame = ttk.Frame(self)
frame.grid(pady=2, sticky="ew") frame.grid(pady=2, sticky="ew")
for i in range(2): for i in range(2):
frame.columnconfigure(i, weight=1) frame.columnconfigure(i, weight=1)
label = tk.Label( label = ttk.Label(
frame, frame,
text=( text=(
"The basic range model calculates on/off " "The basic range model calculates on/off "
@ -81,29 +76,29 @@ class WlanConfigDialog(Dialog):
) )
label.grid(row=0, columnspan=2, pady=2, sticky="ew") label.grid(row=0, columnspan=2, pady=2, sticky="ew")
label = tk.Label(frame, text="Range") label = ttk.Label(frame, text="Range")
label.grid(row=1, column=0, sticky="w") label.grid(row=1, column=0, sticky="w")
entry = tk.Entry(frame, textvariable=self.range_var) entry = ttk.Entry(frame, textvariable=self.range_var)
entry.grid(row=1, column=1, sticky="ew") entry.grid(row=1, column=1, sticky="ew")
label = tk.Label(frame, text="Bandwidth (bps)") label = ttk.Label(frame, text="Bandwidth (bps)")
label.grid(row=2, column=0, sticky="w") label.grid(row=2, column=0, sticky="w")
entry = tk.Entry(frame, textvariable=self.bandwidth_var) entry = ttk.Entry(frame, textvariable=self.bandwidth_var)
entry.grid(row=2, column=1, sticky="ew") entry.grid(row=2, column=1, sticky="ew")
label = tk.Label(frame, text="Delay (us)") label = ttk.Label(frame, text="Delay (us)")
label.grid(row=3, column=0, sticky="w") label.grid(row=3, column=0, sticky="w")
entry = tk.Entry(frame, textvariable=self.delay_var) entry = ttk.Entry(frame, textvariable=self.delay_var)
entry.grid(row=3, column=1, sticky="ew") entry.grid(row=3, column=1, sticky="ew")
label = tk.Label(frame, text="Loss (%)") label = ttk.Label(frame, text="Loss (%)")
label.grid(row=4, column=0, sticky="w") label.grid(row=4, column=0, sticky="w")
entry = tk.Entry(frame, textvariable=self.loss_var) entry = ttk.Entry(frame, textvariable=self.loss_var)
entry.grid(row=4, column=1, sticky="ew") entry.grid(row=4, column=1, sticky="ew")
label = tk.Label(frame, text="Jitter (us)") label = ttk.Label(frame, text="Jitter (us)")
label.grid(row=5, column=0, sticky="w") label.grid(row=5, column=0, sticky="w")
entry = tk.Entry(frame, textvariable=self.jitter_var) entry = ttk.Entry(frame, textvariable=self.jitter_var)
entry.grid(row=5, column=1, sticky="ew") entry.grid(row=5, column=1, sticky="ew")
def draw_subnet(self): def draw_subnet(self):
@ -113,19 +108,19 @@ class WlanConfigDialog(Dialog):
:return: nothing :return: nothing
""" """
frame = tk.Frame(self) frame = ttk.Frame(self)
frame.grid(pady=3, sticky="ew") frame.grid(pady=3, sticky="ew")
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="IPv4 Subnet") label = ttk.Label(frame, text="IPv4 Subnet")
label.grid(row=0, column=0, sticky="w") label.grid(row=0, column=0, sticky="w")
entry = tk.Entry(frame, textvariable=self.ip4_subnet) entry = ttk.Entry(frame, textvariable=self.ip4_subnet)
entry.grid(row=0, column=1, sticky="ew") entry.grid(row=0, column=1, sticky="ew")
label = tk.Label(frame, text="IPv6 Subnet") label = ttk.Label(frame, text="IPv6 Subnet")
label.grid(row=0, column=2, sticky="w") label.grid(row=0, column=2, sticky="w")
entry = tk.Entry(frame, textvariable=self.ip6_subnet) entry = ttk.Entry(frame, textvariable=self.ip6_subnet)
entry.grid(row=0, column=3, sticky="ew") entry.grid(row=0, column=3, sticky="ew")
def draw_wlan_buttons(self): def draw_wlan_buttons(self):
@ -135,18 +130,18 @@ class WlanConfigDialog(Dialog):
:return: :return:
""" """
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="ns-2 mobility script...") button = ttk.Button(frame, text="ns-2 mobility script...")
button.grid(row=0, column=0, padx=2, sticky="ew") button.grid(row=0, column=0, padx=2, sticky="ew")
button = tk.Button(frame, text="Link to all routers") button = ttk.Button(frame, text="Link to all routers")
button.grid(row=0, column=1, padx=2, sticky="ew") button.grid(row=0, column=1, padx=2, sticky="ew")
button = tk.Button(frame, text="Choose WLAN members") button = ttk.Button(frame, text="Choose WLAN members")
button.grid(row=0, column=2, padx=2, sticky="ew") button.grid(row=0, column=2, padx=2, sticky="ew")
def draw_apply_buttons(self): def draw_apply_buttons(self):
@ -155,15 +150,15 @@ class WlanConfigDialog(Dialog):
:return: nothing :return: nothing
""" """
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="Apply", command=self.click_apply) button = ttk.Button(frame, text="Apply", command=self.click_apply)
button.grid(row=0, column=0, padx=2, sticky="ew") button.grid(row=0, column=0, padx=2, 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, padx=2, sticky="ew") button.grid(row=0, column=1, padx=2, sticky="ew")
def click_icon(self): def click_icon(self):
@ -188,7 +183,6 @@ class WlanConfigDialog(Dialog):
jitter = self.jitter_var.get() jitter = self.jitter_var.get()
# set wireless node configuration here # set wireless node configuration here
wlanconfig_manager = self.app.core.wlanconfig_management wlanconfig_manager = self.app.core.wlanconfig_management
wlanconfig_manager.set_custom_config( wlanconfig_manager.set_custom_config(
node_id=self.canvas_node.core_id, node_id=self.canvas_node.core_id,

View file

@ -146,9 +146,7 @@ class CanvasGraph(tk.Canvas):
# peer to peer node is not drawn on the GUI # peer to peer node is not drawn on the GUI
if node.type != core_pb2.NodeType.PEER_TO_PEER: if node.type != core_pb2.NodeType.PEER_TO_PEER:
# draw nodes on the canvas # draw nodes on the canvas
image, name = Images.convert_type_and_model_to_image( image, name = Images.node_icon(node.type, node.model)
node.type, node.model
)
n = CanvasNode( n = CanvasNode(
node.position.x, node.position.y, image, name, self.master, node.id node.position.x, node.position.y, image, name, self.master, node.id
) )

View file

@ -77,6 +77,7 @@ class WlanAntennaManager:
self.quantity = 0 self.quantity = 0
self._max = 5 self._max = 5
self.antennas = [] self.antennas = []
self.image = Images.get(ImageEnum.ANTENNA, 32)
# distance between each antenna # distance between each antenna
self.offset = 0 self.offset = 0
@ -94,7 +95,7 @@ class WlanAntennaManager:
x - 16 + self.offset, x - 16 + self.offset,
y - 16, y - 16,
anchor=tk.CENTER, anchor=tk.CENTER,
image=Images.get(ImageEnum.ANTENNA), image=self.image,
tags="antenna", tags="antenna",
) )
) )

View file

@ -6,35 +6,37 @@ from PIL import Image, ImageTk
from core.api.grpc import core_pb2 from core.api.grpc import core_pb2
from coretk.appconfig import LOCAL_ICONS_PATH from coretk.appconfig import LOCAL_ICONS_PATH
NODE_WIDTH = 32
class Images: class Images:
images = {} images = {}
@classmethod @classmethod
def create(cls, file_path): def create(cls, file_path, width, height=None):
if height is None:
height = width
image = Image.open(file_path) image = Image.open(file_path)
image = image.resize((width, height), Image.ANTIALIAS)
return ImageTk.PhotoImage(image) return ImageTk.PhotoImage(image)
@classmethod @classmethod
def load_all(cls): def load_all(cls):
for image in LOCAL_ICONS_PATH.glob("*"): for image in LOCAL_ICONS_PATH.glob("*"):
cls.load(image.stem, str(image)) cls.images[image.stem] = str(image)
@classmethod @classmethod
def load(cls, name, file_path): def get(cls, image_enum, width, height=None):
tk_image = cls.create(file_path) file_path = cls.images[image_enum.value]
cls.images[name] = tk_image return cls.create(file_path, width, height)
@classmethod @classmethod
def get(cls, image): def get_custom(cls, name, width, height):
return cls.images[image.value] file_path = cls.images[name]
return cls.create(file_path, width, height)
@classmethod @classmethod
def get_custom(cls, name): def node_icon(cls, node_type, node_model):
return cls.images[name]
@classmethod
def convert_type_and_model_to_image(cls, node_type, node_model):
""" """
Retrieve image based on type and model Retrieve image based on type and model
:param core_pb2.NodeType node_type: core node type :param core_pb2.NodeType node_type: core node type
@ -43,34 +45,48 @@ class Images:
:rtype: tuple(PhotoImage, str) :rtype: tuple(PhotoImage, str)
:return: the matching image and its name :return: the matching image and its name
""" """
image_enum = ImageEnum.ROUTER
name = "unknown"
if node_type == core_pb2.NodeType.SWITCH: if node_type == core_pb2.NodeType.SWITCH:
return Images.get(ImageEnum.SWITCH), "switch" image_enum = ImageEnum.SWITCH
if node_type == core_pb2.NodeType.HUB: name = "switch"
return Images.get(ImageEnum.HUB), "hub" elif node_type == core_pb2.NodeType.HUB:
if node_type == core_pb2.NodeType.WIRELESS_LAN: image_enum = ImageEnum.HUB
return Images.get(ImageEnum.WLAN), "wlan" name = "hub"
if node_type == core_pb2.NodeType.EMANE: elif node_type == core_pb2.NodeType.WIRELESS_LAN:
return Images.get(ImageEnum.EMANE), "emane" image_enum = ImageEnum.WLAN
name = "wlan"
if node_type == core_pb2.NodeType.RJ45: elif node_type == core_pb2.NodeType.EMANE:
return Images.get(ImageEnum.RJ45), "rj45" image_enum = ImageEnum.EMANE
if node_type == core_pb2.NodeType.TUNNEL: name = "emane"
return Images.get(ImageEnum.TUNNEL), "tunnel" elif node_type == core_pb2.NodeType.RJ45:
if node_type == core_pb2.NodeType.DEFAULT: image_enum = ImageEnum.RJ45
name = "rj45"
elif node_type == core_pb2.NodeType.TUNNEL:
image_enum = ImageEnum.TUNNEL
name = "tunnel"
elif node_type == core_pb2.NodeType.DEFAULT:
if node_model == "router": if node_model == "router":
return Images.get(ImageEnum.ROUTER), "router" image_enum = ImageEnum.ROUTER
if node_model == "host": name = "router"
return Images.get(ImageEnum.HOST), "host" elif node_model == "host":
if node_model == "PC": image_enum = ImageEnum.HOST
return Images.get(ImageEnum.PC), "PC" name = "host"
if node_model == "mdr": elif node_model == "PC":
return Images.get(ImageEnum.MDR), "mdr" image_enum = ImageEnum.PC
if node_model == "prouter": name = "PC"
return Images.get(ImageEnum.PROUTER), "prouter" elif node_model == "mdr":
if node_model == "OVS": image_enum = ImageEnum.MDR
return Images.get(ImageEnum.OVS), "ovs" name = "mdr"
elif node_model == "prouter":
image_enum = ImageEnum.PROUTER
name = "prouter"
else:
logging.error("invalid node model: %s", node_model)
else: else:
logging.debug("INVALID INPUT OR NOT CONSIDERED YET") logging.error("invalid node type: %s", node_type)
return Images.get(image_enum, NODE_WIDTH), name
class ImageEnum(Enum): class ImageEnum(Enum):

162
coretk/coretk/theme.py Normal file
View file

@ -0,0 +1,162 @@
import tkinter as tk
from tkinter import ttk
class Colors:
disabledfg = "DarkGrey"
frame = "#424242"
dark = "#222222"
darker = "#121212"
darkest = "black"
lighter = "#626262"
lightest = "#ffffff"
selectbg = "#4a6984"
selectfg = "#ffffff"
white = "white"
black = "black"
style = ttk.Style()
style.theme_create(
"black",
"clam",
{
".": {
"configure": {
"background": Colors.frame,
"foreground": Colors.white,
"bordercolor": Colors.darkest,
"darkcolor": Colors.dark,
"lightcolor": Colors.lighter,
"troughcolor": Colors.darker,
"selectbackground": Colors.selectbg,
"selectforeground": Colors.selectfg,
"selectborderwidth": 0,
"font": "TkDefaultFont",
},
"map": {
"background": [("disabled", Colors.frame), ("active", Colors.lighter)],
"foreground": [("disabled", Colors.disabledfg)],
"selectbackground": [("!focus", Colors.darkest)],
"selectforeground": [("!focus", Colors.white)],
},
},
"TButton": {
"configure": {"width": 8, "padding": (5, 1), "relief": tk.RAISED},
"map": {
"relief": [("pressed", tk.SUNKEN)],
"shiftrelief": [("pressed", 1)],
},
},
"TMenubutton": {
"configure": {"width": 11, "padding": (5, 1), "relief": tk.RAISED}
},
"TCheckbutton": {
"configure": {
"indicatorbackground": Colors.white,
"indicatormargin": (1, 1, 4, 1),
}
},
"TRadiobutton": {
"configure": {
"indicatorbackground": Colors.white,
"indicatormargin": (1, 1, 4, 1),
}
},
"TEntry": {
"configure": {
"fieldbackground": Colors.white,
"foreground": Colors.black,
"padding": (2, 0),
}
},
"TCombobox": {
"configure": {
"fieldbackground": Colors.white,
"foreground": Colors.black,
"padding": (2, 0),
}
},
"TNotebook.Tab": {
"configure": {"padding": (6, 2, 6, 2)},
"map": {"background": [("selected", Colors.lighter)]},
},
"Treeview": {
"configure": {
"fieldbackground": Colors.white,
"background": Colors.white,
"foreground": Colors.black,
},
"map": {
"background": [("selected", Colors.selectbg)],
"foreground": [("selected", Colors.selectfg)],
},
},
},
)
style.theme_use("black")
def update_menu(event):
bg = style.lookup(".", "background")
fg = style.lookup(".", "foreground")
abg = style.lookup(".", "lightcolor")
event.widget.config(
background=bg, foreground=fg, activebackground=abg, activeforeground=fg
)
class Application(ttk.Frame):
def __init__(self, master=None):
super().__init__(master)
self.master.bind_class("Menu", "<<ThemeChanged>>", update_menu)
self.master.geometry("800x600")
menu = tk.Menu(self.master)
menu.add_command(label="Command1")
menu.add_command(label="Command2")
submenu = tk.Menu(menu, tearoff=False)
submenu.add_command(label="Command1")
submenu.add_command(label="Command2")
menu.add_cascade(label="Submenu", menu=submenu)
self.master.config(menu=menu)
self.master.columnconfigure(0, weight=1)
self.master.rowconfigure(0, weight=1)
notebook = ttk.Notebook(self.master)
notebook.grid(sticky="nsew")
frame = ttk.Frame(notebook)
frame.grid(sticky="nsew")
ttk.Label(frame, text="Label").grid()
ttk.Entry(frame).grid()
ttk.Button(frame, text="Button").grid()
ttk.Combobox(frame, values=("one", "two", "three")).grid()
menubutton = ttk.Menubutton(frame, text="MenuButton")
menubutton.grid()
mbmenu = tk.Menu(menubutton, tearoff=False)
menubutton.config(menu=mbmenu)
mbmenu.add_command(label="Menu1")
mbmenu.add_command(label="Menu2")
submenu = tk.Menu(mbmenu, tearoff=False)
submenu.add_command(label="Command1")
submenu.add_command(label="Command2")
mbmenu.add_cascade(label="Submenu", menu=submenu)
ttk.Radiobutton(frame, text="Radio Button").grid()
ttk.Checkbutton(frame, text="Check Button").grid()
tv = ttk.Treeview(frame, columns=("one", "two", "three"), show="headings")
tv.grid()
tv.column("one", stretch=tk.YES)
tv.heading("one", text="ID")
tv.column("two", stretch=tk.YES)
tv.heading("two", text="State")
tv.column("three", stretch=tk.YES)
tv.heading("three", text="Node Count")
tv.insert("", tk.END, text="1", values=("v1", "v2", "v3"))
tv.insert("", tk.END, text="2", values=("v1", "v2", "v3"))
notebook.add(frame, text="Tab1")
frame = ttk.Frame(notebook)
frame.grid(sticky="nsew")
notebook.add(frame, text="Tab2")
if __name__ == "__main__":
app = Application()
app.mainloop()

View file

@ -1,43 +1,44 @@
import logging import logging
import tkinter as tk import tkinter as tk
from functools import partial from functools import partial
from tkinter import ttk
from coretk.dialogs.customnodes import CustomNodesDialog from coretk.dialogs.customnodes import CustomNodesDialog
from coretk.graph import GraphMode from coretk.graph import GraphMode
from coretk.images import ImageEnum, Images from coretk.images import ImageEnum, Images
from coretk.tooltip import CreateToolTip from coretk.tooltip import Tooltip
WIDTH = 32
class Toolbar(tk.Frame): def icon(image_enum):
return Images.get(image_enum, WIDTH)
class Toolbar(ttk.Frame):
""" """
Core toolbar class Core toolbar class
""" """
def __init__(self, master, app, cnf={}, **kwargs): def __init__(self, master, app, **kwargs):
""" """
Create a CoreToolbar instance Create a CoreToolbar instance
:param tkinter.Frame edit_frame: edit frame :param tkinter.Frame edit_frame: edit frame
""" """
super().__init__(master, cnf, **kwargs) super().__init__(master, **kwargs)
self.app = app self.app = app
self.master = app.master self.master = app.master
self.radio_value = tk.IntVar()
self.exec_radio_value = tk.IntVar()
# button dimension # design buttons
self.width = 32 self.select_button = None
self.height = 32 self.link_button = None
# Reference to the option menus
self.selection_tool_button = None
self.link_layer_option_menu = None
self.marker_option_menu = None
self.network_layer_option_menu = None
self.node_button = None self.node_button = None
self.network_button = None self.network_button = None
self.annotation_button = None self.annotation_button = None
# runtime buttons
# frames # frames
self.design_frame = None self.design_frame = None
self.runtime_frame = None self.runtime_frame = None
@ -56,89 +57,77 @@ class Toolbar(tk.Frame):
self.design_frame.tkraise() self.design_frame.tkraise()
def draw_design_frame(self): def draw_design_frame(self):
self.design_frame = tk.Frame(self) self.design_frame = ttk.Frame(self)
self.design_frame.grid(row=0, column=0, sticky="nsew") self.design_frame.grid(row=0, column=0, sticky="nsew")
self.design_frame.columnconfigure(0, weight=1) self.design_frame.columnconfigure(0, weight=1)
self.create_button(
self.create_regular_button(
self.design_frame, self.design_frame,
Images.get(ImageEnum.START), icon(ImageEnum.START),
self.click_start_session_tool, self.click_start,
"start the session", "start the session",
) )
self.create_radio_button( self.select_button = self.create_button(
self.design_frame, self.design_frame,
Images.get(ImageEnum.SELECT), icon(ImageEnum.SELECT),
self.click_selection_tool, self.click_selection,
self.radio_value,
1,
"selection tool", "selection tool",
) )
self.create_radio_button( self.link_button = self.create_button(
self.design_frame, self.design_frame, icon(ImageEnum.LINK), self.click_link, "link tool"
Images.get(ImageEnum.LINK),
self.click_link_tool,
self.radio_value,
2,
"link tool",
) )
self.create_node_button() self.create_node_button()
self.create_network_button() self.create_network_button()
self.create_annotation_button() self.create_annotation_button()
self.radio_value.set(1)
def design_select(self, button):
logging.info("selecting design button: %s", button)
self.select_button.state(["!pressed"])
self.link_button.state(["!pressed"])
self.node_button.state(["!pressed"])
self.network_button.state(["!pressed"])
self.annotation_button.state(["!pressed"])
button.state(["pressed"])
def draw_runtime_frame(self): def draw_runtime_frame(self):
self.runtime_frame = tk.Frame(self) self.runtime_frame = ttk.Frame(self)
self.runtime_frame.grid(row=0, column=0, sticky="nsew") self.runtime_frame.grid(row=0, column=0, sticky="nsew")
self.runtime_frame.columnconfigure(0, weight=1) self.runtime_frame.columnconfigure(0, weight=1)
self.create_regular_button( self.create_button(
self.runtime_frame, self.runtime_frame,
Images.get(ImageEnum.STOP), icon(ImageEnum.STOP),
self.click_stop_button, self.click_stop,
"stop the session", "stop the session",
) )
self.create_radio_button( self.create_button(
self.runtime_frame, self.runtime_frame,
Images.get(ImageEnum.SELECT), icon(ImageEnum.SELECT),
self.click_selection_tool, self.click_selection,
self.exec_radio_value,
1,
"selection tool", "selection tool",
) )
self.create_observe_button() # self.create_observe_button()
self.create_radio_button( self.create_button(
self.runtime_frame, self.runtime_frame, icon(ImageEnum.PLOT), self.click_plot_button, "plot"
Images.get(ImageEnum.PLOT),
self.click_plot_button,
self.exec_radio_value,
2,
"plot",
) )
self.create_radio_button( self.create_button(
self.runtime_frame, self.runtime_frame,
Images.get(ImageEnum.MARKER), icon(ImageEnum.MARKER),
self.click_marker_button, self.click_marker_button,
self.exec_radio_value,
3,
"marker", "marker",
) )
self.create_radio_button( self.create_button(
self.runtime_frame, self.runtime_frame,
Images.get(ImageEnum.TWONODE), icon(ImageEnum.TWONODE),
self.click_two_node_button, self.click_two_node_button,
self.exec_radio_value,
4,
"run command from one node to another", "run command from one node to another",
) )
self.create_regular_button( self.create_button(
self.runtime_frame, Images.get(ImageEnum.RUN), self.click_run_button, "run" self.runtime_frame, icon(ImageEnum.RUN), self.click_run_button, "run"
) )
self.exec_radio_value.set(1)
def draw_node_picker(self): def draw_node_picker(self):
self.hide_pickers() self.hide_pickers()
self.node_picker = tk.Frame(self.master, padx=1, pady=1) self.node_picker = ttk.Frame(self.master)
nodes = [ nodes = [
(ImageEnum.ROUTER, "router"), (ImageEnum.ROUTER, "router"),
(ImageEnum.HOST, "host"), (ImageEnum.HOST, "host"),
@ -148,26 +137,28 @@ class Toolbar(tk.Frame):
] ]
# draw default nodes # draw default nodes
for image_enum, tooltip in nodes: for image_enum, tooltip in nodes:
image = Images.get(image_enum) image = icon(image_enum)
func = partial(self.update_button, self.node_button, image, tooltip) func = partial(self.update_button, self.node_button, image, tooltip)
self.create_button(image, func, self.node_picker, tooltip) self.create_picker_button(image, func, self.node_picker, tooltip)
# draw custom nodes # draw custom nodes
for name in sorted(self.app.core.custom_nodes): for name in sorted(self.app.core.custom_nodes):
custom_node = self.app.core.custom_nodes[name] custom_node = self.app.core.custom_nodes[name]
image = custom_node.image image = custom_node.image
func = partial(self.update_button, self.node_button, image, name) func = partial(self.update_button, self.node_button, image, name)
self.create_button(image, func, self.node_picker, name) self.create_picker_button(image, func, self.node_picker, name)
# draw edit node # draw edit node
image = Images.get(ImageEnum.EDITNODE) image = icon(ImageEnum.EDITNODE)
self.create_button( self.create_picker_button(
image, self.click_edit_node, self.node_picker, "custom nodes" image, self.click_edit_node, self.node_picker, "custom nodes"
) )
self.show_picker(self.node_button, self.node_picker) self.design_select(self.node_button)
self.node_button.after(
0, lambda: self.show_picker(self.node_button, self.node_picker)
)
def show_picker(self, button, picker): def show_picker(self, button, picker):
first_button = self.winfo_children()[0] x = self.winfo_width() + 1
x = button.winfo_rootx() - first_button.winfo_rootx() + 40 y = button.winfo_rooty() - picker.master.winfo_rooty() - 1
y = button.winfo_rooty() - first_button.winfo_rooty() - 1
picker.place(x=x, y=y) picker.place(x=x, y=y)
self.app.bind_all("<ButtonRelease-1>", lambda e: self.hide_pickers()) self.app.bind_all("<ButtonRelease-1>", lambda e: self.hide_pickers())
picker.wait_visibility() picker.wait_visibility()
@ -175,7 +166,7 @@ class Toolbar(tk.Frame):
self.wait_window(picker) self.wait_window(picker)
self.app.unbind_all("<ButtonRelease-1>") self.app.unbind_all("<ButtonRelease-1>")
def create_button(self, image, func, frame, tooltip): def create_picker_button(self, image, func, frame, tooltip):
""" """
Create button and put it on the frame Create button and put it on the frame
@ -185,37 +176,25 @@ class Toolbar(tk.Frame):
:param str tooltip: tooltip text :param str tooltip: tooltip text
:return: nothing :return: nothing
""" """
button = tk.Button(frame, width=self.width, height=self.height, image=image) button = ttk.Button(frame, image=image)
button.image = image
button.bind("<ButtonRelease-1>", lambda e: func()) button.bind("<ButtonRelease-1>", lambda e: func())
button.grid(pady=1) button.grid(pady=1)
CreateToolTip(button, tooltip) Tooltip(button, tooltip)
def create_radio_button(self, frame, image, func, variable, value, tooltip_msg): def create_button(self, frame, image, func, tooltip):
button = tk.Radiobutton( button = ttk.Button(frame, image=image, command=func)
frame, button.image = image
indicatoron=False, button.grid(sticky="ew")
width=self.width, Tooltip(button, tooltip)
height=self.height, return button
image=image,
value=value,
variable=variable,
command=func,
)
button.grid()
CreateToolTip(button, tooltip_msg)
def create_regular_button(self, frame, image, func, tooltip): def click_selection(self):
button = tk.Button(
frame, width=self.width, height=self.height, image=image, command=func
)
button.grid()
CreateToolTip(button, tooltip)
def click_selection_tool(self):
logging.debug("clicked selection tool") logging.debug("clicked selection tool")
self.design_select(self.select_button)
self.app.canvas.mode = GraphMode.SELECT self.app.canvas.mode = GraphMode.SELECT
def click_start_session_tool(self): def click_start(self):
""" """
Start session handler redraw buttons, send node and link messages to grpc Start session handler redraw buttons, send node and link messages to grpc
server. server.
@ -227,8 +206,9 @@ class Toolbar(tk.Frame):
self.app.core.start_session() self.app.core.start_session()
self.runtime_frame.tkraise() self.runtime_frame.tkraise()
def click_link_tool(self): def click_link(self):
logging.debug("Click LINK button") logging.debug("Click LINK button")
self.design_select(self.link_button)
self.app.canvas.mode = GraphMode.EDGE self.app.canvas.mode = GraphMode.EDGE
def click_edit_node(self): def click_edit_node(self):
@ -240,6 +220,7 @@ class Toolbar(tk.Frame):
logging.info("update button(%s): %s", button, name) logging.info("update button(%s): %s", button, name)
self.hide_pickers() self.hide_pickers()
button.configure(image=image) button.configure(image=image)
button.image = image
self.app.canvas.mode = GraphMode.NODE self.app.canvas.mode = GraphMode.NODE
self.app.canvas.draw_node_image = image self.app.canvas.draw_node_image = image
self.app.canvas.draw_node_name = name self.app.canvas.draw_node_name = name
@ -262,29 +243,22 @@ class Toolbar(tk.Frame):
:return: nothing :return: nothing
""" """
router_image = Images.get(ImageEnum.ROUTER) image = icon(ImageEnum.ROUTER)
self.node_button = tk.Radiobutton( self.node_button = ttk.Button(
self.design_frame, self.design_frame, image=image, command=self.draw_node_picker
indicatoron=False,
variable=self.radio_value,
value=3,
width=self.width,
height=self.height,
image=router_image,
) )
self.node_button.bind("<ButtonRelease-1>", lambda e: self.draw_node_picker()) self.node_button.image = image
self.node_button.grid() self.node_button.grid(sticky="ew")
CreateToolTip(self.node_button, "Network-layer virtual nodes") Tooltip(self.node_button, "Network-layer virtual nodes")
def draw_network_picker(self): def draw_network_picker(self):
""" """
Draw the options for link-layer button Draw the options for link-layer button.
:param tkinter.RadioButton link_layer_button: link-layer button
:return: nothing :return: nothing
""" """
self.hide_pickers() self.hide_pickers()
self.network_picker = tk.Frame(self.master, padx=1, pady=1) self.network_picker = ttk.Frame(self.master)
nodes = [ nodes = [
(ImageEnum.HUB, "hub", "ethernet hub"), (ImageEnum.HUB, "hub", "ethernet hub"),
(ImageEnum.SWITCH, "switch", "ethernet switch"), (ImageEnum.SWITCH, "switch", "ethernet switch"),
@ -294,14 +268,17 @@ class Toolbar(tk.Frame):
(ImageEnum.TUNNEL, "tunnel", "tunnel tool"), (ImageEnum.TUNNEL, "tunnel", "tunnel tool"),
] ]
for image_enum, name, tooltip in nodes: for image_enum, name, tooltip in nodes:
image = Images.get(image_enum) image = icon(image_enum)
self.create_button( self.create_picker_button(
image, image,
partial(self.update_button, self.network_button, image, name), partial(self.update_button, self.network_button, image, name),
self.network_picker, self.network_picker,
tooltip, tooltip,
) )
self.show_picker(self.network_button, self.network_picker) self.design_select(self.network_button)
self.network_button.after(
0, lambda: self.show_picker(self.network_button, self.network_picker)
)
def create_network_button(self): def create_network_button(self):
""" """
@ -309,31 +286,22 @@ class Toolbar(tk.Frame):
:return: nothing :return: nothing
""" """
hub_image = Images.get(ImageEnum.HUB) image = icon(ImageEnum.HUB)
self.network_button = tk.Radiobutton( self.network_button = ttk.Button(
self.design_frame, self.design_frame, image=image, command=self.draw_network_picker
indicatoron=False,
variable=self.radio_value,
value=4,
width=self.width,
height=self.height,
image=hub_image,
) )
self.network_button.bind( self.network_button.image = image
"<ButtonRelease-1>", lambda e: self.draw_network_picker() self.network_button.grid(sticky="ew")
) Tooltip(self.network_button, "link-layer nodes")
self.network_button.grid()
CreateToolTip(self.network_button, "link-layer nodes")
def draw_annotation_picker(self): def draw_annotation_picker(self):
""" """
Draw the options for marker button Draw the options for marker button.
:param tkinter.Radiobutton main_button: the main button
:return: nothing :return: nothing
""" """
self.hide_pickers() self.hide_pickers()
self.annotation_picker = tk.Frame(self.master, padx=1, pady=1) self.annotation_picker = ttk.Frame(self.master)
nodes = [ nodes = [
(ImageEnum.MARKER, "marker"), (ImageEnum.MARKER, "marker"),
(ImageEnum.OVAL, "oval"), (ImageEnum.OVAL, "oval"),
@ -341,13 +309,17 @@ class Toolbar(tk.Frame):
(ImageEnum.TEXT, "text"), (ImageEnum.TEXT, "text"),
] ]
for image_enum, tooltip in nodes: for image_enum, tooltip in nodes:
self.create_button( image = icon(image_enum)
Images.get(image_enum), self.create_picker_button(
partial(self.update_annotation, image_enum), image,
partial(self.update_annotation, image),
self.annotation_picker, self.annotation_picker,
tooltip, tooltip,
) )
self.show_picker(self.annotation_button, self.annotation_picker) self.design_select(self.annotation_button)
self.annotation_button.after(
0, lambda: self.show_picker(self.annotation_button, self.annotation_picker)
)
def create_annotation_button(self): def create_annotation_button(self):
""" """
@ -355,53 +327,39 @@ class Toolbar(tk.Frame):
:return: nothing :return: nothing
""" """
marker_image = Images.get(ImageEnum.MARKER) image = icon(ImageEnum.MARKER)
self.annotation_button = tk.Radiobutton( self.annotation_button = ttk.Button(
self.design_frame, self.design_frame, image=image, command=self.draw_annotation_picker
indicatoron=False,
variable=self.radio_value,
value=5,
width=self.width,
height=self.height,
image=marker_image,
) )
self.annotation_button.bind( self.annotation_button.image = image
"<ButtonRelease-1>", lambda e: self.draw_annotation_picker() self.annotation_button.grid(sticky="ew")
) Tooltip(self.annotation_button, "background annotation tools")
self.annotation_button.grid()
CreateToolTip(self.annotation_button, "background annotation tools")
def create_observe_button(self): def create_observe_button(self):
menu_button = tk.Menubutton( menu_button = ttk.Menubutton(
self.runtime_frame, self.runtime_frame, image=icon(ImageEnum.OBSERVE), direction=tk.RIGHT
image=Images.get(ImageEnum.OBSERVE),
width=self.width,
height=self.height,
direction=tk.RIGHT,
relief=tk.RAISED,
) )
menu_button.menu = tk.Menu(menu_button, tearoff=0) menu_button.grid(sticky="ew")
menu_button["menu"] = menu_button.menu menu = tk.Menu(menu_button, tearoff=0)
menu_button.grid() menu_button["menu"] = menu
menu.add_command(label="None")
menu.add_command(label="processes")
menu.add_command(label="ifconfig")
menu.add_command(label="IPv4 routes")
menu.add_command(label="IPv6 routes")
menu.add_command(label="OSPFv2 neighbors")
menu.add_command(label="OSPFv3 neighbors")
menu.add_command(label="Listening sockets")
menu.add_command(label="IPv4 MFC entries")
menu.add_command(label="IPv6 MFC entries")
menu.add_command(label="firewall rules")
menu.add_command(label="IPSec policies")
menu.add_command(label="docker logs")
menu.add_command(label="OSPFv3 MDR level")
menu.add_command(label="PIM neighbors")
menu.add_command(label="Edit...")
menu_button.menu.add_command(label="None") def click_stop(self):
menu_button.menu.add_command(label="processes")
menu_button.menu.add_command(label="ifconfig")
menu_button.menu.add_command(label="IPv4 routes")
menu_button.menu.add_command(label="IPv6 routes")
menu_button.menu.add_command(label="OSPFv2 neighbors")
menu_button.menu.add_command(label="OSPFv3 neighbors")
menu_button.menu.add_command(label="Listening sockets")
menu_button.menu.add_command(label="IPv4 MFC entries")
menu_button.menu.add_command(label="IPv6 MFC entries")
menu_button.menu.add_command(label="firewall rules")
menu_button.menu.add_command(label="IPSec policies")
menu_button.menu.add_command(label="docker logs")
menu_button.menu.add_command(label="OSPFv3 MDR level")
menu_button.menu.add_command(label="PIM neighbors")
menu_button.menu.add_command(label="Edit...")
def click_stop_button(self):
""" """
redraw buttons on the toolbar, send node and link messages to grpc server redraw buttons on the toolbar, send node and link messages to grpc server
@ -411,10 +369,11 @@ class Toolbar(tk.Frame):
self.app.core.stop_session() self.app.core.stop_session()
self.design_frame.tkraise() self.design_frame.tkraise()
def update_annotation(self, image_enum): def update_annotation(self, image):
logging.info("clicked annotation: ") logging.info("clicked annotation: ")
self.hide_pickers() self.hide_pickers()
self.annotation_button.configure(image=Images.get(image_enum)) self.annotation_button.configure(image=image)
self.annotation_button.image = image
def click_run_button(self): def click_run_button(self):
logging.debug("Click on RUN button") logging.debug("Click on RUN button")

View file

@ -1,7 +1,8 @@
import tkinter as tk import tkinter as tk
from tkinter import ttk
class CreateToolTip(object): class Tooltip(object):
""" """
Create tool tip for a given widget Create tool tip for a given widget
""" """
@ -9,10 +10,29 @@ class CreateToolTip(object):
def __init__(self, widget, text="widget info"): def __init__(self, widget, text="widget info"):
self.widget = widget self.widget = widget
self.text = text self.text = text
self.widget.bind("<Enter>", self.enter) self.widget.bind("<Enter>", self.on_enter)
self.widget.bind("<Leave>", self.close) self.widget.bind("<Leave>", self.on_leave)
self.waittime = 400
self.id = None
self.tw = None self.tw = None
def on_enter(self, event=None):
self.schedule()
def on_leave(self, event=None):
self.unschedule()
self.close(event)
def schedule(self):
self.unschedule()
self.id = self.widget.after(self.waittime, self.enter)
def unschedule(self):
id_ = self.id
self.id = None
if id_:
self.widget.after_cancel(id_)
def enter(self, event=None): def enter(self, event=None):
x, y, cx, cy = self.widget.bbox("insert") x, y, cx, cy = self.widget.bbox("insert")
x += self.widget.winfo_rootx() x += self.widget.winfo_rootx()
@ -21,13 +41,13 @@ class CreateToolTip(object):
self.tw = tk.Toplevel(self.widget) self.tw = tk.Toplevel(self.widget)
self.tw.wm_overrideredirect(True) self.tw.wm_overrideredirect(True)
self.tw.wm_geometry("+%d+%d" % (x, y)) self.tw.wm_geometry("+%d+%d" % (x, y))
label = tk.Label( label = ttk.Label(
self.tw, self.tw,
text=self.text, text=self.text,
justify=tk.LEFT, justify=tk.LEFT,
background="#ffffe6", background="#FFFFEA",
relief="solid", relief=tk.SOLID,
borderwidth=1, borderwidth=0,
) )
label.grid(padx=1) label.grid(padx=1)