finish writing a Find tool that allows find a node based on node name
This commit is contained in:
parent
b5f4571618
commit
275e8f4c30
2 changed files with 151 additions and 0 deletions
144
daemon/core/gui/dialogs/find.py
Normal file
144
daemon/core/gui/dialogs/find.py
Normal file
|
@ -0,0 +1,144 @@
|
|||
import logging
|
||||
import tkinter as tk
|
||||
from tkinter import ttk
|
||||
|
||||
from core.gui.dialogs.dialog import Dialog
|
||||
from core.gui.themes import FRAME_PAD, PADX, PADY
|
||||
|
||||
|
||||
class FindDialog(Dialog):
|
||||
def __init__(self, master, app):
|
||||
super().__init__(master, app, "Find", modal=True)
|
||||
|
||||
self.find_text = tk.StringVar(value="")
|
||||
self.tree = None
|
||||
self.draw()
|
||||
self.protocol("WM_DELETE_WINDOW", self.close_dialog)
|
||||
self.bind("<Return>", self.find_node)
|
||||
|
||||
def draw(self):
|
||||
self.top.columnconfigure(0, weight=1)
|
||||
self.top.rowconfigure(0, weight=1)
|
||||
self.top.rowconfigure(1, weight=5)
|
||||
self.top.rowconfigure(2, weight=1)
|
||||
|
||||
# Find node frame
|
||||
frame = ttk.Frame(self.top, padding=FRAME_PAD)
|
||||
frame.grid(sticky="nsew")
|
||||
frame.columnconfigure(1, weight=1)
|
||||
label = ttk.Label(frame, text="Find:")
|
||||
label.grid()
|
||||
entry = ttk.Entry(frame, textvariable=self.find_text)
|
||||
entry.grid(row=0, column=1, sticky="nsew")
|
||||
|
||||
# node list frame
|
||||
frame = ttk.Frame(self.top)
|
||||
frame.columnconfigure(0, weight=1)
|
||||
frame.rowconfigure(0, weight=1)
|
||||
frame.grid(sticky="nsew", padx=PADX, pady=PADY)
|
||||
self.tree = ttk.Treeview(
|
||||
frame,
|
||||
columns=("nodeid", "name", "location", "detail"),
|
||||
show="headings",
|
||||
selectmode=tk.BROWSE,
|
||||
)
|
||||
self.tree.grid(sticky="nsew")
|
||||
style = ttk.Style()
|
||||
heading_size = int(self.app.guiconfig["scale"] * 10)
|
||||
style.configure("Treeview.Heading", font=(None, heading_size, "bold"))
|
||||
self.tree.column("nodeid", stretch=tk.YES, anchor="center")
|
||||
self.tree.heading("nodeid", text="Node ID")
|
||||
self.tree.column("name", stretch=tk.YES, anchor="center")
|
||||
self.tree.heading("name", text="Name")
|
||||
self.tree.column("location", stretch=tk.YES, anchor="center")
|
||||
self.tree.heading("location", text="Location")
|
||||
self.tree.column("detail", stretch=tk.YES, anchor="center")
|
||||
self.tree.heading("detail", text="Detail")
|
||||
|
||||
self.tree.bind("<<TreeviewSelect>>", self.click_select)
|
||||
|
||||
yscrollbar = ttk.Scrollbar(frame, orient="vertical", command=self.tree.yview)
|
||||
yscrollbar.grid(row=0, column=1, sticky="ns")
|
||||
self.tree.configure(yscrollcommand=yscrollbar.set)
|
||||
|
||||
xscrollbar = ttk.Scrollbar(frame, orient="horizontal", command=self.tree.xview)
|
||||
xscrollbar.grid(row=1, sticky="ew")
|
||||
self.tree.configure(xscrollcommand=xscrollbar.set)
|
||||
|
||||
# button frame
|
||||
frame = ttk.Frame(self.top)
|
||||
frame.grid(sticky="nsew")
|
||||
frame.columnconfigure(0, weight=1)
|
||||
frame.columnconfigure(1, weight=1)
|
||||
button = ttk.Button(frame, text="Find", command=self.find_node)
|
||||
button.grid(row=0, column=0, sticky="ew", padx=PADX)
|
||||
button = ttk.Button(frame, text="Cancel", command=self.close_dialog)
|
||||
button.grid(row=0, column=1, sticky="ew", padx=PADX)
|
||||
|
||||
def clear_treeview_items(self):
|
||||
"""
|
||||
clear all items in the treeview
|
||||
:return:
|
||||
"""
|
||||
for i in list(self.tree.get_children("")):
|
||||
self.tree.delete(i)
|
||||
|
||||
def find_node(self, event=None):
|
||||
"""
|
||||
Query nodes that have the same node name as our search key,
|
||||
display results to tree view
|
||||
"""
|
||||
node_name = self.find_text.get().strip()
|
||||
self.clear_treeview_items()
|
||||
for node_id, node in sorted(
|
||||
self.app.core.canvas_nodes.items(), key=lambda x: x[0]
|
||||
):
|
||||
name = node.core_node.name
|
||||
if not node_name or node_name == name:
|
||||
location = f"<{node.core_node.position.x}, {node.core_node.position.y}>"
|
||||
# TODO I am not sure what to insert for Detail column, leaving in blank for now
|
||||
self.tree.insert(
|
||||
"", tk.END, text=str(node_id), values=(node_id, name, location, "")
|
||||
)
|
||||
|
||||
results = self.tree.get_children("")
|
||||
if results:
|
||||
self.tree.selection_set(results[0])
|
||||
|
||||
def close_dialog(self):
|
||||
self.app.canvas.delete("find")
|
||||
self.destroy()
|
||||
|
||||
def click_select(self, _event: tk.Event = None) -> None:
|
||||
item = self.tree.selection()
|
||||
if item:
|
||||
self.app.canvas.delete("find")
|
||||
node_id = int(self.tree.item(item, "text"))
|
||||
canvas_node = self.app.core.canvas_nodes[node_id]
|
||||
|
||||
x0, y0, x1, y1 = self.app.canvas.bbox(canvas_node.id)
|
||||
dist = 5 * self.app.guiconfig["scale"]
|
||||
self.app.canvas.create_oval(
|
||||
x0 - dist,
|
||||
y0 - dist,
|
||||
x1 + dist,
|
||||
y1 + dist,
|
||||
tags="find",
|
||||
outline="red",
|
||||
width=3.0 * self.app.guiconfig["scale"],
|
||||
)
|
||||
|
||||
_x, _y, _, _ = self.app.canvas.bbox(canvas_node.id)
|
||||
oid = self.app.canvas.find_withtag("rectangle")
|
||||
x0, y0, x1, y1 = self.app.canvas.bbox(oid[0])
|
||||
logging.debug("Dist to most left: %s", abs(x0 - _x))
|
||||
logging.debug("White canvas width: %s", abs(x0 - x1))
|
||||
|
||||
# calculate the node's location
|
||||
# (as fractions of white canvas's width and height)
|
||||
# and instantly scroll the x and y scrollbar to that location
|
||||
|
||||
xscroll_fraction = abs(x0 - _x) / abs(x0 - x1)
|
||||
yscroll_fraction = abs(y0 - _y) / abs(y0 - y1)
|
||||
self.app.canvas.xview_moveto(xscroll_fraction)
|
||||
self.app.canvas.yview_moveto(yscroll_fraction)
|
|
@ -11,6 +11,7 @@ from core.gui.dialogs.about import AboutDialog
|
|||
from core.gui.dialogs.canvassizeandscale import SizeAndScaleDialog
|
||||
from core.gui.dialogs.canvaswallpaper import CanvasWallpaperDialog
|
||||
from core.gui.dialogs.executepython import ExecutePythonDialog
|
||||
from core.gui.dialogs.find import FindDialog
|
||||
from core.gui.dialogs.hooks import HooksDialog
|
||||
from core.gui.dialogs.ipdialog import IpConfigDialog
|
||||
from core.gui.dialogs.macdialog import MacConfigDialog
|
||||
|
@ -114,6 +115,7 @@ class Menubar(tk.Menu):
|
|||
Create edit menu
|
||||
"""
|
||||
menu = tk.Menu(self)
|
||||
menu.add_command(label="Find", accelerator="Ctrl+F", command=self.click_find)
|
||||
menu.add_command(label="Preferences", command=self.click_preferences)
|
||||
menu.add_command(label="Undo", accelerator="Ctrl+Z", state=tk.DISABLED)
|
||||
menu.add_command(label="Redo", accelerator="Ctrl+Y", state=tk.DISABLED)
|
||||
|
@ -125,6 +127,7 @@ class Menubar(tk.Menu):
|
|||
label="Delete", accelerator="Ctrl+D", command=self.click_delete
|
||||
)
|
||||
self.add_cascade(label="Edit", menu=menu)
|
||||
self.app.master.bind_all("<Control-f>", self.click_find)
|
||||
self.app.master.bind_all("<Control-x>", self.click_cut)
|
||||
self.app.master.bind_all("<Control-c>", self.click_copy)
|
||||
self.app.master.bind_all("<Control-v>", self.click_paste)
|
||||
|
@ -397,6 +400,10 @@ class Menubar(tk.Menu):
|
|||
self.core.create_new_session()
|
||||
self.core.xml_file = None
|
||||
|
||||
def click_find(self, _event: tk.Event = None) -> None:
|
||||
dialog = FindDialog(self.app, self.app)
|
||||
dialog.show()
|
||||
|
||||
def click_preferences(self) -> None:
|
||||
dialog = PreferencesDialog(self.app, self.app)
|
||||
dialog.show()
|
||||
|
|
Loading…
Reference in a new issue