shape dialog

This commit is contained in:
Huy Pham 2019-12-02 16:05:10 -08:00
parent a0caff6ca2
commit ff473b9748
4 changed files with 215 additions and 49 deletions

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

View file

@ -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}")

View file

@ -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

View file

@ -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