shape dialog
This commit is contained in:
parent
a0caff6ca2
commit
ff473b9748
4 changed files with 215 additions and 49 deletions
126
coretk/coretk/dialogs/shapemod.py
Normal file
126
coretk/coretk/dialogs/shapemod.py
Normal file
|
@ -0,0 +1,126 @@
|
|||
"""
|
||||
shape input dialog
|
||||
"""
|
||||
import tkinter as tk
|
||||
from tkinter import colorchooser, font, ttk
|
||||
|
||||
from coretk.dialogs.dialog import Dialog
|
||||
|
||||
FONT_SIZES = [8, 9, 10, 11, 12, 14, 16, 18, 20, 22, 24, 26, 28, 36, 48, 72]
|
||||
BORDER_WIDTH = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
|
||||
|
||||
|
||||
class ShapeDialog(Dialog):
|
||||
def __init__(self, master, app):
|
||||
super().__init__(master, app, "Add a new shape", modal=True)
|
||||
self.shape_text = tk.StringVar(value="")
|
||||
self.font = tk.StringVar(value="Arial")
|
||||
self.font_size = tk.IntVar(value=12)
|
||||
self.text_color = "#000000"
|
||||
self.fill_color = "#CFCFFF"
|
||||
self.border_color = "black"
|
||||
self.border_width = tk.IntVar(value=0)
|
||||
|
||||
self.fill = None
|
||||
self.border = None
|
||||
|
||||
self.top.columnconfigure(0, weight=1)
|
||||
self.draw()
|
||||
|
||||
def draw(self):
|
||||
frame = ttk.Frame(self.top)
|
||||
frame.columnconfigure(0, weight=1)
|
||||
frame.columnconfigure(1, weight=2)
|
||||
label = ttk.Label(frame, text="Text for top of shape: ")
|
||||
label.grid(row=0, column=0, sticky="nsew")
|
||||
entry = ttk.Entry(frame, textvariable=self.shape_text)
|
||||
entry.grid(row=0, column=1, sticky="nsew")
|
||||
frame.grid(row=0, column=0, sticky="nsew", padx=3, pady=3)
|
||||
|
||||
frame = ttk.Frame(self.top)
|
||||
frame.columnconfigure(0, weight=1)
|
||||
frame.columnconfigure(1, weight=1)
|
||||
frame.columnconfigure(2, weight=1)
|
||||
combobox = ttk.Combobox(
|
||||
frame,
|
||||
textvariable=self.font,
|
||||
values=sorted(font.families()),
|
||||
state="readonly",
|
||||
)
|
||||
combobox.grid(row=0, column=0, sticky="nsew")
|
||||
combobox = ttk.Combobox(
|
||||
frame, textvariable=self.font_size, values=FONT_SIZES, state="readonly"
|
||||
)
|
||||
combobox.grid(row=0, column=1, padx=3, sticky="nsew")
|
||||
button = ttk.Button(frame, text="Text color", command=self.choose_text_color)
|
||||
button.grid(row=0, column=2, sticky="nsew")
|
||||
frame.grid(row=1, column=0, sticky="nsew", padx=3, pady=3)
|
||||
|
||||
frame = ttk.Frame(self.top)
|
||||
button = ttk.Checkbutton(frame, text="Bold")
|
||||
button.grid(row=0, column=0)
|
||||
button = ttk.Checkbutton(frame, text="Italic")
|
||||
button.grid(row=0, column=1, padx=3)
|
||||
button = ttk.Checkbutton(frame, text="Underline")
|
||||
button.grid(row=0, column=2)
|
||||
frame.grid(row=2, column=0, sticky="nsew", padx=3, pady=3)
|
||||
|
||||
frame = ttk.Frame(self.top)
|
||||
frame.columnconfigure(0, weight=1)
|
||||
frame.columnconfigure(1, weight=1)
|
||||
frame.columnconfigure(2, weight=1)
|
||||
label = ttk.Label(frame, text="Fill color")
|
||||
label.grid(row=0, column=0, sticky="nsew")
|
||||
self.fill = ttk.Label(frame, text=self.fill_color, background="#CFCFFF")
|
||||
self.fill.grid(row=0, column=1, sticky="nsew", padx=3)
|
||||
button = ttk.Button(frame, text="Color", command=self.choose_fill_color)
|
||||
button.grid(row=0, column=2, sticky="nsew")
|
||||
frame.grid(row=3, column=0, sticky="nsew", padx=3, pady=3)
|
||||
|
||||
frame = ttk.Frame(self.top)
|
||||
frame.columnconfigure(0, weight=1)
|
||||
frame.columnconfigure(1, weight=1)
|
||||
frame.columnconfigure(2, weight=1)
|
||||
label = ttk.Label(frame, text="Border color:")
|
||||
label.grid(row=0, column=0, sticky="nsew")
|
||||
self.border = ttk.Label(
|
||||
frame, text=self.border_color, background=self.fill_color
|
||||
)
|
||||
self.border.grid(row=0, column=1, sticky="nsew", padx=3)
|
||||
button = ttk.Button(frame, text="Color", command=self.choose_border_color)
|
||||
button.grid(row=0, column=2, sticky="nsew")
|
||||
frame.grid(row=4, column=0, sticky="nsew", padx=3, pady=3)
|
||||
|
||||
frame = ttk.Frame(self.top)
|
||||
frame.columnconfigure(0, weight=1)
|
||||
frame.columnconfigure(1, weight=2)
|
||||
label = ttk.Label(frame, text="Border width:")
|
||||
label.grid(row=0, column=0, sticky="nsew")
|
||||
combobox = ttk.Combobox(
|
||||
frame, textvariable=self.border_width, values=BORDER_WIDTH, state="readonly"
|
||||
)
|
||||
combobox.grid(row=0, column=1, sticky="nsew")
|
||||
frame.grid(row=5, column=0, sticky="nsew", padx=3, pady=3)
|
||||
|
||||
frame = ttk.Frame(self.top)
|
||||
frame.columnconfigure(0, weight=1)
|
||||
frame.columnconfigure(1, weight=1)
|
||||
button = ttk.Button(frame, text="Add shape")
|
||||
button.grid(row=0, column=0, sticky="e", padx=3)
|
||||
button = ttk.Button(frame, text="Cancel", command=self.destroy)
|
||||
button.grid(row=0, column=1, sticky="w", pady=3)
|
||||
frame.grid(row=6, column=0, sticky="nsew", padx=3, pady=3)
|
||||
|
||||
def choose_text_color(self):
|
||||
color = colorchooser.askcolor(color="black")
|
||||
self.text_color = color[1]
|
||||
|
||||
def choose_fill_color(self):
|
||||
color = colorchooser.askcolor(color=self.fill_color)
|
||||
self.fill_color = color[1]
|
||||
self.fill.config(background=color[1], text=color[1])
|
||||
|
||||
def choose_border_color(self):
|
||||
color = colorchooser.askcolor(color="black")
|
||||
self.border_color = color[1]
|
||||
self.border.config(background=color[1], text=color[1])
|
|
@ -68,6 +68,7 @@ class CanvasGraph(tk.Canvas):
|
|||
self.core = core
|
||||
self.helper = GraphHelper(self, core)
|
||||
self.throughput_draw = Throughput(self, core)
|
||||
self.shape_drawing = False
|
||||
|
||||
# background related
|
||||
self.wallpaper_id = None
|
||||
|
@ -144,6 +145,7 @@ class CanvasGraph(tk.Canvas):
|
|||
self.bind("<B1-Motion>", self.click_motion)
|
||||
self.bind("<Button-3>", self.click_context)
|
||||
self.bind("<Delete>", self.press_delete)
|
||||
self.bind("<Control-1>", self.ctrl_click)
|
||||
|
||||
def draw_grid(self, width=1000, height=800):
|
||||
"""
|
||||
|
@ -275,6 +277,9 @@ class CanvasGraph(tk.Canvas):
|
|||
selected = _id
|
||||
break
|
||||
|
||||
if _id in self.shapes:
|
||||
selected = _id
|
||||
|
||||
return selected
|
||||
|
||||
def click_release(self, event):
|
||||
|
@ -290,8 +295,10 @@ class CanvasGraph(tk.Canvas):
|
|||
else:
|
||||
if self.mode == GraphMode.ANNOTATION:
|
||||
if self.annotation_type in [ImageEnum.OVAL, ImageEnum.RECTANGLE]:
|
||||
self.focus_set()
|
||||
x, y = self.canvas_xy(event)
|
||||
self.shapes[self.selected].shape_complete(x, y)
|
||||
self.shape_drawing = False
|
||||
else:
|
||||
self.focus_set()
|
||||
self.selected = self.get_selected(event)
|
||||
|
@ -355,12 +362,28 @@ class CanvasGraph(tk.Canvas):
|
|||
if self.mode == GraphMode.EDGE and is_node:
|
||||
x, y = self.coords(selected)
|
||||
self.drawing_edge = CanvasEdge(x, y, x, y, selected, self)
|
||||
if self.mode == GraphMode.ANNOTATION:
|
||||
if self.annotation_type in [ImageEnum.OVAL, ImageEnum.RECTANGLE]:
|
||||
x, y = self.canvas_xy(event)
|
||||
shape = Shape(self.app, self, x, y)
|
||||
self.selected = shape.id
|
||||
self.shapes[shape.id] = shape
|
||||
if (
|
||||
self.mode == GraphMode.ANNOTATION
|
||||
and self.annotation_type in [ImageEnum.OVAL, ImageEnum.RECTANGLE]
|
||||
and selected is None
|
||||
):
|
||||
x, y = self.canvas_xy(event)
|
||||
shape = Shape(self.app, self, x, y)
|
||||
self.selected = shape.id
|
||||
self.shapes[shape.id] = shape
|
||||
self.shape_drawing = True
|
||||
if self.mode == GraphMode.SELECT and "shape" in self.gettags(selected):
|
||||
x, y = self.canvas_xy(event)
|
||||
self.shapes[selected].cursor_x = x
|
||||
self.shapes[selected].cursor_y = y
|
||||
self.canvas_management.node_select(self.shapes[selected])
|
||||
self.selected = selected
|
||||
|
||||
def ctrl_click(self, event):
|
||||
logging.debug("Control left click %s", event)
|
||||
selected = self.get_selected(event)
|
||||
if self.mode == GraphMode.SELECT and "shape" in self.gettags(selected):
|
||||
self.canvas_management.node_select(self.shapes[selected], True)
|
||||
|
||||
def click_motion(self, event):
|
||||
"""
|
||||
|
@ -374,9 +397,14 @@ class CanvasGraph(tk.Canvas):
|
|||
x1, y1, _, _ = self.coords(self.drawing_edge.id)
|
||||
self.coords(self.drawing_edge.id, x1, y1, x2, y2)
|
||||
if self.mode == GraphMode.ANNOTATION:
|
||||
if self.annotation_type in [ImageEnum.OVAL, ImageEnum.RECTANGLE]:
|
||||
if (
|
||||
self.annotation_type in [ImageEnum.OVAL, ImageEnum.RECTANGLE]
|
||||
and self.shape_drawing
|
||||
):
|
||||
x, y = self.canvas_xy(event)
|
||||
self.shapes[self.selected].shape_motion(x, y)
|
||||
if self.mode == GraphMode.SELECT and "shape" in self.gettags(self.selected):
|
||||
self.shapes[self.selected].motion(event)
|
||||
|
||||
def click_context(self, event):
|
||||
logging.info("context event: %s", self.context)
|
||||
|
@ -399,11 +427,12 @@ class CanvasGraph(tk.Canvas):
|
|||
:param event:
|
||||
:return:
|
||||
"""
|
||||
logging.debug("press delete key")
|
||||
nodes = self.canvas_management.delete_selected_nodes()
|
||||
self.core.delete_graph_nodes(nodes)
|
||||
|
||||
def add_node(self, x, y):
|
||||
if self.selected is None:
|
||||
if self.selected is None or "shape" in self.gettags(self.selected):
|
||||
core_node = self.core.create_node(
|
||||
int(x), int(y), self.node_draw.node_type, self.node_draw.model
|
||||
)
|
||||
|
@ -536,6 +565,9 @@ class CanvasGraph(tk.Canvas):
|
|||
else:
|
||||
self.itemconfig("gridline", state=tk.HIDDEN)
|
||||
|
||||
def is_selection_mode(self):
|
||||
return self.mode == GraphMode.SELECT
|
||||
|
||||
|
||||
class CanvasWirelessEdge:
|
||||
def __init__(self, token, position, src, dst, canvas):
|
||||
|
@ -701,6 +733,7 @@ class CanvasNode:
|
|||
logging.debug(f"node click press {self.core_node.name}: {event}")
|
||||
self.moving = self.canvas.canvas_xy(event)
|
||||
self.canvas.canvas_management.node_select(self)
|
||||
self.canvas.selected = self.id
|
||||
|
||||
def click_release(self, event):
|
||||
logging.debug(f"node click release {self.core_node.name}: {event}")
|
||||
|
|
|
@ -47,41 +47,49 @@ class CanvasComponentManagement:
|
|||
def delete_selected_nodes(self):
|
||||
edges = set()
|
||||
nodes = []
|
||||
for node_id in self.selected:
|
||||
if "node" in self.canvas.gettags(node_id):
|
||||
bbox_id = self.selected[node_id]
|
||||
canvas_node = self.canvas.nodes.pop(node_id)
|
||||
nodes.append(canvas_node)
|
||||
self.canvas.delete(node_id)
|
||||
self.canvas.delete(bbox_id)
|
||||
self.canvas.delete(canvas_node.text_id)
|
||||
|
||||
for node_id in list(self.selected):
|
||||
bbox_id = self.selected[node_id]
|
||||
canvas_node = self.canvas.nodes.pop(node_id)
|
||||
nodes.append(canvas_node)
|
||||
self.canvas.delete(node_id)
|
||||
self.canvas.delete(bbox_id)
|
||||
self.canvas.delete(canvas_node.text_id)
|
||||
|
||||
# delete antennas
|
||||
is_wireless = NodeUtils.is_wireless_node(canvas_node.core_node.type)
|
||||
if is_wireless:
|
||||
canvas_node.antenna_draw.delete_antennas()
|
||||
|
||||
# delete related edges
|
||||
for edge in canvas_node.edges:
|
||||
if edge in edges:
|
||||
continue
|
||||
edges.add(edge)
|
||||
self.canvas.edges.pop(edge.token)
|
||||
self.canvas.delete(edge.id)
|
||||
self.canvas.delete(edge.link_info.id1)
|
||||
self.canvas.delete(edge.link_info.id2)
|
||||
other_id = edge.src
|
||||
other_interface = edge.src_interface
|
||||
if edge.src == node_id:
|
||||
other_id = edge.dst
|
||||
other_interface = edge.dst_interface
|
||||
other_node = self.canvas.nodes[other_id]
|
||||
other_node.edges.remove(edge)
|
||||
try:
|
||||
other_node.interfaces.remove(other_interface)
|
||||
except ValueError:
|
||||
pass
|
||||
# delete antennas
|
||||
is_wireless = NodeUtils.is_wireless_node(canvas_node.core_node.type)
|
||||
if is_wireless:
|
||||
other_node.antenna_draw.delete_antenna()
|
||||
canvas_node.antenna_draw.delete_antennas()
|
||||
|
||||
# delete related edges
|
||||
for edge in canvas_node.edges:
|
||||
if edge in edges:
|
||||
continue
|
||||
edges.add(edge)
|
||||
self.canvas.edges.pop(edge.token)
|
||||
self.canvas.delete(edge.id)
|
||||
self.canvas.delete(edge.link_info.id1)
|
||||
self.canvas.delete(edge.link_info.id2)
|
||||
other_id = edge.src
|
||||
other_interface = edge.src_interface
|
||||
if edge.src == node_id:
|
||||
other_id = edge.dst
|
||||
other_interface = edge.dst_interface
|
||||
other_node = self.canvas.nodes[other_id]
|
||||
other_node.edges.remove(edge)
|
||||
try:
|
||||
other_node.interfaces.remove(other_interface)
|
||||
except ValueError:
|
||||
pass
|
||||
if is_wireless:
|
||||
other_node.antenna_draw.delete_antenna()
|
||||
|
||||
for shape_id in self.selected:
|
||||
if "shape" in self.canvas.gettags(shape_id):
|
||||
bbox_id = self.selected[node_id]
|
||||
self.canvas.delete(shape_id)
|
||||
self.canvas.delete(bbox_id)
|
||||
self.canvas.shapes.pop(shape_id)
|
||||
|
||||
self.selected.clear()
|
||||
return nodes
|
||||
|
|
|
@ -3,6 +3,7 @@ class for shapes
|
|||
"""
|
||||
import logging
|
||||
|
||||
from coretk.dialogs.shapemod import ShapeDialog
|
||||
from coretk.images import ImageEnum
|
||||
|
||||
ABOVE_COMPONENT = ["gridline", "edge", "linkinfo", "antenna", "node", "nodename"]
|
||||
|
@ -16,6 +17,7 @@ class Shape:
|
|||
self.y0 = top_y
|
||||
self.cursor_x = None
|
||||
self.cursor_y = None
|
||||
canvas.delete(canvas.find_withtag("selectednodes"))
|
||||
annotation_type = self.canvas.annotation_type
|
||||
if annotation_type == ImageEnum.OVAL:
|
||||
self.id = canvas.create_oval(
|
||||
|
@ -25,9 +27,8 @@ class Shape:
|
|||
self.id = canvas.create_rectangle(
|
||||
top_x, top_y, top_x, top_y, tags="shape", dash="-"
|
||||
)
|
||||
self.canvas.tag_bind(self.id, "<ButtonPress-1>", self.click_press)
|
||||
self.canvas.tag_bind(self.id, "<ButtonRelease-1>", self.click_release)
|
||||
self.canvas.tag_bind(self.id, "<B1-Motion>", self.motion)
|
||||
# self.canvas.tag_bind(self.id, "<B1-Motion>", self.motion)
|
||||
|
||||
def shape_motion(self, x1, y1):
|
||||
self.canvas.coords(self.id, self.x0, self.y0, x1, y1)
|
||||
|
@ -36,11 +37,8 @@ class Shape:
|
|||
self.canvas.itemconfig(self.id, width=0, fill="#ccccff")
|
||||
for component in ABOVE_COMPONENT:
|
||||
self.canvas.tag_raise(component)
|
||||
|
||||
def click_press(self, event):
|
||||
logging.debug("Click on shape %s", self.id)
|
||||
self.cursor_x = event.x
|
||||
self.cursor_y = event.y
|
||||
s = ShapeDialog(self.app, self.app)
|
||||
s.show()
|
||||
|
||||
def click_release(self, event):
|
||||
logging.debug("Click release on shape %s", self.id)
|
||||
|
@ -53,5 +51,6 @@ class Shape:
|
|||
self.canvas.coords(
|
||||
self.id, x0 + delta_x, y0 + delta_y, x1 + delta_x, y1 + delta_y
|
||||
)
|
||||
self.canvas.canvas_management.node_drag(self, delta_x, delta_y)
|
||||
self.cursor_x = event.x
|
||||
self.cursor_y = event.y
|
||||
|
|
Loading…
Add table
Reference in a new issue