From 40b2c270e49684bae2692ffc2b9fc4e318b09ca6 Mon Sep 17 00:00:00 2001 From: Blake Harnden <32446120+bharnden@users.noreply.github.com> Date: Wed, 13 Nov 2019 12:11:37 -0800 Subject: [PATCH 1/7] fixed typo in canvas dialog variable, updated theming to make label frame have a relief groove border --- coretk/coretk/dialogs/canvassizeandscale.py | 8 ++++---- coretk/coretk/themes.py | 1 + 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/coretk/coretk/dialogs/canvassizeandscale.py b/coretk/coretk/dialogs/canvassizeandscale.py index 09132aef..5bbd2ec2 100644 --- a/coretk/coretk/dialogs/canvassizeandscale.py +++ b/coretk/coretk/dialogs/canvassizeandscale.py @@ -8,7 +8,7 @@ from coretk.dialogs.canvasbackground import ScaleOption from coretk.dialogs.dialog import Dialog DRAW_OBJECT_TAGS = ["edge", "node", "nodename", "linkinfo", "antenna"] -FRAME_BAD = 5 +FRAME_PAD = 5 PAD = (0, 0, 5, 0) PADX = 5 @@ -52,7 +52,7 @@ class SizeAndScaleDialog(Dialog): self.draw_buttons() 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.columnconfigure(0, weight=1) @@ -89,7 +89,7 @@ class SizeAndScaleDialog(Dialog): label.grid(row=0, column=4, sticky="w") 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.columnconfigure(0, weight=1) @@ -105,7 +105,7 @@ class SizeAndScaleDialog(Dialog): def draw_reference_point(self): 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.columnconfigure(0, weight=1) diff --git a/coretk/coretk/themes.py b/coretk/coretk/themes.py index b661b644..8eefa35e 100644 --- a/coretk/coretk/themes.py +++ b/coretk/coretk/themes.py @@ -86,6 +86,7 @@ def load(style): "padding": (2, 0), } }, + "TLabelframe": {"configure": {"relief": tk.GROOVE}}, "TNotebook.Tab": { "configure": {"padding": (6, 2, 6, 2)}, "map": {"background": [("selected", Colors.lighter)]}, From 08927b180a37488868050eaa7fa1cff1e06bbe6b Mon Sep 17 00:00:00 2001 From: Blake Harnden <32446120+bharnden@users.noreply.github.com> Date: Wed, 13 Nov 2019 12:42:16 -0800 Subject: [PATCH 2/7] changed service checklist style --- coretk/coretk/themes.py | 8 ++++++++ coretk/coretk/widgets.py | 10 +++++++++- 2 files changed, 17 insertions(+), 1 deletion(-) diff --git a/coretk/coretk/themes.py b/coretk/coretk/themes.py index 8eefa35e..8bbdb545 100644 --- a/coretk/coretk/themes.py +++ b/coretk/coretk/themes.py @@ -6,6 +6,7 @@ DARK = "black" class Styles: tooltip = "Tooltip.TLabel" tooltip_frame = "Tooltip.TFrame" + service_checkbutton = "Service.TCheckbutton" class Colors: @@ -20,6 +21,7 @@ class Colors: selectfg = "#ffffff" white = "white" black = "black" + listboxbg = "#f2f1f0" def load(style): @@ -106,6 +108,12 @@ def load(style): "configure": {"justify": tk.LEFT, "relief": tk.SOLID, "borderwidth": 0} }, Styles.tooltip_frame: {"configure": {}}, + Styles.service_checkbutton: { + "configure": { + "background": Colors.listboxbg, + "foreground": Colors.black, + } + }, }, ) diff --git a/coretk/coretk/widgets.py b/coretk/coretk/widgets.py index 87651701..d91f7f8a 100644 --- a/coretk/coretk/widgets.py +++ b/coretk/coretk/widgets.py @@ -4,6 +4,7 @@ from functools import partial from tkinter import ttk from core.api.grpc import core_pb2 +from coretk.themes import Styles INT_TYPES = { core_pb2.ConfigOptionType.UINT8, @@ -136,6 +137,7 @@ class ListboxScroll(ttk.LabelFrame): self.listbox = tk.Listbox( 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.scrollbar.config(command=self.listbox.yview) @@ -149,5 +151,11 @@ class CheckboxList(FrameScroll): def add(self, name, checked): var = tk.BooleanVar(value=checked) func = partial(self.clicked, name, var) - checkbox = ttk.Checkbutton(self.frame, text=name, variable=var, command=func) + checkbox = ttk.Checkbutton( + self.frame, + text=name, + variable=var, + command=func, + style=Styles.service_checkbutton, + ) checkbox.grid(sticky="w") From d63da73581174b93e979aecf5199ca5e6d8b4d67 Mon Sep 17 00:00:00 2001 From: Blake Harnden <32446120+bharnden@users.noreply.github.com> Date: Wed, 13 Nov 2019 13:19:18 -0800 Subject: [PATCH 3/7] updated framescroll to dynamically set bg based on current style --- coretk/coretk/app.py | 2 -- coretk/coretk/dialogs/customnodes.py | 2 +- coretk/coretk/dialogs/emaneconfig.py | 4 ++-- coretk/coretk/dialogs/nodeservice.py | 2 +- coretk/coretk/dialogs/sessionoptions.py | 2 +- coretk/coretk/themes.py | 6 +++--- coretk/coretk/widgets.py | 23 +++++++++-------------- 7 files changed, 17 insertions(+), 24 deletions(-) diff --git a/coretk/coretk/app.py b/coretk/coretk/app.py index bc3ac9dd..b66f1388 100644 --- a/coretk/coretk/app.py +++ b/coretk/coretk/app.py @@ -40,8 +40,6 @@ class Application(tk.Frame): self.style.theme_use(themes.DARK) func = partial(themes.update_menu, self.style) self.master.bind_class("Menu", "<>", func) - func = partial(themes.update_toplevel, self.style) - self.master.bind_class("Toplevel", "<>", func) def setup_app(self): self.master.title("CORE") diff --git a/coretk/coretk/dialogs/customnodes.py b/coretk/coretk/dialogs/customnodes.py index 154b7868..f427f08b 100644 --- a/coretk/coretk/dialogs/customnodes.py +++ b/coretk/coretk/dialogs/customnodes.py @@ -35,7 +35,7 @@ class ServicesSelectDialog(Dialog): self.groups.listbox.selection_set(0) 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") diff --git a/coretk/coretk/dialogs/emaneconfig.py b/coretk/coretk/dialogs/emaneconfig.py index 181e1264..d64e9089 100644 --- a/coretk/coretk/dialogs/emaneconfig.py +++ b/coretk/coretk/dialogs/emaneconfig.py @@ -93,7 +93,7 @@ class EmaneConfiguration(Dialog): self.emane_dialog.top.columnconfigure(0, weight=1) self.emane_dialog.top.rowconfigure(0, weight=1) 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.grid(sticky="nsew") @@ -167,7 +167,7 @@ class EmaneConfiguration(Dialog): self.model_options = response.config 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.draw_config() diff --git a/coretk/coretk/dialogs/nodeservice.py b/coretk/coretk/dialogs/nodeservice.py index ce5a4715..9ced9205 100644 --- a/coretk/coretk/dialogs/nodeservice.py +++ b/coretk/coretk/dialogs/nodeservice.py @@ -38,7 +38,7 @@ class NodeService(Dialog): self.groups.listbox.selection_set(0) 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") diff --git a/coretk/coretk/dialogs/sessionoptions.py b/coretk/coretk/dialogs/sessionoptions.py index 8cd7ad68..b2666015 100644 --- a/coretk/coretk/dialogs/sessionoptions.py +++ b/coretk/coretk/dialogs/sessionoptions.py @@ -22,7 +22,7 @@ class SessionOptionsDialog(Dialog): response = self.app.core.client.get_session_options(session_id) 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.grid(sticky="nsew") diff --git a/coretk/coretk/themes.py b/coretk/coretk/themes.py index 8bbdb545..f6dced19 100644 --- a/coretk/coretk/themes.py +++ b/coretk/coretk/themes.py @@ -1,3 +1,4 @@ +import logging import tkinter as tk DARK = "black" @@ -118,9 +119,8 @@ def load(style): ) -def update_toplevel(style, event): - if not isinstance(event.widget, tk.Toplevel): - return +def update_bg(style, event): + logging.info("updating background: %s", event.widget) bg = style.lookup(".", "background") event.widget.config(background=bg) diff --git a/coretk/coretk/widgets.py b/coretk/coretk/widgets.py index d91f7f8a..e825fdb4 100644 --- a/coretk/coretk/widgets.py +++ b/coretk/coretk/widgets.py @@ -4,7 +4,6 @@ from functools import partial from tkinter import ttk from core.api.grpc import core_pb2 -from coretk.themes import Styles INT_TYPES = { core_pb2.ConfigOptionType.UINT8, @@ -19,11 +18,13 @@ INT_TYPES = { 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) + self.app = app self.rowconfigure(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.columnconfigure(0, weight=1) self.canvas.rowconfigure(0, weight=1) @@ -55,8 +56,8 @@ class FrameScroll(ttk.LabelFrame): class ConfigFrame(FrameScroll): - def __init__(self, master=None, config=None, **kw): - super().__init__(master, ttk.Notebook, **kw) + def __init__(self, master, app, config, **kw): + super().__init__(master, app, ttk.Notebook, **kw) self.config = config self.values = {} @@ -143,19 +144,13 @@ class ListboxScroll(ttk.LabelFrame): class CheckboxList(FrameScroll): - def __init__(self, master=None, clicked=None, **kw): - super().__init__(master, **kw) + def __init__(self, master, app, clicked=None, **kw): + super().__init__(master, app, **kw) self.clicked = clicked self.frame.columnconfigure(0, weight=1) def add(self, name, checked): var = tk.BooleanVar(value=checked) func = partial(self.clicked, name, var) - checkbox = ttk.Checkbutton( - self.frame, - text=name, - variable=var, - command=func, - style=Styles.service_checkbutton, - ) + checkbox = ttk.Checkbutton(self.frame, text=name, variable=var, command=func) checkbox.grid(sticky="w") From 145abca8632dcf1f858b8182683a44567b5dedb4 Mon Sep 17 00:00:00 2001 From: bharnden <32446120+bharnden@users.noreply.github.com> Date: Wed, 13 Nov 2019 22:49:32 -0800 Subject: [PATCH 4/7] added theme configuration to preferences dialog --- coretk/coretk/app.py | 4 ++-- coretk/coretk/appconfig.py | 3 +++ coretk/coretk/dialogs/preferences.py | 36 +++++++++++++++++++++------- 3 files changed, 32 insertions(+), 11 deletions(-) diff --git a/coretk/coretk/app.py b/coretk/coretk/app.py index b66f1388..5481ad19 100644 --- a/coretk/coretk/app.py +++ b/coretk/coretk/app.py @@ -15,6 +15,7 @@ from coretk.toolbar import Toolbar class Application(tk.Frame): def __init__(self, master=None): super().__init__(master) + self.config = appconfig.read() self.style = ttk.Style() self.setup_theme() self.menubar = None @@ -29,7 +30,6 @@ class Application(tk.Frame): 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.core = CoreClient(self) self.setup_app() self.draw() @@ -37,7 +37,7 @@ class Application(tk.Frame): def setup_theme(self): 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) self.master.bind_class("Menu", "<>", func) diff --git a/coretk/coretk/appconfig.py b/coretk/coretk/appconfig.py index 67f97181..e8f5db6e 100644 --- a/coretk/coretk/appconfig.py +++ b/coretk/coretk/appconfig.py @@ -6,6 +6,8 @@ from pathlib import Path import yaml # gui home paths +from coretk import themes + HOME_PATH = Path.home().joinpath(".coretk") BACKGROUNDS_PATH = HOME_PATH.joinpath("backgrounds") CUSTOM_EMANE_PATH = HOME_PATH.joinpath("custom_emane") @@ -68,6 +70,7 @@ def check_directory(): editor = EDITORS[1] config = { "preferences": { + "theme": themes.DARK, "editor": editor, "terminal": terminal, "gui3d": "/usr/local/bin/std3d.sh", diff --git a/coretk/coretk/dialogs/preferences.py b/coretk/coretk/dialogs/preferences.py index 0c426d3c..148cb6bb 100644 --- a/coretk/coretk/dialogs/preferences.py +++ b/coretk/coretk/dialogs/preferences.py @@ -1,3 +1,4 @@ +import logging import tkinter as tk from tkinter import ttk @@ -10,41 +11,52 @@ class PreferencesDialog(Dialog): super().__init__(master, app, "Preferences", modal=True) preferences = self.app.config["preferences"] self.editor = tk.StringVar(value=preferences["editor"]) + self.theme = tk.StringVar(value=preferences["theme"]) self.terminal = tk.StringVar(value=preferences["terminal"]) self.gui3d = tk.StringVar(value=preferences["gui3d"]) self.draw() def draw(self): self.top.columnconfigure(0, weight=1) - self.draw_programs() + self.draw_preferences() self.draw_buttons() - def draw_programs(self): - frame = ttk.LabelFrame(self.top, text="Programs") + def draw_preferences(self): + frame = ttk.LabelFrame(self.top, text="Preferences") frame.grid(sticky="ew", pady=2) 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") + 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("<>", self.theme_change) + + label = ttk.Label(frame, text="Editor") + label.grid(row=1, column=0, pady=2, padx=2, sticky="w") combobox = ttk.Combobox( frame, textvariable=self.editor, values=appconfig.EDITORS, state="readonly" ) - combobox.grid(row=0, column=1, sticky="ew") + combobox.grid(row=1, column=1, sticky="ew") 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( frame, textvariable=self.terminal, values=appconfig.TERMINALS, 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.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.grid(row=2, column=1, sticky="ew") + entry.grid(row=3, column=1, sticky="ew") def draw_buttons(self): frame = ttk.Frame(self.top) @@ -58,10 +70,16 @@ class PreferencesDialog(Dialog): button = ttk.Button(frame, text="Cancel", command=self.destroy) 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): preferences = self.app.config["preferences"] preferences["terminal"] = self.terminal.get() preferences["editor"] = self.editor.get() preferences["gui3d"] = self.gui3d.get() + preferences["theme"] = self.theme.get() self.app.save_config() self.destroy() From 31d87810086f1482715cea1d619c6499d97b130e Mon Sep 17 00:00:00 2001 From: bharnden <32446120+bharnden@users.noreply.github.com> Date: Wed, 13 Nov 2019 23:03:12 -0800 Subject: [PATCH 5/7] fixed emane icon background to alpha, updated wlan icon to have a white cloud instead of alpha --- coretk/coretk/icons/emane.gif | Bin 1111 -> 337 bytes coretk/coretk/icons/wlan.gif | Bin 146 -> 173 bytes 2 files changed, 0 insertions(+), 0 deletions(-) diff --git a/coretk/coretk/icons/emane.gif b/coretk/coretk/icons/emane.gif index 8a3d3850d4c01d35e3322c97b8cd0ab00251ecd8..0531a932532f4573b3f581364a01a059a7a54e26 100644 GIT binary patch literal 337 zcmZ?wbhEHbRA5kGc+A591jgD7#-R)|uL6w9SoqqGI`S+J)Z}3~{55m3>-wv~T?H#< zW@b2-6z*ZzwOP^2gZrP5;o(z43Q~UM#g#@z4%MQzE@c_^bw;Lk?IH|)m32vxaa}CA z3fvO{o3pwW8foTD(O4XmndY#7V{QjS_&47}7hO2# Z!QgRoI`a`OK~`a{m=hZowsSC80|0bwhHwA? literal 1111 zcmW+!Uue)(7(D}p89_BM)XmtxBE44IKCNjFQrT)0L!wKI3bD;^%+_DXryeeCA)}Qv zqWBE4bQrr}ZY?5waS`Q$uZ-BG@MV#(psWa4Qc771P(TF@bg;Tq+#*nc3B1B2 zK!Qk62`0fMP$DFXM3ra~T_Pnxl1NfXCdnmHG9-&+m28q-GNnL@NKq*!#idXPp$JuI zLKjv#sxO zw1^hfVp?1al~9UOm8NuMWkKb*7}Q_}uN<)e3t~Ynm<6{$i?Apb)uLH+i?jqwVo5ET zCAUP&uq>9w?ZR~VpO9U-B`I_g)I(sn8T|uJivo^P!Hz8JGnl_iy~ z3aqLSz#t6DU<}ScMlcGaG8&^Zk_k-0q)f)-Ok@VLFe|e$J2P3pA}q>cEY7k_Ru!#E zyRy8RdxdK$1^z}{u4nEZX z&53(&(@U*+B98YSUj5?1%Z=$|%fORwc6Tg3piPIL-c~!jIQ{Ctxs&TQ*DYRn`If;W zpa1>ssk!l6f3I8h!yTs{o9sUN^RM&kj?3&_KOHFbkM?(+9%=8n{z%#K;M|Fg7gt~V z_J{pnZhvj`w@=o8FnDHP`_7B4y*Cbh-@5Cav4)wCXW!~s7+)Ie%@;jEB@otNY*qmFfdba%1_PAOJ`90$->CRz{sEjQUOxS zz!cuozw-23{>32+u5qs4D3yPjAx>eEpJZvqkAmdpb(+5?eJb>ho%FhP{o<=WA`fyl xetyz3Q~L84X{Px{Rg%)5F0}|bV|49q%MP!#xfR=XUU=m{gSY?m^L8c%YXB@FJ0t)A From 4d2b84b107cff0fce3e943ca8dfd8d9bb36b420c Mon Sep 17 00:00:00 2001 From: bharnden <32446120+bharnden@users.noreply.github.com> Date: Thu, 14 Nov 2019 11:26:20 -0800 Subject: [PATCH 6/7] updated wallpaper dialog to now save and redisplay current wallpaper, updated app to display in center of screen on launch --- coretk/coretk/app.py | 29 +++-- coretk/coretk/dialogs/canvasbackground.py | 132 ++++++++++---------- coretk/coretk/dialogs/canvassizeandscale.py | 66 +++++----- coretk/coretk/graph.py | 14 ++- coretk/coretk/menuaction.py | 1 - 5 files changed, 124 insertions(+), 118 deletions(-) diff --git a/coretk/coretk/app.py b/coretk/coretk/app.py index 5481ad19..11fad378 100644 --- a/coretk/coretk/app.py +++ b/coretk/coretk/app.py @@ -15,21 +15,19 @@ from coretk.toolbar import Toolbar class Application(tk.Frame): def __init__(self, master=None): super().__init__(master) - self.config = appconfig.read() - self.style = ttk.Style() - self.setup_theme() + # widgets self.menubar = None self.toolbar = None self.canvas = None self.statusbar = None - self.is_open_xml = False - self.size_and_scale = None + + # variables 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) + + # setup + self.config = appconfig.read() + self.style = ttk.Style() + self.setup_theme() self.core = CoreClient(self) self.setup_app() self.draw() @@ -43,12 +41,21 @@ class Application(tk.Frame): def setup_app(self): self.master.title("CORE") - self.master.geometry("1000x800") + self.center() self.master.protocol("WM_DELETE_WINDOW", self.on_closing) image = Images.get(ImageEnum.CORE, 16) self.master.tk.call("wm", "iconphoto", self.master._w, image) 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): self.master.option_add("*tearOff", tk.FALSE) self.menubar = Menubar(self.master, self) diff --git a/coretk/coretk/dialogs/canvasbackground.py b/coretk/coretk/dialogs/canvasbackground.py index 7b1dd186..80b1ae5f 100644 --- a/coretk/coretk/dialogs/canvasbackground.py +++ b/coretk/coretk/dialogs/canvasbackground.py @@ -10,6 +10,7 @@ from PIL import Image, ImageTk from coretk.appconfig import BACKGROUNDS_PATH from coretk.dialogs.dialog import Dialog +from coretk.images import Images PADX = 5 @@ -31,11 +32,11 @@ class CanvasBackgroundDialog(Dialog): """ super().__init__(master, app, "Canvas Background", modal=True) self.canvas = self.app.canvas - self.radiovar = tk.IntVar(value=self.app.radiovar.get()) - self.show_grid_var = tk.IntVar(value=self.app.show_grid_var.get()) - self.adjust_to_dim_var = tk.IntVar(value=self.app.adjust_to_dim_var.get()) + self.scale_option = tk.IntVar(value=self.canvas.scale_option.get()) + self.show_grid = tk.IntVar(value=self.canvas.show_grid.get()) + self.adjust_to_dim = tk.IntVar(value=self.canvas.adjust_to_dim.get()) + self.filename = tk.StringVar(value=self.canvas.wallpaper_file) self.image_label = None - self.file_name = tk.StringVar() self.options = [] self.draw() @@ -57,6 +58,8 @@ class CanvasBackgroundDialog(Dialog): def draw_image_label(self): label = ttk.Label(self.top, text="Image filename: ") label.grid(row=1, column=0, sticky="ew") + if self.filename.get(): + self.draw_preview() def draw_image_selection(self): frame = ttk.Frame(self.top) @@ -65,7 +68,7 @@ class CanvasBackgroundDialog(Dialog): frame.columnconfigure(2, weight=1) 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.grid(row=0, column=0, sticky="ew", padx=PADX) @@ -84,41 +87,45 @@ class CanvasBackgroundDialog(Dialog): frame.grid(row=3, column=0, sticky="ew") 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") self.options.append(button) 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") 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") 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") self.options.append(button) def draw_additional_options(self): 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 = ttk.Checkbutton( self.top, text="Adjust canvas size to image dimensions", - variable=self.adjust_to_dim_var, + variable=self.adjust_to_dim, command=self.click_adjust_canvas, ) checkbutton.grid(row=5, column=0, sticky="ew", padx=PADX) - self.show_grid_var.set(1) - self.adjust_to_dim_var.set(0) + self.show_grid.set(1) + self.adjust_to_dim.set(0) def draw_buttons(self): frame = ttk.Frame(self.top) @@ -142,13 +149,13 @@ class CanvasBackgroundDialog(Dialog): ), ) if filename: - self.file_name.set(filename) - width, height = 250, 135 - img = Image.open(filename) - img = img.resize((width, height), Image.ANTIALIAS) - tk_img = ImageTk.PhotoImage(img) - self.image_label.config(image=tk_img, width=width) - self.image_label.image = tk_img + self.filename.set(filename) + self.draw_preview() + + def draw_preview(self): + image = Images.create(self.filename.get(), 250, 135) + self.image_label.config(image=image) + self.image_label.image = image def click_clear(self): """ @@ -157,19 +164,20 @@ class CanvasBackgroundDialog(Dialog): :return: nothing """ # delete entry - self.file_name.set("") + self.filename.set("") # delete display image self.image_label.config(image="", width=32) + self.image_label.image = None def click_adjust_canvas(self): # deselect all radio buttons and grey them out - if self.adjust_to_dim_var.get() == 1: - self.radiovar.set(0) + if self.adjust_to_dim.get() == 1: + self.scale_option.set(0) for option in self.options: option.config(state=tk.DISABLED) # turn back the radio button to active state so that user can choose again - elif self.adjust_to_dim_var.get() == 0: - self.radiovar.set(1) + elif self.adjust_to_dim.get() == 0: + self.scale_option.set(1) for option in self.options: option.config(state=tk.NORMAL) else: @@ -192,9 +200,8 @@ class CanvasBackgroundDialog(Dialog): :return: nothing """ - canvas = self.app.canvas - grid = canvas.find_withtag("rectangle")[0] - x0, y0, x1, y1 = canvas.coords(grid) + grid = self.canvas.find_withtag("rectangle")[0] + x0, y0, x1, y1 = self.canvas.coords(grid) canvas_w = abs(x0 - x1) canvas_h = abs(y0 - y1) return canvas_w, canvas_h @@ -224,15 +231,12 @@ class CanvasBackgroundDialog(Dialog): cropped_tk = ImageTk.PhotoImage(cropped) # place left corner of image to the left corner of the canvas - self.app.croppedwallpaper = cropped_tk - + self.canvas.wallpaper_drawn = 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 + self.canvas.wallpaper_id = wid def center(self, img): """ @@ -261,13 +265,13 @@ class CanvasBackgroundDialog(Dialog): 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 + self.canvas.wallpaper_id = wid + self.canvas.wallpaper_drawn = cropped_tk def scaled(self, img): """ @@ -279,15 +283,12 @@ class CanvasBackgroundDialog(Dialog): 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 + self.canvas.wallpaper_id = wid + self.canvas.wallpaper_drawn = image_tk def tiled(self, img): return @@ -310,20 +311,15 @@ class CanvasBackgroundDialog(Dialog): 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 + self.canvas.wallpaper_id = wid + self.canvas.wallpaper_drawn = image_tk - 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: + def draw_grid(self): + self.canvas.adjust_to_dim.set(self.adjust_to_dim.get()) + if self.show_grid.get() == 0: for i in self.canvas.find_withtag("gridline"): self.canvas.itemconfig(i, state=tk.HIDDEN) - elif self.show_grid_var.get() == 1: + elif self.show_grid.get() == 1: for i in self.canvas.find_withtag("gridline"): self.canvas.itemconfig(i, state=tk.NORMAL) self.canvas.lift(i) @@ -331,33 +327,36 @@ class CanvasBackgroundDialog(Dialog): 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()) + 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()) def click_apply(self): - filename = self.file_name.get() + filename = self.filename.get() if not filename: self.delete_canvas_components(["wallpaper"]) self.destroy() - self.app.current_wallpaper = None + self.canvas.wallpaper = None + self.canvas.wallpaper_file = None self.save_wallpaper_options() return try: img = Image.open(filename) - self.app.current_wallpaper = img + self.canvas.wallpaper = img + self.canvas.wallpaper_file = filename except FileNotFoundError: logging.error("invalid background: %s", filename) - if self.app.wallpaper_id: - self.canvas.delete(self.app.wallpaper_id) + if self.canvas.wallpaper_id: + self.canvas.delete(self.canvas.wallpaper_id) + self.canvas.wallpaper_id = None self.destroy() return - 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()) + self.canvas.adjust_to_dim.set(self.adjust_to_dim.get()) + if self.adjust_to_dim.get() == 0: + self.canvas.scale_option.set(self.scale_option.get()) + option = ScaleOption(self.scale_option.get()) if option == ScaleOption.UPPER_LEFT: self.upper_left(img) elif option == ScaleOption.CENTERED: @@ -365,10 +364,9 @@ class CanvasBackgroundDialog(Dialog): elif option == ScaleOption.SCALED: self.scaled(img) elif option == ScaleOption.TILED: - print("not implemented yet") - - elif self.adjust_to_dim_var.get() == 1: + logging.warning("tiled background not implemented yet") + elif self.adjust_to_dim.get() == 1: self.canvas_to_image_dimension(img) - self.show_grid() + self.draw_grid() self.destroy() diff --git a/coretk/coretk/dialogs/canvassizeandscale.py b/coretk/coretk/dialogs/canvassizeandscale.py index 5bbd2ec2..598d8d37 100644 --- a/coretk/coretk/dialogs/canvassizeandscale.py +++ b/coretk/coretk/dialogs/canvassizeandscale.py @@ -1,6 +1,7 @@ """ size and scale """ +import logging import tkinter as tk from tkinter import font, ttk @@ -9,7 +10,6 @@ from coretk.dialogs.dialog import Dialog DRAW_OBJECT_TAGS = ["edge", "node", "nodename", "linkinfo", "antenna"] FRAME_PAD = 5 -PAD = (0, 0, 5, 0) PADX = 5 @@ -21,13 +21,13 @@ class SizeAndScaleDialog(Dialog): :param app: main application """ 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") # get current canvas dimensions - canvas = self.app.canvas - plot = canvas.find_withtag("rectangle") - x0, y0, x1, y1 = canvas.bbox(plot[0]) + plot = self.canvas.find_withtag("rectangle") + x0, y0, x1, y1 = self.canvas.bbox(plot[0]) width = abs(x0 - x1) - 2 height = abs(y0 - y1) - 2 self.pixel_width = tk.IntVar(value=width) @@ -122,14 +122,12 @@ class SizeAndScaleDialog(Dialog): label = ttk.Label(frame, text="X") label.grid(row=0, column=0, sticky="w", padx=PADX) - x_var = tk.StringVar(value=0) - entry = ttk.Entry(frame, textvariable=x_var) + entry = ttk.Entry(frame, textvariable=self.x) entry.grid(row=0, column=1, sticky="ew", padx=PADX) label = ttk.Label(frame, text="Y") label.grid(row=0, column=2, sticky="w", padx=PADX) - y_var = tk.StringVar(value=0) - entry = ttk.Entry(frame, textvariable=y_var) + entry = ttk.Entry(frame, textvariable=self.y) entry.grid(row=0, column=3, sticky="ew", padx=PADX) label = ttk.Label(label_frame, text="Translates To") @@ -181,40 +179,40 @@ class SizeAndScaleDialog(Dialog): :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)) + self.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) + for i in self.canvas.find_withtag("gridline"): + self.canvas.delete(i) + for i in self.canvas.find_withtag("rectangle"): + self.canvas.delete(i) - canvas.draw_grid(width=width, height=height) + self.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) + for i in self.canvas.find_withtag(tag): + self.canvas.lift(i) def click_apply(self): meter_per_pixel = float(self.scale.get()) / 100 - self.app.canvas.meters_per_pixel = meter_per_pixel + self.canvas.meters_per_pixel = meter_per_pixel self.redraw_grid() - # if there is a current wallpaper showing, redraw it based on current wallpaper options + # if there is a current wallpaper showing, redraw it based on current + # wallpaper options wallpaper_tool = self.app.set_wallpaper - current_wallpaper = self.app.current_wallpaper - 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 = self.canvas.wallpaper + if wallpaper: + if self.canvas.adjust_to_dim.get() == 0: + scale_option = ScaleOption(self.canvas.scale_option.get()) + if scale_option == ScaleOption.UPPER_LEFT: + wallpaper_tool.upper_left(wallpaper) + elif scale_option == ScaleOption.CENTERED: + wallpaper_tool.center(wallpaper) + elif scale_option == ScaleOption.SCALED: + wallpaper_tool.scaled(wallpaper) + elif scale_option == ScaleOption.TILED: + logging.warning("tiled background not implemented") + elif self.canvas.adjust_to_dim.get() == 1: + wallpaper_tool.canvas_to_image_dimension(wallpaper) wallpaper_tool.show_grid() self.destroy() diff --git a/coretk/coretk/graph.py b/coretk/coretk/graph.py index 5cdd2eec..1bec481b 100644 --- a/coretk/coretk/graph.py +++ b/coretk/coretk/graph.py @@ -43,11 +43,8 @@ class CanvasGraph(tk.Canvas): self.drawing_edge = None self.grid = None self.meters_per_pixel = 1.5 - self.canvas_management = CanvasComponentManagement(self, core) - self.canvas_action = CanvasAction(master, self) - self.setup_menus() self.setup_bindings() self.draw_grid() @@ -57,6 +54,15 @@ class CanvasGraph(tk.Canvas): self.wireless_draw = WirelessConnection(self, core) 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.IntVar(value=1) + self.adjust_to_dim = tk.IntVar(value=0) + def setup_menus(self): self.node_context = tk.Menu(self.master) self.node_context.add_command( @@ -95,8 +101,6 @@ class CanvasGraph(tk.Canvas): self.drawing_edge = None self.draw_existing_component(session) - # self.grpc_manager.wlanconfig_management.load_wlan_configurations(self.core_grpc) - def setup_bindings(self): """ Bind any mouse events or hot keys to the matching action diff --git a/coretk/coretk/menuaction.py b/coretk/coretk/menuaction.py index 98b3d254..b47c6ef2 100644 --- a/coretk/coretk/menuaction.py +++ b/coretk/coretk/menuaction.py @@ -73,7 +73,6 @@ class MenuAction: def file_open_xml(self, event=None): logging.info("menuaction.py file_open_xml()") - self.app.is_open_xml = True file_path = filedialog.askopenfilename( initialdir=str(XML_PATH), title="Open", From aec1126a14cca6e1eaaf8394f498cadee13e142d Mon Sep 17 00:00:00 2001 From: bharnden <32446120+bharnden@users.noreply.github.com> Date: Thu, 14 Nov 2019 12:58:27 -0800 Subject: [PATCH 7/7] updated canvas dialogs to make use of common canvas redraw/wallpaper logic --- coretk/coretk/app.py | 3 - coretk/coretk/dialogs/canvasbackground.py | 196 ++------------------ coretk/coretk/dialogs/canvassizeandscale.py | 47 +---- coretk/coretk/graph.py | 154 ++++++++++++++- 4 files changed, 159 insertions(+), 241 deletions(-) diff --git a/coretk/coretk/app.py b/coretk/coretk/app.py index 11fad378..185e5968 100644 --- a/coretk/coretk/app.py +++ b/coretk/coretk/app.py @@ -21,9 +21,6 @@ class Application(tk.Frame): self.canvas = None self.statusbar = None - # variables - self.set_wallpaper = None - # setup self.config = appconfig.read() self.style = ttk.Style() diff --git a/coretk/coretk/dialogs/canvasbackground.py b/coretk/coretk/dialogs/canvasbackground.py index 80b1ae5f..8fb92c8b 100644 --- a/coretk/coretk/dialogs/canvasbackground.py +++ b/coretk/coretk/dialogs/canvasbackground.py @@ -1,12 +1,11 @@ """ set wallpaper """ -import enum import logging import tkinter as tk from tkinter import filedialog, ttk -from PIL import Image, ImageTk +from PIL import Image from coretk.appconfig import BACKGROUNDS_PATH from coretk.dialogs.dialog import Dialog @@ -15,14 +14,6 @@ from coretk.images import Images PADX = 5 -class ScaleOption(enum.Enum): - NONE = 0 - UPPER_LEFT = 1 - CENTERED = 2 - SCALED = 3 - TILED = 4 - - class CanvasBackgroundDialog(Dialog): def __init__(self, master, app): """ @@ -33,8 +24,8 @@ class CanvasBackgroundDialog(Dialog): super().__init__(master, app, "Canvas Background", modal=True) self.canvas = self.app.canvas self.scale_option = tk.IntVar(value=self.canvas.scale_option.get()) - self.show_grid = tk.IntVar(value=self.canvas.show_grid.get()) - self.adjust_to_dim = tk.IntVar(value=self.canvas.adjust_to_dim.get()) + self.show_grid = tk.BooleanVar(value=self.canvas.show_grid.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.options = [] @@ -124,9 +115,6 @@ class CanvasBackgroundDialog(Dialog): ) checkbutton.grid(row=5, column=0, sticky="ew", padx=PADX) - self.show_grid.set(1) - self.adjust_to_dim.set(0) - def draw_buttons(self): frame = ttk.Frame(self.top) frame.grid(row=6, column=0, pady=5, sticky="ew") @@ -171,202 +159,40 @@ class CanvasBackgroundDialog(Dialog): def click_adjust_canvas(self): # deselect all radio buttons and grey them out - if self.adjust_to_dim.get() == 1: + if self.adjust_to_dim.get(): self.scale_option.set(0) for option in self.options: option.config(state=tk.DISABLED) # turn back the radio button to active state so that user can choose again - elif self.adjust_to_dim.get() == 0: + else: self.scale_option.set(1) for option in self.options: 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 - """ - grid = self.canvas.find_withtag("rectangle")[0] - x0, y0, x1, y1 = self.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.canvas.wallpaper_drawn = cropped_tk - self.delete_canvas_components(["wallpaper"]) - wid = self.canvas.create_image( - (cropx / 2, cropy / 2), image=cropped_tk, tags="wallpaper" - ) - self.canvas.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.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.canvas.wallpaper_id = wid - self.canvas.wallpaper_drawn = cropped_tk - - 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.delete_canvas_components(["wallpaper"]) - wid = self.canvas.create_image( - (canvas_w / 2, canvas_h / 2), image=image_tk, tags="wallpaper" - ) - self.canvas.wallpaper_id = wid - self.canvas.wallpaper_drawn = image_tk - - 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.canvas.wallpaper_id = wid - self.canvas.wallpaper_drawn = image_tk - - def draw_grid(self): - self.canvas.adjust_to_dim.set(self.adjust_to_dim.get()) - if self.show_grid.get() == 0: - for i in self.canvas.find_withtag("gridline"): - self.canvas.itemconfig(i, state=tk.HIDDEN) - elif self.show_grid.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): + def click_apply(self): 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() - def click_apply(self): filename = self.filename.get() if not filename: - self.delete_canvas_components(["wallpaper"]) - self.destroy() + self.canvas.delete(self.canvas.wallpaper_id) self.canvas.wallpaper = None self.canvas.wallpaper_file = None - self.save_wallpaper_options() + self.destroy() return try: img = Image.open(filename) self.canvas.wallpaper = img self.canvas.wallpaper_file = filename + self.canvas.redraw() except FileNotFoundError: logging.error("invalid background: %s", filename) if self.canvas.wallpaper_id: self.canvas.delete(self.canvas.wallpaper_id) self.canvas.wallpaper_id = None - self.destroy() - return + self.canvas.wallpaper_file = None - self.canvas.adjust_to_dim.set(self.adjust_to_dim.get()) - if self.adjust_to_dim.get() == 0: - self.canvas.scale_option.set(self.scale_option.get()) - option = ScaleOption(self.scale_option.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: - logging.warning("tiled background not implemented yet") - elif self.adjust_to_dim.get() == 1: - self.canvas_to_image_dimension(img) - - self.draw_grid() self.destroy() diff --git a/coretk/coretk/dialogs/canvassizeandscale.py b/coretk/coretk/dialogs/canvassizeandscale.py index 598d8d37..3a72389d 100644 --- a/coretk/coretk/dialogs/canvassizeandscale.py +++ b/coretk/coretk/dialogs/canvassizeandscale.py @@ -1,14 +1,11 @@ """ size and scale """ -import logging import tkinter as tk from tkinter import font, ttk -from coretk.dialogs.canvasbackground import ScaleOption from coretk.dialogs.dialog import Dialog -DRAW_OBJECT_TAGS = ["edge", "node", "nodename", "linkinfo", "antenna"] FRAME_PAD = 5 PADX = 5 @@ -172,47 +169,11 @@ class SizeAndScaleDialog(Dialog): button = ttk.Button(frame, text="Cancel", command=self.destroy) 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() - self.canvas.config(scrollregion=(0, 0, width + 200, height + 200)) - - # delete old plot and redraw - for i in self.canvas.find_withtag("gridline"): - self.canvas.delete(i) - for i in self.canvas.find_withtag("rectangle"): - self.canvas.delete(i) - - self.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 self.canvas.find_withtag(tag): - self.canvas.lift(i) - def click_apply(self): meter_per_pixel = float(self.scale.get()) / 100 + width, height = self.pixel_width.get(), self.pixel_height.get() self.canvas.meters_per_pixel = meter_per_pixel - self.redraw_grid() - # if there is a current wallpaper showing, redraw it based on current - # wallpaper options - wallpaper_tool = self.app.set_wallpaper - wallpaper = self.canvas.wallpaper - if wallpaper: - if self.canvas.adjust_to_dim.get() == 0: - scale_option = ScaleOption(self.canvas.scale_option.get()) - if scale_option == ScaleOption.UPPER_LEFT: - wallpaper_tool.upper_left(wallpaper) - elif scale_option == ScaleOption.CENTERED: - wallpaper_tool.center(wallpaper) - elif scale_option == ScaleOption.SCALED: - wallpaper_tool.scaled(wallpaper) - elif scale_option == ScaleOption.TILED: - logging.warning("tiled background not implemented") - elif self.canvas.adjust_to_dim.get() == 1: - wallpaper_tool.canvas_to_image_dimension(wallpaper) - wallpaper_tool.show_grid() + self.canvas.redraw_grid(width, height) + if self.canvas.wallpaper: + self.canvas.redraw() self.destroy() diff --git a/coretk/coretk/graph.py b/coretk/coretk/graph.py index 1bec481b..e5bab65b 100644 --- a/coretk/coretk/graph.py +++ b/coretk/coretk/graph.py @@ -2,6 +2,8 @@ import enum import logging import tkinter as tk +from PIL import ImageTk + from core.api.grpc import core_pb2 from coretk.canvasaction import CanvasAction from coretk.canvastooltip import CanvasTooltip @@ -21,6 +23,14 @@ class GraphMode(enum.Enum): OTHER = 4 +class ScaleOption(enum.Enum): + NONE = 0 + UPPER_LEFT = 1 + CENTERED = 2 + SCALED = 3 + TILED = 4 + + CORE_NODES = ["router"] CORE_WIRED_NETWORK_NODES = [] CORE_WIRELESS_NODE = ["wlan"] @@ -60,8 +70,8 @@ class CanvasGraph(tk.Canvas): self.wallpaper_drawn = None self.wallpaper_file = "" self.scale_option = tk.IntVar(value=1) - self.show_grid = tk.IntVar(value=1) - self.adjust_to_dim = tk.IntVar(value=0) + self.show_grid = tk.BooleanVar(value=True) + self.adjust_to_dim = tk.BooleanVar(value=False) def setup_menus(self): self.node_context = tk.Menu(self.master) @@ -132,11 +142,12 @@ class CanvasGraph(tk.Canvas): width=1, tags="rectangle", ) - self.tag_lower(self.grid) for i in range(0, width, 27): self.create_line(i, 0, i, height, dash=(2, 4), tags="gridline") for i in range(0, height, 27): 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): """ @@ -228,9 +239,8 @@ class CanvasGraph(tk.Canvas): if2 ) - # lift the nodes so they on top of the links - for i in self.find_withtag("node"): - self.lift(i) + # raise the nodes so they on top of the links + self.tag_raise("node") def canvas_xy(self, event): """ @@ -426,6 +436,132 @@ class CanvasGraph(tk.Canvas): self.core.add_graph_node(self.core.session_id, node.id, x, y, node_name) 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: """ @@ -469,8 +605,6 @@ class CanvasEdge: self.link_info = None self.throughput = None self.wired = is_wired - # TODO resolve this - # self.canvas.tag_lower(self.id) def complete(self, dst, x, y): self.dst = dst @@ -478,8 +612,8 @@ class CanvasEdge: x1, y1, _, _ = self.canvas.coords(self.id) self.canvas.coords(self.id, x1, y1, x, y) self.canvas.helper.draw_wireless_case(self.src, self.dst, self) - self.canvas.lift(self.src) - self.canvas.lift(self.dst) + self.canvas.tag_raise(self.src) + self.canvas.tag_raise(self.dst) def delete(self): self.canvas.delete(self.id)