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] 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)