From b88abd0f74281b846cdedbd2c35a1a5c54d2e22b Mon Sep 17 00:00:00 2001 From: bharnden <32446120+bharnden@users.noreply.github.com> Date: Sun, 10 Nov 2019 17:26:38 -0800 Subject: [PATCH] added initial code that can help support canvas tooltips for observer widgets --- coretk/coretk/canvastooltip.py | 134 +++++++++++++++++++++++++++++++++ coretk/coretk/graph.py | 2 + 2 files changed, 136 insertions(+) create mode 100644 coretk/coretk/canvastooltip.py diff --git a/coretk/coretk/canvastooltip.py b/coretk/coretk/canvastooltip.py new file mode 100644 index 00000000..42270809 --- /dev/null +++ b/coretk/coretk/canvastooltip.py @@ -0,0 +1,134 @@ +import tkinter as tk +from tkinter import ttk + + +class CanvasTooltip: + """ + It creates a tooltip for a given canvas tag or id as the mouse is + above it. + + This class has been derived from the original Tooltip class updated + and posted back to StackOverflow at the following link: + + https://stackoverflow.com/questions/3221956/ + what-is-the-simplest-way-to-make-tooltips-in-tkinter/ + 41079350#41079350 + + Alberto Vassena on 2016.12.10. + """ + + def __init__( + self, + canvas, + tag_or_id, + *, + bg="#FFFFEA", + pad=(5, 3, 5, 3), + text="canvas info", + waittime=400, + wraplength=250 + ): + # in miliseconds, originally 500 + self.waittime = waittime + # in pixels, originally 180 + self.wraplength = wraplength + self.canvas = canvas + self.text = text + self.canvas.tag_bind(tag_or_id, "", self.on_enter) + self.canvas.tag_bind(tag_or_id, "", self.on_leave) + self.canvas.tag_bind(tag_or_id, "", self.on_leave) + self.bg = bg + self.pad = pad + self.id = None + self.tw = None + + def on_enter(self, event=None): + self.schedule() + + def on_leave(self, event=None): + self.unschedule() + self.hide() + + def schedule(self): + self.unschedule() + self.id = self.canvas.after(self.waittime, self.show) + + def unschedule(self): + id_ = self.id + self.id = None + if id_: + self.canvas.after_cancel(id_) + + def show(self, event=None): + def tip_pos_calculator(canvas, label, *, tip_delta=(10, 5), pad=(5, 3, 5, 3)): + + c = canvas + + s_width, s_height = c.winfo_screenwidth(), c.winfo_screenheight() + + width, height = ( + pad[0] + label.winfo_reqwidth() + pad[2], + pad[1] + label.winfo_reqheight() + pad[3], + ) + + mouse_x, mouse_y = c.winfo_pointerxy() + + x1, y1 = mouse_x + tip_delta[0], mouse_y + tip_delta[1] + x2, y2 = x1 + width, y1 + height + + x_delta = x2 - s_width + if x_delta < 0: + x_delta = 0 + y_delta = y2 - s_height + if y_delta < 0: + y_delta = 0 + + offscreen = (x_delta, y_delta) != (0, 0) + + if offscreen: + + if x_delta: + x1 = mouse_x - tip_delta[0] - width + + if y_delta: + y1 = mouse_y - tip_delta[1] - height + + offscreen_again = y1 < 0 # out on the top + + if offscreen_again: + y1 = 0 + + return x1, y1 + + bg = self.bg + pad = self.pad + canvas = self.canvas + + # creates a toplevel window + self.tw = tk.Toplevel(canvas.master) + + # Leaves only the label and removes the app window + self.tw.wm_overrideredirect(True) + + win = tk.Frame(self.tw, background=bg, borderwidth=0) + label = ttk.Label( + win, + text=self.text, + justify=tk.LEFT, + background=bg, + relief=tk.SOLID, + borderwidth=0, + wraplength=self.wraplength, + ) + + label.grid(padx=(pad[0], pad[2]), pady=(pad[1], pad[3]), sticky=tk.NSEW) + win.grid() + + x, y = tip_pos_calculator(canvas, label) + + self.tw.wm_geometry("+%d+%d" % (x, y)) + + def hide(self): + if self.tw: + self.tw.destroy() + self.tw = None diff --git a/coretk/coretk/graph.py b/coretk/coretk/graph.py index 19491180..80360c44 100644 --- a/coretk/coretk/graph.py +++ b/coretk/coretk/graph.py @@ -4,6 +4,7 @@ import tkinter as tk from core.api.grpc import core_pb2 from coretk.canvasaction import CanvasAction +from coretk.canvastooltip import CanvasTooltip from coretk.graph_helper import GraphHelper, WlanAntennaManager from coretk.images import Images from coretk.interface import Interface @@ -512,6 +513,7 @@ class CanvasNode: self.canvas.tag_bind(self.id, "", self.context) self.canvas.tag_bind(self.id, "", self.double_click) self.canvas.tag_bind(self.id, "", self.select_multiple) + self.tooltip = CanvasTooltip(self.canvas, self.id, text=self.name) self.edges = set() self.wlans = []