Merge branch 'coretk' into coretk-config

This commit is contained in:
Huy Pham 2019-11-14 15:21:09 -08:00
commit bfcccd8dab
15 changed files with 286 additions and 331 deletions

View file

@ -15,21 +15,16 @@ from coretk.toolbar import Toolbar
class Application(tk.Frame): class Application(tk.Frame):
def __init__(self, master=None): def __init__(self, master=None):
super().__init__(master) super().__init__(master)
self.style = ttk.Style() # widgets
self.setup_theme()
self.menubar = None self.menubar = None
self.toolbar = None self.toolbar = None
self.canvas = None self.canvas = None
self.statusbar = None self.statusbar = None
self.is_open_xml = False
self.size_and_scale = None # setup
self.set_wallpaper = None
self.wallpaper_id = None
self.current_wallpaper = None
self.radiovar = tk.IntVar(value=1)
self.show_grid_var = tk.IntVar(value=1)
self.adjust_to_dim_var = tk.IntVar(value=0)
self.config = appconfig.read() self.config = appconfig.read()
self.style = ttk.Style()
self.setup_theme()
self.core = CoreClient(self) self.core = CoreClient(self)
self.setup_app() self.setup_app()
self.draw() self.draw()
@ -37,20 +32,27 @@ class Application(tk.Frame):
def setup_theme(self): def setup_theme(self):
themes.load(self.style) themes.load(self.style)
self.style.theme_use(themes.DARK) self.style.theme_use(self.config["preferences"]["theme"])
func = partial(themes.update_menu, self.style) func = partial(themes.update_menu, self.style)
self.master.bind_class("Menu", "<<ThemeChanged>>", func) self.master.bind_class("Menu", "<<ThemeChanged>>", func)
func = partial(themes.update_toplevel, self.style)
self.master.bind_class("Toplevel", "<<ThemeChanged>>", func)
def setup_app(self): def setup_app(self):
self.master.title("CORE") self.master.title("CORE")
self.master.geometry("1000x800") self.center()
self.master.protocol("WM_DELETE_WINDOW", self.on_closing) self.master.protocol("WM_DELETE_WINDOW", self.on_closing)
image = Images.get(ImageEnum.CORE, 16) 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)
def center(self):
width = 1000
height = 800
screen_width = self.master.winfo_screenwidth()
screen_height = self.master.winfo_screenheight()
x = int((screen_width / 2) - (width / 2))
y = int((screen_height / 2) - (height / 2))
self.master.geometry(f"{width}x{height}+{x}+{y}")
def draw(self): def draw(self):
self.master.option_add("*tearOff", tk.FALSE) self.master.option_add("*tearOff", tk.FALSE)
self.menubar = Menubar(self.master, self) self.menubar = Menubar(self.master, self)

View file

@ -6,6 +6,8 @@ from pathlib import Path
import yaml import yaml
# gui home paths # gui home paths
from coretk import themes
HOME_PATH = Path.home().joinpath(".coretk") HOME_PATH = Path.home().joinpath(".coretk")
BACKGROUNDS_PATH = HOME_PATH.joinpath("backgrounds") BACKGROUNDS_PATH = HOME_PATH.joinpath("backgrounds")
CUSTOM_EMANE_PATH = HOME_PATH.joinpath("custom_emane") CUSTOM_EMANE_PATH = HOME_PATH.joinpath("custom_emane")
@ -68,6 +70,7 @@ def check_directory():
editor = EDITORS[1] editor = EDITORS[1]
config = { config = {
"preferences": { "preferences": {
"theme": themes.DARK,
"editor": editor, "editor": editor,
"terminal": terminal, "terminal": terminal,
"gui3d": "/usr/local/bin/std3d.sh", "gui3d": "/usr/local/bin/std3d.sh",

View file

@ -1,27 +1,19 @@
""" """
set wallpaper set wallpaper
""" """
import enum
import logging import logging
import tkinter as tk import tkinter as tk
from tkinter import filedialog, ttk from tkinter import filedialog, ttk
from PIL import Image, ImageTk from PIL import Image
from coretk.appconfig import BACKGROUNDS_PATH from coretk.appconfig import BACKGROUNDS_PATH
from coretk.dialogs.dialog import Dialog from coretk.dialogs.dialog import Dialog
from coretk.images import Images
PADX = 5 PADX = 5
class ScaleOption(enum.Enum):
NONE = 0
UPPER_LEFT = 1
CENTERED = 2
SCALED = 3
TILED = 4
class CanvasBackgroundDialog(Dialog): class CanvasBackgroundDialog(Dialog):
def __init__(self, master, app): def __init__(self, master, app):
""" """
@ -31,11 +23,11 @@ class CanvasBackgroundDialog(Dialog):
""" """
super().__init__(master, app, "Canvas Background", modal=True) super().__init__(master, app, "Canvas Background", modal=True)
self.canvas = self.app.canvas self.canvas = self.app.canvas
self.radiovar = tk.IntVar(value=self.app.radiovar.get()) self.scale_option = tk.IntVar(value=self.canvas.scale_option.get())
self.show_grid_var = tk.IntVar(value=self.app.show_grid_var.get()) self.show_grid = tk.BooleanVar(value=self.canvas.show_grid.get())
self.adjust_to_dim_var = tk.IntVar(value=self.app.adjust_to_dim_var.get()) self.adjust_to_dim = tk.BooleanVar(value=self.canvas.adjust_to_dim.get())
self.filename = tk.StringVar(value=self.canvas.wallpaper_file)
self.image_label = None self.image_label = None
self.file_name = tk.StringVar()
self.options = [] self.options = []
self.draw() self.draw()
@ -57,6 +49,8 @@ class CanvasBackgroundDialog(Dialog):
def draw_image_label(self): def draw_image_label(self):
label = ttk.Label(self.top, text="Image filename: ") label = ttk.Label(self.top, text="Image filename: ")
label.grid(row=1, column=0, sticky="ew") label.grid(row=1, column=0, sticky="ew")
if self.filename.get():
self.draw_preview()
def draw_image_selection(self): def draw_image_selection(self):
frame = ttk.Frame(self.top) frame = ttk.Frame(self.top)
@ -65,7 +59,7 @@ class CanvasBackgroundDialog(Dialog):
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 = ttk.Entry(frame, textvariable=self.file_name) entry = ttk.Entry(frame, textvariable=self.filename)
entry.focus() entry.focus()
entry.grid(row=0, column=0, sticky="ew", padx=PADX) entry.grid(row=0, column=0, sticky="ew", padx=PADX)
@ -84,42 +78,43 @@ class CanvasBackgroundDialog(Dialog):
frame.grid(row=3, column=0, sticky="ew") frame.grid(row=3, column=0, sticky="ew")
button = ttk.Radiobutton( button = ttk.Radiobutton(
frame, text="upper-left", value=1, variable=self.radiovar frame, text="upper-left", value=1, variable=self.scale_option
) )
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 = ttk.Radiobutton( button = ttk.Radiobutton(
frame, text="centered", value=2, variable=self.radiovar frame, text="centered", value=2, variable=self.scale_option
) )
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 = ttk.Radiobutton(frame, text="scaled", value=3, variable=self.radiovar) button = ttk.Radiobutton(
frame, text="scaled", value=3, variable=self.scale_option
)
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 = ttk.Radiobutton(frame, text="titled", value=4, variable=self.radiovar) button = ttk.Radiobutton(
frame, text="titled", value=4, variable=self.scale_option
)
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 = ttk.Checkbutton( checkbutton = ttk.Checkbutton(
self.top, text="Show grid", variable=self.show_grid_var self.top, text="Show grid", variable=self.show_grid
) )
checkbutton.grid(row=4, column=0, sticky="ew", padx=PADX) checkbutton.grid(row=4, column=0, sticky="ew", padx=PADX)
checkbutton = ttk.Checkbutton( checkbutton = ttk.Checkbutton(
self.top, self.top,
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,
command=self.click_adjust_canvas, command=self.click_adjust_canvas,
) )
checkbutton.grid(row=5, column=0, sticky="ew", padx=PADX) checkbutton.grid(row=5, column=0, sticky="ew", padx=PADX)
self.show_grid_var.set(1)
self.adjust_to_dim_var.set(0)
def draw_buttons(self): def draw_buttons(self):
frame = ttk.Frame(self.top) frame = ttk.Frame(self.top)
frame.grid(row=6, column=0, pady=5, sticky="ew") frame.grid(row=6, column=0, pady=5, sticky="ew")
@ -142,13 +137,13 @@ class CanvasBackgroundDialog(Dialog):
), ),
) )
if filename: if filename:
self.file_name.set(filename) self.filename.set(filename)
width, height = 250, 135 self.draw_preview()
img = Image.open(filename)
img = img.resize((width, height), Image.ANTIALIAS) def draw_preview(self):
tk_img = ImageTk.PhotoImage(img) image = Images.create(self.filename.get(), 250, 135)
self.image_label.config(image=tk_img, width=width) self.image_label.config(image=image)
self.image_label.image = tk_img self.image_label.image = image
def click_clear(self): def click_clear(self):
""" """
@ -157,218 +152,47 @@ class CanvasBackgroundDialog(Dialog):
:return: nothing :return: nothing
""" """
# delete entry # delete entry
self.file_name.set("") self.filename.set("")
# delete display image # delete display image
self.image_label.config(image="", width=32) self.image_label.config(image="", width=32)
self.image_label.image = None
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
if self.adjust_to_dim_var.get() == 1: if self.adjust_to_dim.get():
self.radiovar.set(0) self.scale_option.set(0)
for option in self.options: for option in self.options:
option.config(state=tk.DISABLED) option.config(state=tk.DISABLED)
# turn back the radio button to active state so that user can choose again # turn back the radio button to active state so that user can choose again
elif self.adjust_to_dim_var.get() == 0: else:
self.radiovar.set(1) self.scale_option.set(1)
for option in self.options: for option in self.options:
option.config(state=tk.NORMAL) option.config(state=tk.NORMAL)
else:
logging.error("canvasbackground.py adjust_canvas_size invalid value")
def delete_canvas_components(self, tag_list):
"""
delete canvas items whose tag is in the tag list
:param list[string] tag_list: list of tags
:return: nothing
"""
for tag in tag_list:
for i in self.canvas.find_withtag(tag):
self.canvas.delete(i)
def get_canvas_width_and_height(self):
"""
retrieve canvas width and height in pixels
:return: nothing
"""
canvas = self.app.canvas
grid = canvas.find_withtag("rectangle")[0]
x0, y0, x1, y1 = canvas.coords(grid)
canvas_w = abs(x0 - x1)
canvas_h = abs(y0 - y1)
return canvas_w, canvas_h
def determine_cropped_image_dimension(self):
"""
determine the dimension of the image after being cropped
:return: nothing
"""
return
def upper_left(self, img):
tk_img = ImageTk.PhotoImage(img)
# crop image if it is bigger than canvas
canvas_w, canvas_h = self.get_canvas_width_and_height()
cropx = img_w = tk_img.width()
cropy = img_h = tk_img.height()
if img_w > canvas_w:
cropx -= img_w - canvas_w
if img_h > canvas_h:
cropy -= img_h - canvas_h
cropped = img.crop((0, 0, cropx, cropy))
cropped_tk = ImageTk.PhotoImage(cropped)
# place left corner of image to the left corner of the canvas
self.app.croppedwallpaper = cropped_tk
self.delete_canvas_components(["wallpaper"])
# self.delete_previous_wallpaper()
wid = self.canvas.create_image(
(cropx / 2, cropy / 2), image=cropped_tk, tags="wallpaper"
)
self.app.wallpaper_id = wid
def center(self, img):
"""
place the image at the center of canvas
:param Image img: image object
:return: nothing
"""
tk_img = ImageTk.PhotoImage(img)
canvas_w, canvas_h = self.get_canvas_width_and_height()
cropx = img_w = tk_img.width()
cropy = img_h = tk_img.height()
# dimension of the cropped image
if img_w > canvas_w:
cropx -= img_w - canvas_w
if img_h > canvas_h:
cropy -= img_h - canvas_h
x0 = (img_w - cropx) / 2
y0 = (img_h - cropy) / 2
x1 = x0 + cropx
y1 = y0 + cropy
cropped = img.crop((x0, y0, x1, y1))
cropped_tk = ImageTk.PhotoImage(cropped)
# place the center of the image at the center of the canvas
self.app.croppedwallpaper = cropped_tk
self.delete_canvas_components(["wallpaper"])
# self.delete_previous_wallpaper()
wid = self.canvas.create_image(
(canvas_w / 2, canvas_h / 2), image=cropped_tk, tags="wallpaper"
)
self.app.wallpaper_id = wid
def scaled(self, img):
"""
scale image based on canvas dimension
:param Image img: image object
:return: nothing
"""
canvas_w, canvas_h = self.get_canvas_width_and_height()
resized_image = img.resize((int(canvas_w), int(canvas_h)), Image.ANTIALIAS)
image_tk = ImageTk.PhotoImage(resized_image)
self.app.croppedwallpaper = image_tk
self.delete_canvas_components(["wallpaper"])
# self.delete_previous_wallpaper()
wid = self.canvas.create_image(
(canvas_w / 2, canvas_h / 2), image=image_tk, tags="wallpaper"
)
self.app.wallpaper_id = wid
def tiled(self, img):
return
def draw_new_canvas(self, canvas_width, canvas_height):
"""
delete the old canvas and draw a new one
:param int canvas_width: canvas width in pixel
:param int canvas_height: canvas height in pixel
:return:
"""
self.delete_canvas_components(["rectangle", "gridline"])
self.canvas.draw_grid(canvas_width, canvas_height)
def canvas_to_image_dimension(self, img):
image_tk = ImageTk.PhotoImage(img)
img_w = image_tk.width()
img_h = image_tk.height()
self.delete_canvas_components(["wallpaper"])
self.draw_new_canvas(img_w, img_h)
wid = self.canvas.create_image((img_w / 2, img_h / 2), image=image_tk)
self.app.croppedwallpaper = image_tk
self.app.wallpaper_id = wid
def show_grid(self):
"""
:return: nothing
"""
self.app.adjust_to_dim_var.set(self.adjust_to_dim_var.get())
if self.show_grid_var.get() == 0:
for i in self.canvas.find_withtag("gridline"):
self.canvas.itemconfig(i, state=tk.HIDDEN)
elif self.show_grid_var.get() == 1:
for i in self.canvas.find_withtag("gridline"):
self.canvas.itemconfig(i, state=tk.NORMAL)
self.canvas.lift(i)
else:
logging.error("canvasbackground.py show_grid invalid value")
def save_wallpaper_options(self):
self.app.radiovar.set(self.radiovar.get())
self.app.show_grid_var.set(self.show_grid_var.get())
self.app.adjust_to_dim_var.set(self.adjust_to_dim_var.get())
def click_apply(self): def click_apply(self):
filename = self.file_name.get() self.canvas.scale_option.set(self.scale_option.get())
self.canvas.show_grid.set(self.show_grid.get())
self.canvas.adjust_to_dim.set(self.adjust_to_dim.get())
self.canvas.update_grid()
filename = self.filename.get()
if not filename: if not filename:
self.delete_canvas_components(["wallpaper"]) self.canvas.delete(self.canvas.wallpaper_id)
self.canvas.wallpaper = None
self.canvas.wallpaper_file = None
self.destroy() self.destroy()
self.app.current_wallpaper = None
self.save_wallpaper_options()
return return
try: try:
img = Image.open(filename) img = Image.open(filename)
self.app.current_wallpaper = img self.canvas.wallpaper = img
self.canvas.wallpaper_file = filename
self.canvas.redraw()
except FileNotFoundError: except FileNotFoundError:
logging.error("invalid background: %s", filename) logging.error("invalid background: %s", filename)
if self.app.wallpaper_id: if self.canvas.wallpaper_id:
self.canvas.delete(self.app.wallpaper_id) self.canvas.delete(self.canvas.wallpaper_id)
self.destroy() self.canvas.wallpaper_id = None
return self.canvas.wallpaper_file = None
self.app.adjust_to_dim_var.set(self.adjust_to_dim_var.get())
if self.adjust_to_dim_var.get() == 0:
self.app.radiovar.set(self.radiovar.get())
option = ScaleOption(self.radiovar.get())
if option == ScaleOption.UPPER_LEFT:
self.upper_left(img)
elif option == ScaleOption.CENTERED:
self.center(img)
elif option == ScaleOption.SCALED:
self.scaled(img)
elif option == ScaleOption.TILED:
print("not implemented yet")
elif self.adjust_to_dim_var.get() == 1:
self.canvas_to_image_dimension(img)
self.show_grid()
self.destroy() self.destroy()

View file

@ -4,12 +4,9 @@ size and scale
import tkinter as tk import tkinter as tk
from tkinter import font, ttk from tkinter import font, ttk
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"] FRAME_PAD = 5
FRAME_BAD = 5
PAD = (0, 0, 5, 0)
PADX = 5 PADX = 5
@ -21,13 +18,13 @@ class SizeAndScaleDialog(Dialog):
:param app: main application :param app: main application
""" """
super().__init__(master, app, "Canvas Size and Scale", modal=True) super().__init__(master, app, "Canvas Size and Scale", modal=True)
self.meter_per_pixel = self.app.canvas.meters_per_pixel self.canvas = self.app.canvas
self.meter_per_pixel = self.canvas.meters_per_pixel
self.section_font = font.Font(weight="bold") self.section_font = font.Font(weight="bold")
# get current canvas dimensions # get current canvas dimensions
canvas = self.app.canvas plot = self.canvas.find_withtag("rectangle")
plot = canvas.find_withtag("rectangle") x0, y0, x1, y1 = self.canvas.bbox(plot[0])
x0, y0, x1, y1 = canvas.bbox(plot[0])
width = abs(x0 - x1) - 2 width = abs(x0 - x1) - 2
height = abs(y0 - y1) - 2 height = abs(y0 - y1) - 2
self.pixel_width = tk.IntVar(value=width) self.pixel_width = tk.IntVar(value=width)
@ -52,7 +49,7 @@ class SizeAndScaleDialog(Dialog):
self.draw_buttons() self.draw_buttons()
def draw_size(self): def draw_size(self):
label_frame = ttk.Labelframe(self.top, text="Size", padding=FRAME_BAD) label_frame = ttk.Labelframe(self.top, text="Size", padding=FRAME_PAD)
label_frame.grid(sticky="ew") label_frame.grid(sticky="ew")
label_frame.columnconfigure(0, weight=1) label_frame.columnconfigure(0, weight=1)
@ -89,7 +86,7 @@ class SizeAndScaleDialog(Dialog):
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_frame = ttk.Labelframe(self.top, text="Scale", padding=FRAME_BAD) label_frame = ttk.Labelframe(self.top, text="Scale", padding=FRAME_PAD)
label_frame.grid(sticky="ew") label_frame.grid(sticky="ew")
label_frame.columnconfigure(0, weight=1) label_frame.columnconfigure(0, weight=1)
@ -105,7 +102,7 @@ class SizeAndScaleDialog(Dialog):
def draw_reference_point(self): def draw_reference_point(self):
label_frame = ttk.Labelframe( label_frame = ttk.Labelframe(
self.top, text="Reference Point", padding=FRAME_BAD self.top, text="Reference Point", padding=FRAME_PAD
) )
label_frame.grid(sticky="ew") label_frame.grid(sticky="ew")
label_frame.columnconfigure(0, weight=1) label_frame.columnconfigure(0, weight=1)
@ -122,14 +119,12 @@ class SizeAndScaleDialog(Dialog):
label = ttk.Label(frame, text="X") label = ttk.Label(frame, text="X")
label.grid(row=0, column=0, sticky="w", padx=PADX) label.grid(row=0, column=0, sticky="w", padx=PADX)
x_var = tk.StringVar(value=0) entry = ttk.Entry(frame, textvariable=self.x)
entry = ttk.Entry(frame, textvariable=x_var)
entry.grid(row=0, column=1, sticky="ew", padx=PADX) 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", padx=PADX) label.grid(row=0, column=2, sticky="w", padx=PADX)
y_var = tk.StringVar(value=0) entry = ttk.Entry(frame, textvariable=self.y)
entry = ttk.Entry(frame, textvariable=y_var)
entry.grid(row=0, column=3, sticky="ew", padx=PADX) entry.grid(row=0, column=3, sticky="ew", padx=PADX)
label = ttk.Label(label_frame, text="Translates To") label = ttk.Label(label_frame, text="Translates To")
@ -174,47 +169,11 @@ class SizeAndScaleDialog(Dialog):
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")
def redraw_grid(self):
"""
redraw grid with new dimension
:return: nothing
"""
width, height = self.pixel_width.get(), self.pixel_height.get()
canvas = self.app.canvas
canvas.config(scrollregion=(0, 0, width + 200, height + 200))
# delete old plot and redraw
for i in canvas.find_withtag("gridline"):
canvas.delete(i)
for i in canvas.find_withtag("rectangle"):
canvas.delete(i)
canvas.draw_grid(width=width, height=height)
# lift anything that is drawn on the plot before
for tag in DRAW_OBJECT_TAGS:
for i in canvas.find_withtag(tag):
canvas.lift(i)
def click_apply(self): def click_apply(self):
meter_per_pixel = float(self.scale.get()) / 100 meter_per_pixel = float(self.scale.get()) / 100
self.app.canvas.meters_per_pixel = meter_per_pixel width, height = self.pixel_width.get(), self.pixel_height.get()
self.redraw_grid() self.canvas.meters_per_pixel = meter_per_pixel
# if there is a current wallpaper showing, redraw it based on current wallpaper options self.canvas.redraw_grid(width, height)
wallpaper_tool = self.app.set_wallpaper if self.canvas.wallpaper:
current_wallpaper = self.app.current_wallpaper self.canvas.redraw()
if current_wallpaper:
if self.app.adjust_to_dim_var.get() == 0:
if self.app.radiovar.get() == ScaleOption.UPPER_LEFT.value:
wallpaper_tool.upper_left(current_wallpaper)
elif self.app.radiovar.get() == ScaleOption.CENTERED.value:
wallpaper_tool.center(current_wallpaper)
elif self.app.radiovar.get() == ScaleOption.SCALED.value:
wallpaper_tool.scaled(current_wallpaper)
elif self.app.radiovar.get() == ScaleOption.TILED.value:
print("not implemented")
elif self.app.adjust_to_dim_var.get() == 1:
wallpaper_tool.canvas_to_image_dimension(current_wallpaper)
wallpaper_tool.show_grid()
self.destroy() self.destroy()

View file

@ -35,7 +35,7 @@ class ServicesSelectDialog(Dialog):
self.groups.listbox.selection_set(0) self.groups.listbox.selection_set(0)
self.services = CheckboxList( self.services = CheckboxList(
frame, text="Services", clicked=self.service_clicked frame, self.app, text="Services", clicked=self.service_clicked
) )
self.services.grid(row=0, column=1, sticky="nsew") self.services.grid(row=0, column=1, sticky="nsew")

View file

@ -93,7 +93,7 @@ class EmaneConfiguration(Dialog):
self.emane_dialog.top.columnconfigure(0, weight=1) self.emane_dialog.top.columnconfigure(0, weight=1)
self.emane_dialog.top.rowconfigure(0, weight=1) self.emane_dialog.top.rowconfigure(0, weight=1)
self.emane_config_frame = ConfigFrame( self.emane_config_frame = ConfigFrame(
self.emane_dialog.top, config=self.options self.emane_dialog.top, self.app, config=self.options
) )
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")
@ -167,7 +167,7 @@ class EmaneConfiguration(Dialog):
self.model_options = response.config self.model_options = response.config
self.model_config_frame = ConfigFrame( self.model_config_frame = ConfigFrame(
self.emane_model_dialog.top, config=self.model_options self.emane_model_dialog.top, self.app, config=self.model_options
) )
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()

View file

@ -38,7 +38,7 @@ class NodeService(Dialog):
self.groups.listbox.selection_set(0) self.groups.listbox.selection_set(0)
self.services = CheckboxList( self.services = CheckboxList(
frame, text="Services", clicked=self.service_clicked frame, self.app, text="Services", clicked=self.service_clicked
) )
self.services.grid(row=0, column=1, sticky="nsew") self.services.grid(row=0, column=1, sticky="nsew")

View file

@ -1,3 +1,4 @@
import logging
import tkinter as tk import tkinter as tk
from tkinter import ttk from tkinter import ttk
@ -10,41 +11,52 @@ class PreferencesDialog(Dialog):
super().__init__(master, app, "Preferences", modal=True) super().__init__(master, app, "Preferences", modal=True)
preferences = self.app.config["preferences"] preferences = self.app.config["preferences"]
self.editor = tk.StringVar(value=preferences["editor"]) self.editor = tk.StringVar(value=preferences["editor"])
self.theme = tk.StringVar(value=preferences["theme"])
self.terminal = tk.StringVar(value=preferences["terminal"]) self.terminal = tk.StringVar(value=preferences["terminal"])
self.gui3d = tk.StringVar(value=preferences["gui3d"]) self.gui3d = tk.StringVar(value=preferences["gui3d"])
self.draw() self.draw()
def draw(self): def draw(self):
self.top.columnconfigure(0, weight=1) self.top.columnconfigure(0, weight=1)
self.draw_programs() self.draw_preferences()
self.draw_buttons() self.draw_buttons()
def draw_programs(self): def draw_preferences(self):
frame = ttk.LabelFrame(self.top, text="Programs") frame = ttk.LabelFrame(self.top, text="Preferences")
frame.grid(sticky="ew", pady=2) frame.grid(sticky="ew", pady=2)
frame.columnconfigure(1, weight=1) frame.columnconfigure(1, weight=1)
label = ttk.Label(frame, text="Editor") label = ttk.Label(frame, text="Theme")
label.grid(row=0, column=0, pady=2, padx=2, sticky="w") label.grid(row=0, column=0, pady=2, padx=2, sticky="w")
themes = self.app.style.theme_names()
combobox = ttk.Combobox(
frame, textvariable=self.theme, values=themes, state="readonly"
)
combobox.set(self.theme.get())
combobox.grid(row=0, column=1, sticky="ew")
combobox.bind("<<ComboboxSelected>>", self.theme_change)
label = ttk.Label(frame, text="Editor")
label.grid(row=1, column=0, pady=2, padx=2, sticky="w")
combobox = ttk.Combobox( combobox = ttk.Combobox(
frame, textvariable=self.editor, values=appconfig.EDITORS, state="readonly" frame, textvariable=self.editor, values=appconfig.EDITORS, state="readonly"
) )
combobox.grid(row=0, column=1, sticky="ew") combobox.grid(row=1, column=1, sticky="ew")
label = ttk.Label(frame, text="Terminal") label = ttk.Label(frame, text="Terminal")
label.grid(row=1, column=0, pady=2, padx=2, sticky="w") label.grid(row=2, column=0, pady=2, padx=2, sticky="w")
combobox = ttk.Combobox( combobox = ttk.Combobox(
frame, frame,
textvariable=self.terminal, textvariable=self.terminal,
values=appconfig.TERMINALS, values=appconfig.TERMINALS,
state="readonly", state="readonly",
) )
combobox.grid(row=1, column=1, sticky="ew") combobox.grid(row=2, column=1, sticky="ew")
label = ttk.Label(frame, text="3D GUI") label = ttk.Label(frame, text="3D GUI")
label.grid(row=2, column=0, pady=2, padx=2, sticky="w") label.grid(row=3, column=0, pady=2, padx=2, sticky="w")
entry = ttk.Entry(frame, textvariable=self.gui3d) entry = ttk.Entry(frame, textvariable=self.gui3d)
entry.grid(row=2, column=1, sticky="ew") entry.grid(row=3, column=1, sticky="ew")
def draw_buttons(self): def draw_buttons(self):
frame = ttk.Frame(self.top) frame = ttk.Frame(self.top)
@ -58,10 +70,16 @@ class PreferencesDialog(Dialog):
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")
def theme_change(self, event):
theme = self.theme.get()
logging.info("changing theme: %s", theme)
self.app.style.theme_use(theme)
def click_save(self): def click_save(self):
preferences = self.app.config["preferences"] preferences = self.app.config["preferences"]
preferences["terminal"] = self.terminal.get() preferences["terminal"] = self.terminal.get()
preferences["editor"] = self.editor.get() preferences["editor"] = self.editor.get()
preferences["gui3d"] = self.gui3d.get() preferences["gui3d"] = self.gui3d.get()
preferences["theme"] = self.theme.get()
self.app.save_config() self.app.save_config()
self.destroy() self.destroy()

View file

@ -22,7 +22,7 @@ class SessionOptionsDialog(Dialog):
response = self.app.core.client.get_session_options(session_id) response = self.app.core.client.get_session_options(session_id)
logging.info("session options: %s", response) logging.info("session options: %s", response)
self.config_frame = ConfigFrame(self.top, config=response.config) self.config_frame = ConfigFrame(self.top, self.app, config=response.config)
self.config_frame.draw_config() self.config_frame.draw_config()
self.config_frame.grid(sticky="nsew") self.config_frame.grid(sticky="nsew")

View file

@ -2,6 +2,8 @@ import enum
import logging import logging
import tkinter as tk import tkinter as tk
from PIL import ImageTk
from core.api.grpc import core_pb2 from core.api.grpc import core_pb2
from coretk.canvasaction import CanvasAction from coretk.canvasaction import CanvasAction
from coretk.canvastooltip import CanvasTooltip from coretk.canvastooltip import CanvasTooltip
@ -21,6 +23,14 @@ class GraphMode(enum.Enum):
OTHER = 4 OTHER = 4
class ScaleOption(enum.Enum):
NONE = 0
UPPER_LEFT = 1
CENTERED = 2
SCALED = 3
TILED = 4
CORE_NODES = ["router"] CORE_NODES = ["router"]
CORE_WIRED_NETWORK_NODES = [] CORE_WIRED_NETWORK_NODES = []
CORE_WIRELESS_NODE = ["wlan"] CORE_WIRELESS_NODE = ["wlan"]
@ -43,11 +53,8 @@ class CanvasGraph(tk.Canvas):
self.drawing_edge = None self.drawing_edge = None
self.grid = None self.grid = None
self.meters_per_pixel = 1.5 self.meters_per_pixel = 1.5
self.canvas_management = CanvasComponentManagement(self, core) self.canvas_management = CanvasComponentManagement(self, core)
self.canvas_action = CanvasAction(master, self) self.canvas_action = CanvasAction(master, self)
self.setup_menus() self.setup_menus()
self.setup_bindings() self.setup_bindings()
self.draw_grid() self.draw_grid()
@ -57,6 +64,15 @@ class CanvasGraph(tk.Canvas):
self.wireless_draw = WirelessConnection(self, core) self.wireless_draw = WirelessConnection(self, core)
self.is_node_context_opened = False self.is_node_context_opened = False
# background related
self.wallpaper_id = None
self.wallpaper = None
self.wallpaper_drawn = None
self.wallpaper_file = ""
self.scale_option = tk.IntVar(value=1)
self.show_grid = tk.BooleanVar(value=True)
self.adjust_to_dim = tk.BooleanVar(value=False)
def setup_menus(self): def setup_menus(self):
self.node_context = tk.Menu(self.master) self.node_context = tk.Menu(self.master)
self.node_context.add_command( self.node_context.add_command(
@ -95,8 +111,6 @@ class CanvasGraph(tk.Canvas):
self.drawing_edge = None self.drawing_edge = None
self.draw_existing_component(session) self.draw_existing_component(session)
# self.grpc_manager.wlanconfig_management.load_wlan_configurations(self.core_grpc)
def setup_bindings(self): def setup_bindings(self):
""" """
Bind any mouse events or hot keys to the matching action Bind any mouse events or hot keys to the matching action
@ -128,11 +142,12 @@ class CanvasGraph(tk.Canvas):
width=1, width=1,
tags="rectangle", tags="rectangle",
) )
self.tag_lower(self.grid)
for i in range(0, width, 27): for i in range(0, width, 27):
self.create_line(i, 0, i, height, dash=(2, 4), tags="gridline") self.create_line(i, 0, i, height, dash=(2, 4), tags="gridline")
for i in range(0, height, 27): for i in range(0, height, 27):
self.create_line(0, i, width, i, dash=(2, 4), tags="gridline") self.create_line(0, i, width, i, dash=(2, 4), tags="gridline")
self.tag_lower("gridline")
self.tag_lower(self.grid)
def draw_existing_component(self, session): def draw_existing_component(self, session):
""" """
@ -224,9 +239,8 @@ class CanvasGraph(tk.Canvas):
if2 if2
) )
# lift the nodes so they on top of the links # raise the nodes so they on top of the links
for i in self.find_withtag("node"): self.tag_raise("node")
self.lift(i)
def canvas_xy(self, event): def canvas_xy(self, event):
""" """
@ -422,6 +436,132 @@ class CanvasGraph(tk.Canvas):
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
def width_and_height(self):
"""
retrieve canvas width and height in pixels
:return: nothing
"""
grid = self.find_withtag("rectangle")[0]
x0, y0, x1, y1 = self.coords(grid)
canvas_w = abs(x0 - x1)
canvas_h = abs(y0 - y1)
return canvas_w, canvas_h
def wallpaper_upper_left(self):
tk_img = ImageTk.PhotoImage(self.wallpaper)
# crop image if it is bigger than canvas
canvas_w, canvas_h = self.width_and_height()
cropx = img_w = tk_img.width()
cropy = img_h = tk_img.height()
if img_w > canvas_w:
cropx -= img_w - canvas_w
if img_h > canvas_h:
cropy -= img_h - canvas_h
cropped = self.wallpaper.crop((0, 0, cropx, cropy))
cropped_tk = ImageTk.PhotoImage(cropped)
self.delete(self.wallpaper_id)
# place left corner of image to the left corner of the canvas
self.wallpaper_id = self.create_image(
(cropx / 2, cropy / 2), image=cropped_tk, tags="wallpaper"
)
self.wallpaper_drawn = cropped_tk
def wallpaper_center(self):
"""
place the image at the center of canvas
:param Image img: image object
:return: nothing
"""
tk_img = ImageTk.PhotoImage(self.wallpaper)
canvas_w, canvas_h = self.width_and_height()
cropx = img_w = tk_img.width()
cropy = img_h = tk_img.height()
# dimension of the cropped image
if img_w > canvas_w:
cropx -= img_w - canvas_w
if img_h > canvas_h:
cropy -= img_h - canvas_h
x0 = (img_w - cropx) / 2
y0 = (img_h - cropy) / 2
x1 = x0 + cropx
y1 = y0 + cropy
cropped = self.wallpaper.crop((x0, y0, x1, y1))
cropped_tk = ImageTk.PhotoImage(cropped)
# place the center of the image at the center of the canvas
self.delete(self.wallpaper_id)
self.wallpaper_id = self.create_image(
(canvas_w / 2, canvas_h / 2), image=cropped_tk, tags="wallpaper"
)
self.wallpaper_drawn = cropped_tk
def wallpaper_scaled(self):
"""
scale image based on canvas dimension
:param Image img: image object
:return: nothing
"""
canvas_w, canvas_h = self.width_and_height()
image = Images.create(self.wallpaper_file, int(canvas_w), int(canvas_h))
self.delete(self.wallpaper_id)
self.wallpaper_id = self.create_image(
(canvas_w / 2, canvas_h / 2), image=image, tags="wallpaper"
)
self.wallpaper_drawn = image
def resize_to_wallpaper(self):
image_tk = ImageTk.PhotoImage(self.wallpaper)
img_w = image_tk.width()
img_h = image_tk.height()
self.delete(self.wallpaper_id)
self.delete("rectangle")
self.delete("gridline")
self.draw_grid(img_w, img_h)
self.wallpaper_id = self.create_image((img_w / 2, img_h / 2), image=image_tk)
self.wallpaper_drawn = image_tk
def redraw_grid(self, width, height):
"""
redraw grid with new dimension
:return: nothing
"""
self.config(scrollregion=(0, 0, width + 200, height + 200))
# delete previous grid
self.delete("rectangle")
self.delete("gridline")
# redraw
self.draw_grid(width=width, height=height)
# hide/show grid
self.update_grid()
def redraw(self):
if self.adjust_to_dim.get():
self.resize_to_wallpaper()
else:
option = ScaleOption(self.scale_option.get())
if option == ScaleOption.UPPER_LEFT:
self.wallpaper_upper_left()
elif option == ScaleOption.CENTERED:
self.wallpaper_center()
elif option == ScaleOption.SCALED:
self.wallpaper_scaled()
elif option == ScaleOption.TILED:
logging.warning("tiled background not implemented yet")
def update_grid(self):
logging.info("updating grid show: %s", self.show_grid.get())
if self.show_grid.get():
self.itemconfig("gridline", state=tk.NORMAL)
self.tag_raise("gridline")
else:
self.itemconfig("gridline", state=tk.HIDDEN)
class CanvasEdge: class CanvasEdge:
""" """
@ -465,8 +605,6 @@ class CanvasEdge:
self.link_info = None self.link_info = None
self.throughput = None self.throughput = None
self.wired = is_wired self.wired = is_wired
# TODO resolve this
# self.canvas.tag_lower(self.id)
def complete(self, dst, x, y): def complete(self, dst, x, y):
self.dst = dst self.dst = dst
@ -474,8 +612,8 @@ class CanvasEdge:
x1, y1, _, _ = self.canvas.coords(self.id) x1, y1, _, _ = self.canvas.coords(self.id)
self.canvas.coords(self.id, x1, y1, x, y) self.canvas.coords(self.id, x1, y1, x, y)
self.canvas.helper.draw_wireless_case(self.src, self.dst, self) self.canvas.helper.draw_wireless_case(self.src, self.dst, self)
self.canvas.lift(self.src) self.canvas.tag_raise(self.src)
self.canvas.lift(self.dst) self.canvas.tag_raise(self.dst)
def delete(self): def delete(self):
self.canvas.delete(self.id) self.canvas.delete(self.id)

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.1 KiB

After

Width:  |  Height:  |  Size: 337 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 146 B

After

Width:  |  Height:  |  Size: 173 B

View file

@ -73,7 +73,6 @@ class MenuAction:
def file_open_xml(self, event=None): def file_open_xml(self, event=None):
logging.info("menuaction.py file_open_xml()") logging.info("menuaction.py file_open_xml()")
self.app.is_open_xml = True
file_path = filedialog.askopenfilename( file_path = filedialog.askopenfilename(
initialdir=str(XML_PATH), initialdir=str(XML_PATH),
title="Open", title="Open",

View file

@ -1,3 +1,4 @@
import logging
import tkinter as tk import tkinter as tk
DARK = "black" DARK = "black"
@ -6,6 +7,7 @@ DARK = "black"
class Styles: class Styles:
tooltip = "Tooltip.TLabel" tooltip = "Tooltip.TLabel"
tooltip_frame = "Tooltip.TFrame" tooltip_frame = "Tooltip.TFrame"
service_checkbutton = "Service.TCheckbutton"
class Colors: class Colors:
@ -20,6 +22,7 @@ class Colors:
selectfg = "#ffffff" selectfg = "#ffffff"
white = "white" white = "white"
black = "black" black = "black"
listboxbg = "#f2f1f0"
def load(style): def load(style):
@ -86,6 +89,7 @@ def load(style):
"padding": (2, 0), "padding": (2, 0),
} }
}, },
"TLabelframe": {"configure": {"relief": tk.GROOVE}},
"TNotebook.Tab": { "TNotebook.Tab": {
"configure": {"padding": (6, 2, 6, 2)}, "configure": {"padding": (6, 2, 6, 2)},
"map": {"background": [("selected", Colors.lighter)]}, "map": {"background": [("selected", Colors.lighter)]},
@ -105,13 +109,18 @@ def load(style):
"configure": {"justify": tk.LEFT, "relief": tk.SOLID, "borderwidth": 0} "configure": {"justify": tk.LEFT, "relief": tk.SOLID, "borderwidth": 0}
}, },
Styles.tooltip_frame: {"configure": {}}, Styles.tooltip_frame: {"configure": {}},
Styles.service_checkbutton: {
"configure": {
"background": Colors.listboxbg,
"foreground": Colors.black,
}
},
}, },
) )
def update_toplevel(style, event): def update_bg(style, event):
if not isinstance(event.widget, tk.Toplevel): logging.info("updating background: %s", event.widget)
return
bg = style.lookup(".", "background") bg = style.lookup(".", "background")
event.widget.config(background=bg) event.widget.config(background=bg)

View file

@ -18,11 +18,13 @@ INT_TYPES = {
class FrameScroll(ttk.LabelFrame): class FrameScroll(ttk.LabelFrame):
def __init__(self, master=None, _cls=tk.Frame, **kw): def __init__(self, master, app, _cls=ttk.Frame, **kw):
super().__init__(master, **kw) super().__init__(master, **kw)
self.app = app
self.rowconfigure(0, weight=1) self.rowconfigure(0, weight=1)
self.columnconfigure(0, weight=1) self.columnconfigure(0, weight=1)
self.canvas = tk.Canvas(self, highlightthickness=0) bg = self.app.style.lookup(".", "background")
self.canvas = tk.Canvas(self, highlightthickness=0, background=bg)
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)
@ -54,8 +56,8 @@ class FrameScroll(ttk.LabelFrame):
class ConfigFrame(FrameScroll): class ConfigFrame(FrameScroll):
def __init__(self, master=None, config=None, **kw): def __init__(self, master, app, config, **kw):
super().__init__(master, ttk.Notebook, **kw) super().__init__(master, app, ttk.Notebook, **kw)
self.config = config self.config = config
self.values = {} self.values = {}
@ -136,13 +138,14 @@ class ListboxScroll(ttk.LabelFrame):
self.listbox = tk.Listbox( self.listbox = tk.Listbox(
self, selectmode=tk.SINGLE, yscrollcommand=self.scrollbar.set self, selectmode=tk.SINGLE, yscrollcommand=self.scrollbar.set
) )
logging.info("listbox background: %s", self.listbox.cget("background"))
self.listbox.grid(row=0, column=0, sticky="nsew") self.listbox.grid(row=0, column=0, sticky="nsew")
self.scrollbar.config(command=self.listbox.yview) self.scrollbar.config(command=self.listbox.yview)
class CheckboxList(FrameScroll): class CheckboxList(FrameScroll):
def __init__(self, master=None, clicked=None, **kw): def __init__(self, master, app, clicked=None, **kw):
super().__init__(master, **kw) super().__init__(master, app, **kw)
self.clicked = clicked self.clicked = clicked
self.frame.columnconfigure(0, weight=1) self.frame.columnconfigure(0, weight=1)